Bir PDF sayfasında TrimBox yoksa etkin TrimBox, sayfanın CropBox'ıdır; CropBox da yoksa MediaBox'tır. BleedBox ile ArtBox aynı kuralı izler. Delphi için PDF kütüphanesi olan PDFlibPas bu varsayılan zincirini v3.539.44'ten beri GetPageBox, HasPageBox ve CapturePageEx'de tutarlı uygular ve bir /Pages düğümüne konan production kutularını yok sayar, çünkü ISO 32000-1 onların kalıtılmasına izin vermez
Bu bir dipnot gibi okunur, ta ki bir iş (job) dayayana dek. 6.25 × 9.25 inçlik bir MediaBox'ı, trim olan 6 × 9 inçlik bir CropBox'ı ve hiç TrimBox'ı olmayan — onu yazmayı ihracatçının aklına gelmemiş — bir kitap içi düşünün. Trim kutusunu isteyin, media kutusunu alın; ve baskı tabakanızdaki her hücre komşusuna bir sekizinci inçlik bleed ile slug sürükler. PDFlibPas'ın tam da bu alandaki kusurları v3.539.42 ile v3.539.44'te düzeltildi ve düzeltme biçimleri, page-box semantiğinin herhangi bir PDF kütüphanesinde nasıl uygulanması gerektiği hakkında bir şey söylüyor
Bir sayfada TrimBox yokken hangi kutu geçerlidir?
Yanıt, ISO 32000-1 §14.11.2'den gelen sabit bir varsayılan zinciridir: CropBox MediaBox'a, BleedBox, TrimBox ve ArtBox ise her biri CropBox'a varsayılanlaşır. MediaBox'a doğrudan varsayılanlaşan tek kutu CropBox'tır. Yalnızca MediaBox tanımlayan bir sayfanın bu yüzden beş özdeş kutusu, MediaBox artı CropBox tanımlayan bir sayfanın ise dört kutusu CropBox'a eşittir
| Kutu | PDFlibPas BoxType | Yokken varsayılan | /Pages'ten kalıtılır mı |
|---|---|---|---|
| MediaBox | 1 | Yok, girdi zorunludur | Evet |
| CropBox | 2 | MediaBox | Evet |
| BleedBox | 3 | CropBox | Hayır |
| TrimBox | 4 | CropBox | Hayır |
| ArtBox | 5 | CropBox | Hayır |
İki adımlı zincir önemlidir, çünkü CropBox'ın kendisi de kalıtılabilir olabilir. Ne kendi TrimBox'ı ne de kendi CropBox'ı olan bir sayfanın etkin TrimBox'ı, CropBox'ı olan en yakın atanın CropBox'ıdır; o da yoksa kalıtılan MediaBox'tır. Belirtimin unutması kolay bir kuralı daha vardır: crop, bleed, trim ve art kutuları media kutusunun ötesine uzanmamalıdır; uzanırlarsa fiilen onunla kesişimlerine indirgenirler. PDFlibPas her kutuyu dosyada saklandığı hâliyle bildirir; dolayısıyla güvenilmeyen girdiyi işleyen bir validator, MediaBox'a göre kendi kendini kısmalıdır
Bir /Pages düğümü hangi sayfa attribute'larını aktarabilir?
Tam olarak dördünü: Resources, MediaBox, CropBox ve Rotate. ISO 32000-1 §7.7.3.4 attribute kalıtımını tanımlar ve Table 30 yalnızca o dört page-object girdisini kalıtılabilir işaretler. BleedBox, TrimBox ve ArtBox yaprak sayfaya aittir. Bir /Pages düğümüne yazılmış TrimBox kalıtılan bir değer değildir; standartlara uygun bir okuyucunun yok saydığı standart dışı bir anahtardır
Böyle standart dışı dosyalar vardır; genelde "her sayfada bu trim var" kısayolu olarak kök page tree düğümünde tek bir TrimBox ile. Kısayol, her anahtar için /Parent'ı gezen her araçta doğru görünür ve sorun da budur: dosya artık kimin okuduğuna göre iki anlam taşır. Belirtimi izleyen bir okuyucu TrimBox görmez ve CropBox'ı kullanır; her şeyi kalıtan bir okuyucu ise ebeveyn değerini görür. Prepress hattında o belirsizlik baskı tabakasına kadar iner
PDF/X (ISO 15930) iş akışları bitmiş boyut için TrimBox'a dayanır ve PDF/X profilleri her sayfanın bir TrimBox ya da ArtBox bildirmesini ister. Bir /Pages düğümüne park edilmiş kutu o gereksinimi karşılamaz, çünkü anahtar sayfa object'ine hiç ulaşmaz. Preflight böyle dosyaları bir türlü sessizce okumak yerine işaretlemelidir
PDFlibPas v3.539.44'ten önce neyi yanlış yapıyordu?
PDFlibPas'ın üç ayrı kusuru vardı; hepsi belirtimin söylediği ile iki bağımsız kod yolunun yaptığı arasındaki boşluktaydı. İlki v3.539.42'de, öteki ikisi v3.539.44'te düzeltildi
Production kutuları capture sırasında MediaBox'a varsayılanlaşıyordu
v3.539.42 öncesinde bir sayfayı capture'a hazırlayan dâhilî yordam (kalıtılan girdileri sayfanın üzerine kopyalar ve eksik kutuları doldurur), BleedBox, TrimBox ve ArtBox yokken onlara MediaBox değerlerini veriyordu. 2 ile 4 optionlarıyla CapturePageEx, sınırlayıcı dikdörtgenini tam olarak o doldurulmuş girdilerden okur; dolayısıyla yalnızca CropBox tanımlayan bir sayfada trim kutusu istemek bütün media kutusunu capture ediyordu. GetPageBox CropBox varsayılanını çoktan uyguluyordu ve CapturePageEx referansı da hep, istenen kutu eksikken crop kutusunun kullanıldığını söylüyordu; capture kodu ikisine de ters düşüyordu. v3.539.42'den beri üç production kutusu sayfanın CropBox'ına varsayılanlaşır — o ana kadar CropBox sayfanın üzerindedir (kendi, bir atadan kopyalanmış ya da MediaBox'tan doldurulmuş) — ve yalnızca CropBox'ın kendisi MediaBox'a döner
İki kalıtım yolu, bir semantik kural
İkinci kusur standart dışı kalıtımın kendisiydi ve ince kısım, PDFlibPas'ın kutuları iki bağımsız yol boyunca çözmesiydi. Kutu sorguları (GetPageBox ile HasPageBox) /Parent zincirini bir yardımcı üzerinden geziyordu, capture ise ayrı bir yerel yardımcı üzerinden. İkisi de her anahtarı kalıtıyordu, production kutuları dahil. Yalnızca birini düzeltmek tek belgenin içinde çelişki üretirdi: /Pages düğümünde 180 point genişliğinde bir TrimBox ve sayfada 380 point genişliğinde bir CropBox varken GetPageBox hâlâ 180lik trim genişliği bildirirken CapturePageEx 380lik form kuruyordu. v3.539.44'te her iki yol da /Parent gezinimini dört kalıtılabilir anahtarla sınırlandırır, production kutuları yalnızca yapraktan okunur ve başıboş ebeveyn girdisi ne silinir ne yeniden yazılır; dosyada dokunulmadan kalır
HasPageBox direkt ebeveyn dizilerini kaçırıyordu
HasPageBox, sayfada istenen tipte kutu yokken 0, sayfanın kendi kutusu varken (doğrudan ya da bir indirect referans üzerinden saklanmış) 1 ve bir MediaBox ya da CropBox bir atadan kalıtılmışken 2 döndürür. Eski kod 2'yi yalnızca kalıtılan değer indirect bir referansken döndürüyordu; dolayısıyla kalıtılan direkt bir dizi 0 veriyordu. Düzeltme, referans çözümünü dizi sınamasından ayırır ve her iki gösterim de artık 2 döndürür. v3.539.44'ten beri BleedBox, TrimBox ya da ArtBox için HasPageBox yalnızca 0 ya da 1 döndürebilir
Ders, page box'ların çok ötesine geneller. Bir belirtim semantiğinin bir kütüphanede iki uygulama giriş noktası olduğunda onları birlikte düzeltin ve tek bir mutlu-yol dosyasıyla değil bir matris olarak sının. PDFlibPas regresyon seti, iki ebeveyn-kutu gösterimini (direkt ve indirect dizi) üç yaprak durumu (yok, direkt dizi, indirect dizi) ile üç capture optionıyla (bleed, trim, art) çaprazlar; 18 senaryo çıkar ve her biri sorgu sonucunu, capture edilen sınırları, meşru MediaBox ve CropBox kalıtımını ve dokunulmamış ebeveyn girdisini denetler
Delphi'de etkin TrimBox'ı nasıl okurum?
Seçili sayfada GetPageBox(4, Dimension) çağırın. PDFlibPas varsayılan zincirini sizin için uygular; dolayısıyla sonuç, sayfada olsun ya da olmasın etkin TrimBox'tır. Değerin nereden geldiğini bilmeniz gerektiğinde — bir preflight raporu genelde ister — yanına HasPageBox koyun
uses
System.SysUtils, PDFlibrary;
const
BOX_CROP = 2;
BOX_TRIM = 4;
DIM_LEFT = 0;
DIM_WIDTH = 2;
DIM_HEIGHT = 3;
DIM_BOTTOM = 5;
function DescribeTrim(Lib: TPDFlib; Page: Integer): string;
var
Source: string;
begin
Lib.SelectPage(Page);
if Lib.HasPageBox(BOX_TRIM) = 1 then
Source := 'own TrimBox'
else if Lib.HasPageBox(BOX_CROP) <> 0 then // 1 = kendi, 2 = kalıtsal
Source := 'defaulted to the CropBox'
else
Source := 'defaulted to the MediaBox';
Result := Format('page %d: trim %.2f x %.2f pt at (%.2f, %.2f), %s',
[Page,
Lib.GetPageBox(BOX_TRIM, DIM_WIDTH),
Lib.GetPageBox(BOX_TRIM, DIM_HEIGHT),
Lib.GetPageBox(BOX_TRIM, DIM_LEFT),
Lib.GetPageBox(BOX_TRIM, DIM_BOTTOM),
Source]);
end;
var
Lib: TPDFlib;
Page: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('interior.pdf', '') = 1 then
for Page := 1 to Lib.PageCount do
Writeln(DescribeTrim(Lib, Page));
finally
Lib.Free;
end;
end.
GetPageBox ile SetPageBox belgenin geçerli koordinat ayarlarında çalışır. Buradaki örnekler varsayılanlarla koşar: köken 0 (PDF user space ile aynı olan sol-alt) ve ölçü birimi point; dolayısıyla Top boyutu, sayfanın altından yukarı ölçülen üst kenardır. SetOrigin(1) sonrasında Top ile Bottom boyutları sayfanın üstünden aşağıya ölçülür ve SetMeasurementUnits(1) sonrasında her değer milimetre olarak döner. Genişlik ile yükseklik kökene bağlı değildir
/Pages düğümlerinde mahsur kalmış production kutularını bulmak
v3.539.44'ten beri kutu API'si bir /Pages düğümündeki TrimBox'ı görmüyor; bu doğrudur. Ama bir preflight aracı çoğu zaman böyle bir dosyayı sessizce belirtim yöntemiyle okumak yerine raporlamak ister. Page tree düğümleri sıradan object'lerdir; dolayısıyla düşük düzeyli object API'si onları bulabilir: GetMaxObjectNumber'a kadar object numaralarını gezin, her birini GetObjectToString ile okuyun ve production kutu anahtarı taşıyan bir /Pages sözlüğü arayın. Denetimin ikinci yarısı, PDF/X'in önemsediği sayfa-başı testtir ve HasPageBox artık onu bir PDF/X validator'ının yapacağı gibi yanıtlar; çünkü ebeveyn TrimBox artık sayılmıyor
procedure PreflightTrim(Lib: TPDFlib; Log: TStrings);
const
ProductionKeys: array[0..2] of string = ('/BleedBox', '/TrimBox', '/ArtBox');
var
ObjNum, K, Page, Missing: Integer;
Src: string;
begin
// 1. Page tree düğümlerindeki production kutular: standart dışı ve yok sayılır
for ObjNum := 1 to Lib.GetMaxObjectNumber do
begin
Src := ''; // boş numaralar metin döndürmez
Src := string(Lib.GetObjectToString(ObjNum));
if Pos('/Type /Pages', Src) = 0 then
Continue;
for K := Low(ProductionKeys) to High(ProductionKeys) do
if Pos(ProductionKeys[K] + ' ', Src) > 0 then
Log.Add(Format('object %d: %s on a /Pages node is not inheritable',
[ObjNum, ProductionKeys[K]]));
end;
// 2. PDF/X: her sayfanın kendi TrimBox'ı ya da ArtBox'ı olmalı
Missing := 0;
for Page := 1 to Lib.PageCount do
begin
Lib.SelectPage(Page);
if (Lib.HasPageBox(4) = 0) and (Lib.HasPageBox(5) = 0) then
begin
Inc(Missing);
Log.Add(Format('page %d: no TrimBox or ArtBox', [Page]));
end;
end;
// 3. İsteğe bağlı onarım: 6.25 x 9.25 inçlik media kutusu içinde 6 x 9 inçlik trim
// (point, sol-alt köken: Left, Top, Width, Height)
if Missing > 0 then
Log.Add(Format('TrimBox written on %d pages',
[Lib.SetPageBoxRange('', 4, 9, 657, 432, 648)]));
end;
Metin eşleşmesi pragmatik bir denetimdir, ayrıştırıcı değil. PDFlibPas'ın her sözlük girdisini bir anahtar, bir boşluk ve bir değer olarak serileştirdiğine dayanır; GetObjectToString üzerinden geri okunan object'ler için bu geçerlidir. Onarım adımı refleks değil karar ister: başıboş ebeveyn değeri, yazarın kastettiği şeyin kendisi olabilir; ama onu resmîleştirmeden önce iş fişiyle doğrulayın. Boş aralıkla SetPageBoxRange, kutuyu her sayfaya uygular ve güncellenen sayfa sayısını döndürür. Bir sayfanın mevcut kutusu — başka bir sayfanın ya da bir /Pages düğümünün paylaşabileceği — indirect bir dizi olduğunda SetPageBox, paylaşılan objecti yeniden yazmak yerine o sayfaya yeni bir direkt dizi verir. BleedBox, TrimBox ya da ArtBox set etmek ayrıca kilidi açık bir belgeyi, o girdileri getiren sürüm olan PDF 1.3'e yükseltir
CapturePageEx ile sayfaları TrimBox'a dayamak
CapturePageEx(Page, 3), bir sayfayı sınırlayıcı kutusu sayfanın etkin TrimBox'ı olan bir Form XObject'e çevirir ve DrawCapturedPage o formu başka bir sayfaya istenen boyutta yerleştirir. v3.539.42'den beri TrimBox'sız bir sayfada option 3, referansın anlattığı gibi MediaBox'ı ve bütün slug'ını değil, CropBox'ı verir
Capture'ın iki özelliği kodu biçimlendirir. Capture yıkıcıdır: capture edilen sayfa belgeden kaldırılır ve belge asla sıfır sayfaya düşemez; dolayısıyla herhangi bir şey capture etmeden önce ilk çıktı tabakasını ekleyin. Capture ayrıca yalnızca tek bir belge içinde çalışır; dolayısıyla önce bütün girdileri tek belgeye toplayın — PDF kaynaklarını tek geçişte harmanlamak ve serpiştirmek teknikleri doğrudan uygulanır
procedure ImposeTwoUp(const InFile, OutFile: string);
var
Lib: TPDFlib;
Captures: array of Integer;
SourceCount, I: Integer;
TrimW, TrimH: Double;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile(InFile, '') <> 1 then
raise Exception.Create('Cannot open ' + InFile);
SourceCount := Lib.PageCount;
// 1. sayfanın etkin trim boyutu (bu düzen tek tip trim varsayar)
Lib.SelectPage(1);
TrimW := Lib.GetPageBox(4, 2);
TrimH := Lib.GetPageBox(4, 3);
// İlk tabakayı ekleyip boyutlandır; NewPage yeni sayfayı seçer
Lib.NewPage;
Lib.SetPageDimensions(2 * TrimW, TrimH);
// Her capture 1. sayfayı kaldırır; sonraki kaynak sayfa yukarı kayar
SetLength(Captures, SourceCount);
for I := 0 to SourceCount - 1 do
begin
Captures[I] := Lib.CapturePageEx(1, 3); // 3 = TrimBox
if Captures[I] = 0 then
raise Exception.CreateFmt('Capture of source page %d failed', [I + 1]);
end;
// Geriye yalnızca tabaka kaldı: tabaka başına iki kırpılmış sayfa, yan yana
Lib.SelectPage(1);
for I := 0 to SourceCount - 1 do
begin
if (I > 0) and (I mod 2 = 0) then
Lib.NewPage; // geçerli tabakayla aynı boyut
// Varsayılan köken: Top üst kenardır, alttan ölçülür
Lib.DrawCapturedPage(Captures[I], (I mod 2) * TrimW, TrimH, TrimW, TrimH);
end;
Lib.SaveToFile(OutFile);
finally
Lib.Free;
end;
end;
Trim tabanlı bir capture, TrimBox dışındaki her şeyi kırpar; dijital bir prova ya da kes-ve-yığ düzeni için istediğiniz de budur. Baskıdan sonra kırpılacak bir baskı tabakası için option 2 ile capture edin ki bleed hayatta kalsın ve hücreleri bleed genişliğiyle aralayın. Capture kaynak sayfaları kaldırdığı için onlara işaret eden bookmark ve linkler hedeflerini kaybeder; dolayısıyla gezinmesine hâlâ ihtiyacınız olan bir belgeyi düzenlemek yerine ayrı bir çıktı dosyasına dayayın — bookmark'ları bozmadan sayfa değiştirme sayfa cerrahisinin o tarafını kapsar
Kaynak sapasağlam kalmak zorundayken ImportPageAsFormXObject(SourceDocumentID, SourcePage, Options) aynı 0-4 option değerlerini alır (geçerli belge için Lib.SelectedDocument geçirin), kaynak page tree'ye dokunmaz, kalıtılan sayfa rotasyonunu form matrisine normalize eder ve DrawCapturedPage'in kabul ettiği bir handle döndürür. CapturePageEx /Rotate'i geri almaz; dolayısıyla döndürülmüş girdi önce o adımı ister ve page box'ları bozmadan sayfa rotasyonunu düzleştirmek yaptığınızda her kutuya ne olduğunu gösterir. /Pages düğümlerinde production kutuları taşıyabilecek girdiler için bir uyarı: import yolu kutusunu kendi ata aramasıyla çözer — v3.539.44'te hizalanan iki yoldan ayrı olarak — dolayısıyla önce kaynak sayfada HasPageBox(4)'ü denetleyin ve 0 döndüğünde option 1 (CropBox) geçirin. Sonuç, dosyanın tesadüfen nasıl yazıldığına değil belirtime bağlanmış kalır
Page box hızlı başvurusu
- Etkin CropBox: sayfanın kendi CropBox'ı, yoksa en yakın kalıtılmış CropBox, o da yoksa etkin MediaBox (ISO 32000-1 §14.11.2)
- Etkin BleedBox, TrimBox ve ArtBox: yaprak sayfanın kendi girdisi, yoksa etkin CropBox
- Yalnızca
Resources,MediaBox,CropBoxveRotate/Pagesdüğümlerinden kalıtılır (§7.7.3.4, Table 30);/Pagesdüğümlerindeki production kutuları yok sayılır GetPageBox(BoxType, Dimension): BoxType 1 MediaBox, 2 CropBox, 3 BleedBox, 4 TrimBox, 5 ArtBox; Dimension 0 Left, 1 Top, 2 Width, 3 Height, 4 Right, 5 BottomHasPageBox(BoxType): 0 kutu yok, 1 sayfanın kendi kutusu (direkt ya da indirect), 2 kalıtılmış bir MediaBox ya da CropBox (direkt ya da indirect)CapturePageEx(Page, Options): 0 MediaBox, 1 MediaBox yedekli CropBox, 2-4 CropBox yedekli BleedBox, TrimBox ya da ArtBox- Kutu sorguları ile capture arasında tutarlı varsayılanlar ve kalıtım için v3.539.44 ve sonrasına yükseltin
Page box'lar, PDF'in sessiz varsayılanlarının milimetrenin kesirleriyle ölçülen prepress toleranslarıyla buluştuğu yerdir; bir kütüphane ya o varsayılanları her yerde aynı biçimde uygular ya da tek soruya iki yanıt verir. Tam kutu, capture ve Form XObject API'si PDFlibPas PDF Library for Delphi ürün sayfasında belgelenmiştir