Kun PDF-sivulla ei ole TrimBoxia, sen tehollinen TrimBox on sivun CropBox, ja kun myös CropBox puuttuu, se on MediaBox. BleedBox ja ArtBox noudattavat samaa sääntöä. PDFlibPas, PDF Library for Delphi, soveltaa tätä oletusketjua yhdenmukaisesti funktioissa GetPageBox, HasPageBox ja CapturePageEx versiosta v3.539.44 alkaen, ja se ohittaa /Pages-solmulle sijoitetut tuotantolaatikot, koska ISO 32000-1 ei anna niiden periä
Kyse kuulostaa alaviitteeltä, kunnes impositoit työn. Kuvittele kirjan sisus, jossa on 6.25 × 9.25 tuuman MediaBox, 6 × 9 tuuman trimmiin asetettu CropBox eikä TrimBoxia lainkaan, koska sen vientiä tehnyt ei koskaan tullut ajatelleeksi kirjoittaa sellaista. Pyydä trim-laatikkoa, saat media-laatikon sijaan, ja jokainen painoarkin solu raahaa kahdeksasosan tuumaa bleedia ja slugia naapuriinsa. PDFlibPasissa oli vikoja täsmälleen tällä alueella, korjattu versioissa v3.539.42 ja v3.539.44, ja tapa, jolla ne korjattiin, kertoo jotain siitä, miten sivulaatikoiden semantiikan pitäisi toteutua missä tahansa PDF-kirjastossa
Mikä laatikko pätee, kun sivulla ei ole TrimBoxia?
Vastaus on kiinteä oletusketju lähteestä ISO 32000-1 §14.11.2: CropBoxin oletus on MediaBox, ja BleedBoxin, TrimBoxin ja ArtBoxin oletus on kukin CropBox. Mikään muu kuin CropBox ei mene oletuksena suoraan MediaBoxiin. Sivulla, joka määrittelee vain MediaBoxin, on siksi viisi identtistä laatikkoa, ja sivulla, joka määrittelee MediaBoxin plus CropBoxin, on neljä CropBoxin suuruista laatikkoa
| Laatikko | PDFlibPas BoxType | Oletus, kun puuttuu | Periytyvä /Pages-solmulta |
|---|---|---|---|
| MediaBox | 1 | Ei mitään, merkintä on pakollinen | Kyllä |
| CropBox | 2 | MediaBox | Kyllä |
| BleedBox | 3 | CropBox | Ei |
| TrimBox | 4 | CropBox | Ei |
| ArtBox | 5 | CropBox | Ei |
Kaksivaiheinen ketju merkitsee paljon, koska CropBox voi itse olla peritty. Sivun tehollinen TrimBox, jolla ei ole omaa TrimBoxia eikä CropBoxia, on lähimmän sellaisen esi-isän CropBox, ja jos sellaista ei ole, peritty MediaBox. Määrittely lisää yhden säännön, jonka unohtaa helposti: crop-, bleed-, trim- ja art-laatikoiden ei pidä ulottua media-laatikon yli, ja jos ne ulottuvat, ne kaventuvat tehollisesti leikkaukseensa sen kanssa. PDFlibPas raportoi jokaisen laatikon sellaisena kuin se on talletettu tiedostoon, joten epäluotettavaa syötettä käsittelevän validaattorin kannattaa puristaa MediaBoxia itseään vasten
Mitä sivuattribuutteja /Pages-solmu voi välittää alaspäin?
Tasan neljä: Resources, MediaBox, CropBox ja Rotate. ISO 32000-1 §7.7.3.4 määrittelee attribuuttien perinnän, ja taulukko 30 merkitsee vain ne neljä sivuobjektin merkintää perityviksi. BleedBox, TrimBox ja ArtBox kuuluvat lehtisivulle. /Pages-solmuun kirjoitettu TrimBox ei ole peritty arvo; se on epästandardi avain, jonka määritelmän mukainen lukija ohittaa
Tällaisia epästandardia tiedostoja on olemassa, tyypillisesti yhdellä TrimBoxilla juurisivupuusolmulla lyhenteenä lauseelle "jokaisella sivulla on tämä trim". Lyhenteen näyttää oikealta mikä tahansa työkalu, joka kulkee /Parentia jokaista avainta varten, ja se on ongelma: tiedosto tarkoittaa nyt kahta asiaa riippuen siitä, kuka sen lukee. Määritelmää seuraava lukija ei näe TrimBoxia ja käyttää CropBoxia, kun taas kaiken perivä lukija näkee vanhemman arvon. Esipainoprosessissa kyseinen monimerkityksisyys päätyy painoarkille
PDF/X-työnkulut (ISO 15930) riippuvat TrimBoxista valmiin koon kannalta, ja PDF/X-profiilit vaativat, että jokainen sivu ilmoittaa TrimBoxin tai ArtBoxin. /Pages-solmulle pysäköity laatikko ei täytä kyseistä vaatimusta, koska avain ei koskaan yletä sivuobjektiin. Preflightin kannattaa liputtaa tällaiset tiedostot sen sijaan, että lukee ne hiljaa jommalla kummalla tavalla
Mitä PDFlibPas sai väärin ennen v3.539.44:ää?
PDFlibPasissa oli kolme erillistä vikaa, kaikki siinä välissä, mitä määrittely sanoo ja mitä kaksi itsenäistä koodipolkua teki. Ensimmäinen korjattiin versiossa v3.539.42, muut kaksi versiossa v3.539.44
Tuotantolaatikot ottivat oletuksena MediaBoxin kaappauksen yhteydessä
Ennen v3.539.42:sta sisäinen rutiini, joka valmistelee sivun kaappausta varten (se kopioi perityt merkinnät sivulle ja täyttää puuttuvat laatikot), antoi BleedBoxille, TrimBoxille ja ArtBoxille MediaBoxin arvot, kun ne olivat poissa. CapturePageEx valinnoilla 2–4 lukee rajalaatikkonsa täsmälleen kyseisistä täytetyistä merkinnöistä, joten sivulla, joka määrittelee vain CropBoxin, trim-laatikon pyytäminen kaappasi koko media-laatikon. GetPageBox sovelsi jo CropBox-oletusta, ja CapturePageEx-referenssi oli aina sanonut, että crop-laatikkoa käytetään, kun pyydetty laatikko puuttuu; kaappauskoodi oli eri mieltä kummastakin. Versiosta v3.539.42 alkaen kolmen tuotantolaatikon oletus on sivun CropBox, joka siihen mennessä on jo sivulla (sen oma, esi-isästä kopioitu tai MediaBoxista täytetty), ja vain CropBox itse palaa MediaBoxiin
Kaksi perintäpolkua, yksi semanttinen sääntö
Toinen vika oli epästandardi perintä itse, ja hienovarainen osa oli siinä, että PDFlibPas ratkaisi laatikot pitkin kahta itsenäistä polkua. Laatikkokyselyt (GetPageBox ja HasPageBox) kulkivat /Parent-ketjun yhden avustajan kautta, ja kaappaus kulki sen erillisen paikallisen avustajan kautta. Molemmat perivät jokaisen avaimen, tuotantolaatikot mukaan lukien. Vain toisen korjaaminen olisi tuottanut ristiriidan yhden asiakirjan sisään: kun /Pages-solmulla on 180 pisteen levyinen TrimBox ja sivulla 380 pisteen levyinen CropBox, GetPageBox olisi yhä raportoinut trim-leveydeksi 180, kun CapturePageEx rakensi 380 levyisen formin. Versiossa v3.539.44 molemmat polut rajaavat /Parent-kulun neljään perittyvään avaimeen, tuotantolaatikot luetaan vain lehdestä, ja eksynyt vanhemman merkintä jää tiedostoon koskemattomaksi, ei poistettuna eikä uudelleenkirjoitettuna
HasPageBox ohitti suorat vanhemman taulukot
HasPageBox palauttaa arvon 0, kun sivulla ei ole pyydettyä tyyppiä olevaa laatikkoa, arvon 1, kun sivulla on oma laatikko (talletettu suoraan tai epäsuoran viittauksen kautta), ja arvon 2, kun MediaBox tai CropBox on peritty esi-isältä. Vanha koodi palautti arvon 2 vain, kun peritty arvo oli epäsuora viittaus, joten peritty suora taulukko palautti arvon 0. Korjaus erottaa viittausten purkamisen taulukkotestistä, ja molemmat esitystavat palauttavat nyt arvon 2. Versiosta v3.539.44 alkaen HasPageBox voi BleedBoxin, TrimBoxin tai ArtBoxin kohdalla palauttaa vain arvon 0 tai 1
Oppi yleistyy pitkälle sivulaatikoiden ulkopuolelle. Kun yksi määritelmän semantiikan palanen saa kirjastossa kaksi toteutuksen sisääntulopistettä, korjaa ne yhdessä ja testaa ne matriisina yhden onnistumispolun tiedoston sijaan. PDFlibPasin regressiojoukko risteyttää kaksi vanhemman laatikon esitystapaa (suora ja epäsuora taulukko) kolmen lehtitilan (poissa, suora taulukko, epäsuora taulukko) ja kolmen kaappausvalinnan (bleed, trim, art) kanssa, mikä antaa 18 skenaariota, ja jokainen tarkistaa kyselyn tuloksen, kaapatut rajat, laillisen MediaBox- ja CropBox-perinnän sekä koskemattoman vanhemman merkinnän
Miten luen tehollisen TrimBoxin Delphissä?
Kutsu GetPageBox(4, Dimension)ia valitulla sivulla. PDFlibPas soveltaa oletusketjun puolestasi, joten tulos on tehollinen TrimBox riippumatta siitä, onko sivulla sellaista. Yhdistä se funktioon HasPageBox, kun sinun tarvitsee tietää, mistä arvo tuli, mitä preflight-raportti yleensä tekee
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 = oma, 2 = peritty
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.
Sekä GetPageBox että SetPageBox toimivat asiakirjan nykyisillä koordinaattiasetuksilla. Esimerkit täällä ajetaan oletuksilla: alkukohta 0 (vasen alakulma, vastaa PDF:n käyttäjätilaa) ja pisteet mittayksikkönä, joten Top-dimensio on yläreuna, mitattuna ylöspäin sivun alareunasta. Kutsun SetOrigin(1) jälkeen dimensiot Top ja Bottom mitataan sen sijaan alaspäin sivun yläreunasta, ja kutsun SetMeasurementUnits(1) jälkeen jokainen arvo palautuu millimetreinä. Leveys ja korkeus eivät riipu alkukohdasta
Jumiin jääneiden tuotantolaatikoiden löytäminen /Pages-solmuilta
Versiosta v3.539.44 alkaen laatikko-API ei enää näe TrimBoxia /Pages-solmulla, mikä on oikein, mutta preflight-työkalu haluaa yleensä raportoida tällaisen tiedoston sen sijaan, että lukee sen hiljaa määritelmän tavalla. Sivupuusolmut ovat tavallisia objekteja, joten matalan tason objekti-API pystyy löytämään ne: kulje objektinumerot arvoon GetMaxObjectNumber asti, lue jokainen funktiolla GetObjectToString ja etsi /Pages-sanakirja, joka kantaa tuotantolaatikkoavainta. Tarkistuksen toinen puoli on sivukohtainen testi, josta PDF/X välittää, ja HasPageBox vastaa siihen nykyään niin kuin PDF/X-validaattori vastaisi, koska vanhemman TrimBox ei enää laske
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. Tuotantolaatikot sivupuusolmuilla: epästandardi ja ohitetaan
for ObjNum := 1 to Lib.GetMaxObjectNumber do
begin
Src := ''; // vapaat numerot eivät palauta tekstiä
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: jokainen sivu tarvitsee oman TrimBoxin tai ArtBoxin
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. Valinnainen korjaus: 6 x 9 tuuman trim 6.25 x 9.25 tuuman medialaatikon sisällä
// (pisteet, vasemman alakulman alkukohta: Left, Top, Width, Height)
if Missing > 0 then
Log.Add(Format('TrimBox written on %d pages',
[Lib.SetPageBoxRange('', 4, 9, 657, 432, 648)]));
end;
Tekstivertailu on pragmaattinen tarkistus, ei jäsentin. Se nojaa siihen, että PDFlibPas serialisoi jokaisen sanakirjamerkinnän avaimeksi, yhdeksi välilyönniksi ja arvoksi, mikä pätee objekteille, jotka luetaan takaisin funktiolla GetObjectToString. Korjausvaihe ansaitsee päätöksen refleksin sijaan: eksynyt vanhemman arvo saattaa hyvinkin olla se, mitä tekijä aikoi, mutta vahvista se työkorttia vasten ennen kuin teet siitä virallisen. SetPageBoxRange tyhjällä välillä soveltaa laatikon jokaiselle sivulle ja palauttaa päivitettyjen sivujen määrän. Kun sivun olemassa oleva laatikko on epäsuora taulukko, jota toinen sivu tai /Pages-solmu saattaa jakaa, SetPageBox antaa kyseiselle sivulle uuden suoran taulukon jaetun objektin uudelleenkirjoittamisen sijaan. BleedBoxin, TrimBoxin tai ArtBoxin asettaminen nostaa myös lukitsemattoman asiakirjan versioon PDF 1.3, joka esitteli kyseiset merkinnät
Sivujen impositointi TrimBoxille CapturePageExilla
CapturePageEx(Page, 3) muuttaa sivun Form XObjectiksi, jonka rajalaatikko on sivun tehollinen TrimBox, ja DrawCapturedPage sijoittaa kyseisen formin toiselle sivulle millä tahansa koolla. Versiosta v3.539.42 alkaen valinta 3 sivulla ilman TrimBoxia antaa sinulle CropBoxin, kuten referenssi kuvaa, MediaBoxin sijaan kaikine slugineen
Kaappauksen kaksi ominaisuutta muovaavat koodia. Kaappaus on tuhoava: kaapattu sivu poistetaan asiakirjasta, eikä asiakirja voi koskaan pudota nollaan sivuun, joten liitä ensimmäinen tulostusarkki ennen kuin kaappaat mitään. Kaappaus toimii myös vain yhden asiakirjan sisällä, joten nosta jokainen syöte yhteen asiakirjaan ensin; artikkelin PDF-lähteiden kokoaminen ja lomittaminen yhdellä ajolla tekniikat pätevät suoraan
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;
// Sivun 1 tehollinen trim-koko (tämä asettelu olettaa yhtenäisen trimin)
Lib.SelectPage(1);
TrimW := Lib.GetPageBox(4, 2);
TrimH := Lib.GetPageBox(4, 3);
// Liitä ja mitoita ensimmäinen arkki; NewPage valitsee uuden sivun
Lib.NewPage;
Lib.SetPageDimensions(2 * TrimW, TrimH);
// Jokainen kaappaus poistaa sivun 1, joten seuraava lähdesivu siirtyy ylös
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;
// Vain arkki on jäljellä: kaksi trimmattua sivua arkilla rinnakkain
Lib.SelectPage(1);
for I := 0 to SourceCount - 1 do
begin
if (I > 0) and (I mod 2 = 0) then
Lib.NewPage; // sama koko kuin nykyinen arkki
// Oletusalkukohta: Top on yläreuna, mitattuna alareunasta
Lib.DrawCapturedPage(Captures[I], (I mod 2) * TrimW, TrimH, TrimW, TrimH);
end;
Lib.SaveToFile(OutFile);
finally
Lib.Free;
end;
end;
Trim-pohjainen kaappaus leikkaa kaiken TrimBoxin ulkopuolisen pois, mikä on juuri se, mitä haluat digitaaliselle vedokselle tai cut-and-stack-asettelulle. Painoarkille, joka trimmataan painamisen jälkeen, kaappaa valinnalla 2, jotta bleed säilyy, ja rivitä solut bleed-leveyden välein. Koska kaappaus poistaa lähdesivut, kirjanmerkit ja linkit, jotka osoittivat niihin, menettävät kohteensa, joten impositoi erilliseen tulostustiedostoon sen sijaan, että muokkaat asiakirjaa, jonka navigaatiota tarvitset yhä; artikkeli sivujen korvaaminen rikkomatta kirjanmerkkejä kattaa sivukirurgian kyseisen puolen
Kun lähteen on pysyttävä ehjänä, ImportPageAsFormXObject(SourceDocumentID, SourcePage, Options) ottaa samat valinta-arvot 0–4 (anna Lib.SelectedDocument nykyiselle asiakirjalle), jättää lähteen sivupuun muuttumattomaksi, normalisoi perityn sivunkiertyman formimatriisiin ja palauttaa kahvan, jonka DrawCapturedPage hyväksyy. CapturePageEx ei kumoa /Rotatea, joten kiertynyt syöte tarvitsee kyseisen vaiheen ensin, ja artikkeli sivunkiertyman tasoittaminen rikkomatta sivulaatikoita näyttää, mitä kullekin laatikolle tapahtuu, kun teet niin. Yksi varoitus syötteille, jotka saattavat kantaa tuotantolaatikoita /Pages-solmuilla: tuontipolku ratkaisee laatikkonsa oman esi-isähaun kautta, erillään kahdesta v3.539.44:ssa tasatusta polusta, joten tarkista HasPageBox(4) lähdesivulla ensin ja anna valinta 1 (CropBox), kun se palauttaa arvon 0. Se pitää tuloksen kiinni määritelmässä, ei siinä, miten tiedosto sattui kirjoitettavan
Sivulaatikon pikamuistio
- Tehollinen CropBox: sivun oma CropBox, muutoin lähin peritty CropBox, muutoin tehollinen MediaBox (ISO 32000-1 §14.11.2)
- Tehollinen BleedBox, TrimBox ja ArtBox: lehtisivun oma merkintä, muutoin tehollinen CropBox
- Vain
Resources,MediaBox,CropBoxjaRotateperiytyvät/Pages-solmuilta (§7.7.3.4, taulukko 30); tuotantolaatikot/Pages-solmuilla ohitetaan 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 ei laatikkoa, 1 sivun oma laatikko (suora tai epäsuora), 2 peritty MediaBox tai CropBox (suora tai epäsuora)CapturePageEx(Page, Options): 0 MediaBox, 1 CropBox MediaBox-varalla, 2–4 BleedBox, TrimBox tai ArtBox CropBox-varalla- Päivitys versioon v3.539.44 tai uudempaan yhdenmukaisten oletusten ja perinnän saamiseksi laatikkokyselyissä ja kaappauksessa
Sivulaatikot ovat paikka, jossa PDF:n hiljaiset oletukset kohtaavat murto-osamillimetreinä mitattuja esipainotoleransseja, ja kirjasto joko soveltaa kyseisiä oletuksia samalla tavalla kaikkialla tai ojentaa sinulle kaksi vastausta yhteen kysymykseen. Koko laatikko-, kaappaus- ja Form XObject-API on dokumentoitu PDFlibPas PDF Library for Delphi -tuotesivulla