Kad PDF stranica nema TrimBox, njen efektivni TrimBox je CropBox stranice, a kad i CropBox nedostaje, on je MediaBox. BleedBox i ArtBox prate isto pravilo. PDFlibPas, PDF Library za Delphi, primenjuje ovaj lanac podrazumevanih vrednosti dosledno u GetPageBox, HasPageBox i CapturePageEx od v3.539.44, i ignoriše produkcijske kutije postavljene na /Pages čvor, jer ISO 32000-1 ne dopušta da nasleđuju
Zvuči kao fusnota dok ne isplombirate posao. Zamislite unutrašnjost knjige sa MediaBox-om od 6.25 × 9.25 in, CropBox postavljenim na trim od 6 × 9 in, i bez TrimBox-a, jer ga onaj ko ga je izvezao nije pomislio da upiše. Zatražite trim kutiju, dobijete media kutiju, i svaka ćelija na vašem tiskarskom listu odvlači osminu inča bleed i slug-a ka susedi. PDFlibPas je imao defekte baš na ovom području, popravljene u v3.539.42 i v3.539.44, i način na koji su popravljeni govori nešto o tome kako treba implementirati semantiku kutija stranica u bilo kojoj PDF biblioteci
Koja kutija važi kad stranica nema TrimBox?
Odgovor je fiksni lanac podrazumevanih vrednosti iz ISO 32000-1 §14.11.2: CropBox se podrazumeva na MediaBox, a BleedBox, TrimBox i ArtBox svaki se podrazumeva na CropBox. Ništa osim CropBox-a se ne podrazumeva pravo na MediaBox. Stranica koja definiše samo MediaBox zato ima pet identičnih kutija, a stranica koja definiše MediaBox plus CropBox ima četiri kutije jednake CropBox-u
| Kutija | PDFlibPas BoxType | Podrazumevana kad odsustvuje | Naslediva sa /Pages |
|---|---|---|---|
| MediaBox | 1 | Ništa, unos je obavezan | Da |
| CropBox | 2 | MediaBox | Da |
| BleedBox | 3 | CropBox | Ne |
| TrimBox | 4 | CropBox | Ne |
| ArtBox | 5 | CropBox | Ne |
Dvostepeni lanac je bitan jer CropBox može i sam biti nasleđen. Efektivni TrimBox stranice koja nema ni svoj TrimBox ni svoj CropBox je CropBox najbližeg pretka koji ga ima, a kad ni toga nema, nasleđeni MediaBox. Specifikacija dodaje još jedno pravilo koje se lako zaboravi: crop, bleed, trim i art kutije ne bi trebalo da prelaze media kutiju, i ako prelaze, efektivno se smanjuju na svoj presek sa njom. PDFlibPas prijavljuje svaku kutiju kako je pohranjena u fajlu, pa validator koji radi sa nepouzdanim unosom treba sam da steže prema MediaBox-u
Koje atribute stranica /Pages čvor može da prenese?
Tačno četiri: Resources, MediaBox, CropBox i Rotate. ISO 32000-1 §7.7.3.4 definiše nasleđivanje atributa, i Table 30 označava samo te četiri unosa objekta stranice kao nasledive. BleedBox, TrimBox i ArtBox pripadaju listu stranice. TrimBox upisan u /Pages čvor nije nasleđena vrednost; to je nestandardni ključ koji korektan čitač ignoriše
Takvi nestandardni fajlovi postoje, tipično sa jednim TrimBox-om na korenskom čvoru stabla stranica kao kraticom za „svaka stranica ima ovaj trim“. Kratnica izgleda ispravno u svakom alatu koji obilazi /Parent za svaki ključ, i to je problem: fajl sada znači dve stvari u zavisnosti ko ga čita. Čitač koji prati specifikaciju ne vidi TrimBox i koristi CropBox, dok čitač koji nasleđuje sve vidi vrednost roditelja. U prepress cevovodu ta dvosmislenost završava na tiskarskom listu
PDF/X (ISO 15930) tokovi posla zavise od TrimBox-a za gotovu veličinu, i PDF/X profili zahtevaju da svaka stranica deklariše TrimBox ili ArtBox. Kutija parkirana na /Pages čvoru ne ispunjava taj zahtev, jer ključ nikada ne stigne do objekta stranice. Preflight bi trebalo da označi takve fajlove umesto da ih tiho pročita jednim ili drugim načinom
Šta je PDFlibPas radio pogrešno pre v3.539.44?
PDFlibPas je imao tri odvojena defekta, sve u prostoru između onoga što specifikacija kaže i onoga što su dve nezavisne kodne putanje radile. Prvi je popravljen u v3.539.42, druga dva u v3.539.44
Produkcijske kutije podrazumevane na MediaBox pri hvatanju
Pre v3.539.42, interna rutina koja priprema stranicu za hvatanje (kopira nasleđene unose na stranicu i popunjava nedostajuće kutije) davala je BleedBox, TrimBox i ArtBox vrednosti MediaBox-a kad su odsustvovali. CapturePageEx sa opcijama 2 do 4 čita svoj ogradni pravougaonik baš iz tih popunjenih unosa, pa na stranici koja definiše samo CropBox, zahtev za trim kutijom hvatao je celu media kutiju. GetPageBox već je primenjivao CropBox podrazumevanu vrednost, i CapturePageEx referenca je oduvek govorila da se crop kutija koristi kad tražena kutija nedostaje; kod hvatanja se s obema protivrečio. Od v3.539.42 tri produkcijske kutije se podrazumevaju na CropBox stranice, koji je u tom trenutku već na stranici (sopstveni, kopiran od pretka, ili popunjen iz MediaBox-a), i samo CropBox sam vraća se na MediaBox
Dve putanje nasleđivanja, jedno semantičko pravilo
Drugi defekt bilo je nestandardno nasleđivanje samo, i suptilan deo bio je što je PDFlibPas razrešavao kutije duž dve nezavisne putanje. Upiti kutija (GetPageBox i HasPageBox) hodali su /Parent lanac kroz jednog pomoćnika, a hvatanje kroz posebnog lokalnog pomoćnika. Oba su nasleđivala svaki ključ, uključujući produkcijske kutije. Popraviti samo jedan od njih proizvelo bi protivrečnost unutar jednog dokumenta: sa TrimBox-om širokim 180 tačaka na /Pages čvoru i CropBox-om širokim 380 tačaka na stranici, GetPageBox bi i dalje prijavljivao trim širinu 180 dok bi CapturePageEx gradio formu široku 380. U v3.539.44 obe putanje ograničavaju /Parent šetnju na četiri naslediva ključa, produkcijske kutije čitaju se samo sa lista, i zalutali roditeljski unos ostaje u fajlu netaknut, ni obrisani ni prepisani
HasPageBox promašio direktne roditeljske nizove
HasPageBox vraća 0 kad stranica nema kutiju traženog tipa, 1 kad stranica ima sopstvenu kutiju (pohranjenu direktno ili kroz indirektnu referencu), i 2 kad je MediaBox ili CropBox nasleđen od pretka. Stari kod vraćao je 2 samo kad je nasleđena vrednost bila indirektna referenca, pa je nasleđen direktan niz vraćao 0. Popravka odvaja dereferenciranje od testa niza, i obe reprezentacije sada vraćaju 2. Od v3.539.44, HasPageBox za BleedBox, TrimBox ili ArtBox može vratiti samo 0 ili 1
Lekcija se uopštava daleko van kutija stranica. Kad jedan deo semantike specifikacije ima dva implementaciona ulaza u biblioteci, popravite ih zajedno i testirajte ih kao matricu, a ne sa jednim happy-path fajlom. PDFlibPas regresioni skup ukršta dve reprezentacije roditeljske kutije (direktan i indirektan niz) sa tri stanja lista (odsutan, direktan niz, indirektan niz) i tri opcije hvatanja (bleed, trim, art), dajući 18 scenarija, i svaki proverava rezultat upita, uhvaćene granice, legitimno nasleđivanje MediaBox-a i CropBox-a i netaknuti roditeljski unos
Kako pročitati efektivni TrimBox u Delphi-ju?
Zovite GetPageBox(4, Dimension) na izabranoj stranici. PDFlibPas primenjuje lanac podrazumevanih vrednosti za vas, pa je rezultat efektivni TrimBox bilo da ga stranica ima ili ne. Uparete ga sa HasPageBox kad treba da znate odakle vrednost dolazi, što preflight izveštaj obično hoće
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 = own, 2 = inherited
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.
I GetPageBox i SetPageBox rade u trenutnim koordinatnim podešavanjima dokumenta. Primeri ovde idu sa podrazumevanima: poreklo 0 (dole levo, u skladu sa PDF user space) i tačke kao merna jedinica, pa je Top dimenzija gornja ivica merena naviše od dna stranice. Posle SetOrigin(1) dimenzije Top i Bottom mere se naniže od vrha stranice, a posle SetMeasurementUnits(1) svaka vrednost stiže u milimetrima. Širina i visina ne zavise od porekla
Nalaženje produkcijskih kutija nasukanih na /Pages čvorovima
Od v3.539.44 kutija API više ne vidi TrimBox na /Pages čvoru, što je ispravno, ali preflight alat obično želi takav fajl da prijavi, a ne da ga tiho pročita na spec način. Čvorovi stabla stranica su obični objekti, pa niskonivojni objektni API može da ih nađe: hodajte brojeve objekata do GetMaxObjectNumber, čitajte svaki sa GetObjectToString, i tražite /Pages rečnik koji nosi ključ produkcijske kutije. Druga polovina provere je test po stranici koji PDF/X pazi, i HasPageBox sada na njega odgovara onako kako bi PDF/X validator, jer roditeljski TrimBox više ne računa
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. Produkcijske kutije na čvorovima stabla stranica: nestandardne i ignorisane
for ObjNum := 1 to Lib.GetMaxObjectNumber do
begin
Src := ''; // slobodni brojevi ne vraćaju tekst
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: svaka stranica treba sopstveni TrimBox ili ArtBox
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. Opciona popravka: trim 6 x 9 in unutar media kutije 6.25 x 9.25 in
// (tačke, poreklo dole-levo: Left, Top, Width, Height)
if Missing > 0 then
Log.Add(Format('TrimBox written on %d pages',
[Lib.SetPageBoxRange('', 4, 9, 657, 432, 648)]));
end;
Tekstualno poklapanje je pragmatična provera, ne parser. Oslanja se na to da PDFlibPas serijalizuje svaki unos rečnika kao ključ, jedan razmak i vrednost, što važi za objekte pročitane nazad kroz GetObjectToString. Korak popravke zaslužuje odluku, a ne refleks: zalutala roditeljska vrednost može sasvim biti ono što je autor nameravao, ali potvrdite je protiv radnog naloga pre nego što je učinite zvaničnom. SetPageBoxRange sa praznim opsegom primenjuje kutiju na svaku stranicu i vraća broj ažuriranih stranica. Kad je postojeća kutija stranice indirektan niz, koji druga stranica ili /Pages čvor mogu deliti, SetPageBox daje toj stranici novi direktan niz umesto da prepisuje deljeni objekat. Postavljanje BleedBox, TrimBox ili ArtBox takođe podiže otključan dokument na PDF 1.3, verziju koja je uvela te unose
Plombiranje stranica na TrimBox sa CapturePageEx
CapturePageEx(Page, 3) pretvara stranicu u Form XObject čiji je ogradni okvir efektivni TrimBox stranice, a DrawCapturedPage postavlja tu formu na drugu stranicu u bilo kojoj veličini. Od v3.539.42, opcija 3 na stranici bez TrimBox-a daje vam CropBox, kako referenca opisuje, umesto MediaBox-a sa svim njegovim slug-om
Dve osobine hvatanja oblikuju kod. Hvatanje je destruktivno: uhvaćena stranica se uklanja iz dokumenta, i dokument nikada ne može pasti na nulu stranica, pa dodajte prvi izlazni list pre nego što bilo šta uhvatite. Hvatanje takođe radi samo unutar jednog dokumenta, pa prvo povucite svaki ulaz u jedan dokument; tehnike za slaganje i ispreplitanje PDF izvora u jednom prolazu primenjuju se direktno
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;
// Efektivna trim veličina stranice 1 (ovaj raspored pretpostavlja ujednačen trim)
Lib.SelectPage(1);
TrimW := Lib.GetPageBox(4, 2);
TrimH := Lib.GetPageBox(4, 3);
// Dodajte i dimenzionišite prvi list; NewPage bira novu stranicu
Lib.NewPage;
Lib.SetPageDimensions(2 * TrimW, TrimH);
// Svako hvatanje uklanja stranicu 1, pa se sledeća izvorna stranica pomera gore
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;
// Ostao je samo list: dve odsečene stranice po listu, jedne pored drugih
Lib.SelectPage(1);
for I := 0 to SourceCount - 1 do
begin
if (I > 0) and (I mod 2 = 0) then
Lib.NewPage; // iste veličine kao trenutni list
// Podrazumevano poreklo: Top je gornja ivica, mereno od dna
Lib.DrawCapturedPage(Captures[I], (I mod 2) * TrimW, TrimH, TrimW, TrimH);
end;
Lib.SaveToFile(OutFile);
finally
Lib.Free;
end;
end;
Hvatanje zasnovano na trimu iseče sve van TrimBox-a, što hoćete za digitalni probni otisak ili cut-and-stack raspored. Za tiskarski list koji se seče posle štampe, hvatajte opcijom 2 da bleed preživi, i razmaknite ćelije po širini bleed-a. Pošto hvatanje uklanja izvorne stranice, bookmark-i i linkovi koji su pokazivali na njih gube mete, pa plombirajte u odvojeni izlazni fajl umesto da uređujete dokument čiju navigaciju još trebate; zamena stranica bez lomljenja bookmark-a pokriva tu stranu operacije nad stranicama
Kad izvor mora ostati netaknut, ImportPageAsFormXObject(SourceDocumentID, SourcePage, Options) prima iste opcije od 0 do 4 (prosledite Lib.SelectedDocument za trenutni dokument), ostavlja izvorno stablo stranica nepromenjeno, normalizuje nasleđenu rotaciju stranice u matricu forme, i vraća handle koji DrawCapturedPage prima. CapturePageEx ne poništava /Rotate, pa rotirani ulaz prvo treba taj korak, a izravnavanje rotacije stranice bez lomljenja kutija stranica pokazuje šta se dešava sa svakom kutijom kad to uradite. Jedno upozorenje za ulaze koji mogu nositi produkcijske kutije na /Pages čvorovima: putanja uvoza razrešava svoju kutiju kroz sopstveno potraživanje pretka, odvojeno od dve putanje usklađene u v3.539.44, pa prvo proverite HasPageBox(4) na izvornoj stranici i prosledite opciju 1 (CropBox) kad vrati 0. To drži rezultat vezanim za specifikaciju, a ne za to kako je fajl slučajno upisan
Brzi pregled kutija stranice
- Efektivni CropBox: sopstveni CropBox stranice, inače najbliži nasleđeni CropBox, inače efektivni MediaBox (ISO 32000-1 §14.11.2)
- Efektivni BleedBox, TrimBox i ArtBox: sopstveni unos lista stranice, inače efektivni CropBox
- Samo
Resources,MediaBox,CropBoxiRotatenasleđuju se sa/Pagesčvorova (§7.7.3.4, Table 30); produkcijske kutije na/Pagesčvorovima ignorišu se 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 nema kutije, 1 sopstvena kutija stranice (direktna ili indirektna), 2 nasleđeni MediaBox ili CropBox (direktan ili indirektan)CapturePageEx(Page, Options): 0 MediaBox, 1 CropBox sa vraćanjem na MediaBox, 2 do 4 BleedBox, TrimBox ili ArtBox sa vraćanjem na CropBox- Nadogradite na v3.539.44 ili noviji za dosledne podrazumevane vrednosti i nasleđivanje kroz upite kutija i hvatanje
Kutije stranice su mesto gde tihe podrazumevane vrednosti PDF-a sreću prepress tolerancije merene delovima milimetra, i biblioteka ili primenjuje te vrednosti isto svuda ili vam uručuje dva odgovora na jedno pitanje. Kompletan API kutija, hvatanja i Form XObject dokumentovan je na stranici proizvoda PDFlibPas PDF Library for Delphi