Kad PDF stranica nema TrimBox, njezin djelotvorni TrimBox jest CropBox stranice, a kad nedostaje i CropBox, onda je to MediaBox. BleedBox i ArtBox slijede isto pravilo. PDFlibPas, PDF Library za Delphi, primjenjuje taj lanac zadanih vrijednosti dosljedno u GetPageBox, HasPageBox i CapturePageEx od v3.539.44, i ignorira produkcijske okvire postavljene na /Pages čvor, jer ISO 32000-1 ne dopušta da se nasljeđuju
Zvuči kao fusnota dok ne impozirate posao. Zamislite unutrašnjost knjige s MediaBoxom od 6,25 × 9,25 inča, CropBoxom postavljenim na 6 × 9 inča reza, i bez TrimBoxa, jer ga tko god ga je izvezao nije pomislio zapisati. Zatražite trim box, a dobijete media box, i svaka ćelija na vašem tiskarskom arku vuče osminu inča ispusta i sluga u susjeda. PDFlibPas je imao defekte točno na tom području, popravljene u v3.539.42 i v3.539.44, a način na koji su popravljeni nešto govori o tome kako bi semantika okvira stranica trebala biti implementirana u svakoj PDF biblioteci
Koji se okvir primjenjuje kad stranica nema TrimBox?
Odgovor je fiksni lanac zadanih vrijednosti iz ISO 32000-1 §14.11.2: CropBox zadano jest MediaBox, a BleedBox, TrimBox i ArtBox svaki zadano jesu CropBox. Ništa osim CropBoxa ne pada izravno na MediaBox. Stranica koja definira samo MediaBox stoga ima pet identičnih okvira, a stranica koja definira MediaBox plus CropBox ima četiri okvira jednaka CropBoxu
| Okvir | PDFlibPas BoxType | Zadano kad nema | Nasljedivo s /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 |
Dvostupanjski lanac važan je jer CropBox sam može biti naslijeđen. Djelotvorni TrimBox stranice koja nema ni TrimBox ni vlastiti CropBox jest CropBox najbližeg predka koji ga ima, a ako ni toga, naslijeđeni MediaBox. Spec dodaje još jedno pravilo koje se lako zaboravi: crop, bleed, trim i art okviri ne smiju prelaziti media box, a ako prelaze, djelotvorno se svode na svoj presjek s njim. PDFlibPas javlja svaki okvir kako je spremljen u datoteci, pa bi validator koji rukuje nepouzdanim ulazom trebao stezati prema samom MediaBoxu
Koje atribute stranice /Pages čvor može prenijeti dalje?
Točno četiri: Resources, MediaBox, CropBox i Rotate. ISO 32000-1 §7.7.3.4 definira nasljeđivanje atributa, a Tablica 30 označava samo ta četiri unosa objekta stranice kao nasljediva. BleedBox, TrimBox i ArtBox pripadaju listnoj stranici. TrimBox zapisan u /Pages čvor nije naslijeđena vrijednost; to je nestandardni ključ kojeg sukladni čitač ignorira
Nestandardne datoteke poput te postoje, obično s jednim TrimBoxom na korijenskom čvoru stabla stranica kao kraticom za „svaka stranica ima ovaj rez". Kratica izgleda ispravno u svakom alatu koji prevaljuje /Parent za svaki ključ, i to je problem: datoteka sada znači dvije stvari ovisno o tome tko je čita. Čitač koji slijedi spec ne vidi TrimBox i koristi CropBox, dok čitač koji nasljeđuje sve vidi vrijednost roditelja. U prepress pipelineu ta dvosmislenost završi na tiskarskom arku
PDF/X (ISO 15930) tokovi rada ovise o TrimBoxu za gotovu veličinu, a PDF/X profili zahtijevaju da svaka stranica deklarira TrimBox ili ArtBox. Okvir parkiran na /Pages čvoru ne zadovoljava taj zahtjev, jer ključ nikad ne dođe do objekta stranice. Preflight bi trebao označiti takve datoteke, a ne tiho ih čitati jednim ili drugim načinom
Što je PDFlibPas bio pogriješio prije v3.539.44?
PDFlibPas je imao tri odvojena defekta, sve u rasponu između onoga što spec kaže i onoga što su dvije neovisne putanje koda radile. Prvi je popravljen u v3.539.42, a druga dva u v3.539.44
Produkcijski okviri padali su na MediaBox pri hvatanju
Prije v3.539.42 interna rutina koja priprema stranicu za hvatanje (kopira naslijeđene unose na stranicu i popunjava nedostajuće okvire) davala je BleedBoxu, TrimBoxu i ArtBoxu MediaBox vrijednosti kad su nedostajale. CapturePageEx s opcijama 2 do 4 čita svoj obodni pravokutnik iz točno tih popunjenih unosa, pa se na stranici koja definira samo CropBox zahtjevom za trim box hvatao cijeli media box. GetPageBox je već primjenjivao CropBox zadano, a CapturePageEx referenca je oduvijek govorila da se crop box koristi kad traženi okvir nedostaje; kod hvatanja nije se slagao ni s jednim ni s drugim. Od v3.539.42 tri produkcijska okvira padaju na CropBox stranice, koji u tom trenutku već stoji na stranici (vlastiti, kopiran od predka ili popunjen iz MediaBoxa), a samo se CropBox vraća na MediaBox
Dvije nasljedne putanje, jedno semantičko pravilo
Drugi defekt bilo je samo nestandardno nasljeđivanje, a suptilan dio bio je što je PDFlibPas razrješivao okvire duž dviju neovisnih putanja. Upiti okvira (GetPageBox i HasPageBox) prevaljivali su /Parent lanac kroz jednog pomoćnika, a hvatanje kroz zasebnog lokalnog pomoćnika. Oboje je nasljeđivalo svaki ključ, uključujući produkcijske okvire. Popraviti samo jedan od njih proizvelo bi proturječje unutar jednog dokumenta: sa 180-točaka širokim TrimBoxom na /Pages čvoru i 380-točaka širokim CropBoxom na stranici, GetPageBox bi i dalje javljao širinu reza 180 dok bi CapturePageEx gradio form od 380. U v3.539.44 obje putanje ograničavaju /Parent prevaljanje na četiri nasljediva ključa, produkcijski se okviri čitaju samo s lista, a stran unos roditelja ostaje u datoteci netaknut, ni izbrisan ni prepravljen
HasPageBox promašivao izravna roditeljska polja
HasPageBox vraća 0 kad stranica nema okvir traženog tipa, 1 kad stranica ima vlastiti okvir (spremljen izravno ili kroz neizravnu referencu), i 2 kad je MediaBox ili CropBox naslijeđen od predka. Stari je kod vraćao 2 samo kad je naslijeđena vrijednost bila neizravna referenca, pa je naslijeđeno izravno polje vraćalo 0. Popravak razdvaja dereferenciranje od testa polja, i obje reprezentacije sada vraćaju 2. Od v3.539.44 HasPageBox za BleedBox, TrimBox ili ArtBox može vratiti samo 0 ili 1
Lekcija se generalizira daleko izvan okvira stranica. Kad jedan komad spec semantike ima dvije implementacijske ulazne točke u biblioteci, popravite ih zajedno i testirajte ih kao matricu, a ne s jednom datotekom sretnog puta. PDFlibPas regresijski skup ukršta dvije reprezentacije roditeljskog okvira (izravno i neizravno polje) s tri stanja lista (odsutno, izravno polje, neizravno polje) i tri opcije hvatanja (bleed, trim, art), dajući 18 scenarija, i svako provjerava rezultat upita, uhvaćene granice, legitimno MediaBox i CropBox nasljeđivanje i netaknut unos roditelja
Kako čitati djelotvorni TrimBox u Delphiju?
Pozovite GetPageBox(4, Dimension) na odabranoj stranici. PDFlibPas za vas primjenjuje lanac zadanih vrijednosti, pa je rezultat djelotvorni TrimBox ima li ga stranica ili ne. Kombinirajte ga s HasPageBox kad trebate znati odakle vrijednost dolazi, što izvještaj preflighta 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 = vlastiti, 2 = naslijeđen
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 trenutačnim postavkama koordinata dokumenta. Primjeri ovdje rade sa zadanim vrijednostima: ishodište 0 (dolje lijevo, u skladu s PDF user spaceom) i točke kao mjerna jedinica, pa je dimenzija Top gornji rub mjeren gore od dna stranice. Nakon SetOrigin(1) dimenzije Top i Bottom mjere se dolje od vrha stranice, a nakon SetMeasurementUnits(1) svaka se vrijednost vraća u milimetrima. Širina i visina ne ovise o ishodištu
Nalaženje produkcijskih okvira nasukanih na /Pages čvorovima
Od v3.539.44 okvirni API više ne vidi TrimBox na /Pages čvoru, što je ispravno, ali preflight alat obično želi takvu datoteku prijaviti, a ne je tiho pročitati na spec način. Čvorovi stabla stranica obični su objekti, pa ih niskorazinski objektni API može naći: prevalite brojeve objekata do GetMaxObjectNumber, pročitajte svaki s GetObjectToString i tražite /Pages rječnik koji nosi ključ produkcijskog okvira. Druga polovica provjere jest test po stranici koji PDF/X-u je stvar, a HasPageBox ga sada rješava onako kako bi to učinio PDF/X validator, jer se 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. Produkcijski okviri na čvorovima stabla stranica: nestandardni i ignorirani
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 vlastiti 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. Neobavezan popravak: 6 x 9 in rez unutar 6.25 x 9.25 in media boxa
// (točke, ishodište dolje lijevo: Left, Top, Width, Height)
if Missing > 0 then
Log.Add(Format('TrimBox written on %d pages',
[Lib.SetPageBoxRange('', 4, 9, 657, 432, 648)]));
end;
Tekstovno poklapanje pragmatična je provjera, a ne parser. Oslanja se na to da PDFlibPas serijalizira svaki unos rječnika kao ključ, jedan razmak i vrijednost, što vrijedi za objekte pročitane natrag kroz GetObjectToString. Korak popravka zaslužuje odluku, a ne refleks: stran unos roditelja može lako biti ono što je autor mislio, ali potvrdite ga protiv radnog naloga prije nego ga učinite službenim. SetPageBoxRange s praznim rasponom primjenjuje okvir na svaku stranicu i vraća broj ažuriranih stranica. Kad je postojeći okvir stranice neizravno polje, koje druga stranica ili /Pages čvor mogu dijeliti, SetPageBox daje toj stranici novo izravno polje umjesto da prepiše dijeljeni objekt. Postavljanje BleedBoxa, TrimBoxa ili ArtBoxa također podiže otključani dokument na PDF 1.3, verziju koja je uvela te unose
Impozicija stranica na TrimBox s CapturePageEx
CapturePageEx(Page, 3) pretvara stranicu u Form XObject čiji je obodni okvir djelotvorni TrimBox stranice, a DrawCapturedPage postavlja taj form na drugu stranicu u bilo kojoj veličini. Od v3.539.42 opcija 3 na stranici bez TrimBoxa daje vam CropBox, kako referenca opisuje, umjesto MediaBoxa sa svim njegovim slugom
Dva svojstva hvatanja oblikuju kod. Hvatanje je destruktivno: uhvaćena stranica uklanja se iz dokumenta, i dokument nikad ne smije pasti na nula stranica, pa dodajte prvi izlazni ark prije nego što išta uhvatite. Hvatanje radi i samo unutar jednog dokumenta, pa prvo povucite svaki ulaz u jedan dokument; tehnike za slaganje i ispreplitanje PDF izvora u jednom prolazu primjenjuju se izravno
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;
// Djelotvorna veličina reza stranice 1 (ovaj raspored pretpostavlja ujednačen rez)
Lib.SelectPage(1);
TrimW := Lib.GetPageBox(4, 2);
TrimH := Lib.GetPageBox(4, 3);
// Dodajte i dimenzionirajte prvi ark; NewPage odabire novu stranicu
Lib.NewPage;
Lib.SetPageDimensions(2 * TrimW, TrimH);
// Svako hvatanje uklanja stranicu 1, pa sljedeća izvorna stranica iskoči 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 ark: dvije obrezane stranice po arku, jedno uz drugo
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 trenutačni ark
// Zadano ishodište: Top je gornji rub, mjeren od dna
Lib.DrawCapturedPage(Captures[I], (I mod 2) * TrimW, TrimH, TrimW, TrimH);
end;
Lib.SaveToFile(OutFile);
finally
Lib.Free;
end;
end;
Hvatanje temeljeno na rezu izreže sve izvan TrimBoxa, što želite za digitalni probni otisak ili cut-and-stack raspored. Za tiskarski ark koji se reže nakon tiska hvatajte s opcijom 2 da ispust preživi, i razmaknite ćelije za širinu ispusta. Budući da hvatanje uklanja izvorne stranice, bookmarkovi i poveznice koje su pokazivale na njih gube svoje ciljeve, pa impozirajte u zasebnu izlaznu datoteku umjesto da uređujete dokument čiju navigaciju još trebate; zamjena stranica bez lomljenja bookmarkova pokriva tu stranu operacija na stranicama
Kad izvor mora ostati netaknut, ImportPageAsFormXObject(SourceDocumentID, SourcePage, Options) prima iste vrijednosti opcija od 0 do 4 (prenesite Lib.SelectedDocument za trenutačni dokument), ostavlja izvorno stablo stranica nepromijenjenim, normalizira naslijeđenu rotaciju stranice u form matricu i vraća handle koji DrawCapturedPage prihvaća. CapturePageEx ne poništava /Rotate, pa rotirani ulaz prvo treba taj korak, a izravnavanje rotacije stranice bez lomljenja okvira stranica pokriva što se dogodi sa svakim okvirom kad to napravite. Jedno upozorenje za ulaze koji mogu nositi produkcijske okvire na /Pages čvorovima: putanja uvoza razrješuje svoj okvir kroz vlastito traženje predaka, odvojeno od dviju putanja usklađenih u v3.539.44, pa prvo provjerite HasPageBox(4) na izvornoj stranici i prenesite opciju 1 (CropBox) kad vrati 0. To rezultat veže uz spec, a ne uz to kako je datoteka slučajno zapisana
Brza referenca okvira stranica
- Djelotvorni CropBox: vlastiti CropBox stranice, inače najbliži naslijeđeni CropBox, inače djelotvorni MediaBox (ISO 32000-1 §14.11.2)
- Djelotvorni BleedBox, TrimBox i ArtBox: vlastiti unos listne stranice, inače djelotvorni CropBox
- Samo
Resources,MediaBox,CropBoxiRotatenasljeđuju se s/Pagesčvorova (§7.7.3.4, Tablica 30); produkcijski okviri na/Pagesčvorovima ignoriraju 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 okvira, 1 vlastiti okvir stranice (izravan ili neizravan), 2 naslijeđeni MediaBox ili CropBox (izravan ili neizravan)CapturePageEx(Page, Options): 0 MediaBox, 1 CropBox s povratkom na MediaBox, 2 do 4 BleedBox, TrimBox ili ArtBox s povratkom na CropBox- Nadogradite na v3.539.44 ili kasniji za dosljedne zadane vrijednosti i nasljeđivanje kroz upite okvira i hvatanje
Okviri stranica mjesto su gdje se tihe PDF zadane vrijednosti susreću s prepress tolerancijama mjerenim dijelovima milimetra, i biblioteka ili primjenjuje te zadane vrijednosti jednako svugdje ili vam uručuje dva odgovora na jedno pitanje. Potpuni okvirni, capture i Form XObject API dokumentiran je na stranici proizvoda PDFlibPas PDF Library za Delphi