HotPDF izravna zasuk strani PDF s THotPDF.FlattenLoadedPageRotation: metoda ovije vsebino vsake zasukane strani v urno transformacijo cm, prepiše vsak okvir strani, ki ga stran dejansko ima, zavrti geometrijo opomb, matrike videza, eksplicitne cilje in označeno geometrijo strukture za istim kotom in nato nastavi /Rotate na 0. Stran v pregledovalniku izgleda identično, njen koordinatni sistem pa je zdaj pokončen. To je pomembno v trenutku, ko nek kasnejši orod, tiskalni RIP ali vaša lastna koda za žige spregleda /Rotate in postavlja stvari v surovi uporabniški prostor
Tipični sprožilec je skener ali mobilna aplikacija za zajem, ki ležeče strani zapiše kot pokončni medij z /Rotate 90. Vsak pregledovalnik jih prikaže prav, zato nihče ne opazi ničesar, dokler nekdo ne žige številko strani pri »desnem spodnjem kotu« in ta pristane na boku ob levem robu, ali pa korak impozicije, ki bere samo /MediaBox, ne razporedi pokončne reže za ležečo stran. Izravnavanje se sliši kot matrično delo za eno vrstico. V praksi se dotakne petih okvirjev strani, treh vrst geometrije opomb, ciljev povezav dokumenta in drevesa strukture, vsak od njih pa ima v ISO 32000-1 svoje pravilo
V katero smer /Rotate zavrti stran PDF?
/Rotate zavrti stran za prikaz in tiskanje v smeri urinega kazalca, v večkratnikih 90 stopinj (ISO 32000-1 §7.7.3.3, tabela 30). Pri 90 stopinjah levi rob medija postane zgornji, zgornji rob pa desna stran, zato je v y-navzdol napravnem prostoru preslikava X = (y - Bottom) * Scale in Y = (x - Left) * Scale. Pri 270 stopinjah desni rob postane zgornji. /Rotate je tudi eden od le štirih podedljivih atributov strani, skupaj z /Resources, /MediaBox in /CropBox (§7.7.3.4), zato lahko slovar strani brez lastnega /Rotate vseeno zavrti prednik /Pages. THotPDF.GetLoadedPageRotation prehodi verigo /Parent in rezultat normalizira v 0–359, kar je vrednost, ki jo želite, ne surovi ključ na strani
Smer je lahko narobe dojeti na način, ki preživi testiranje, in zgodnejše verzije HotPDF so storile točno to. Stara matrika od strani do naprave je zamenjala y-komponente za 90 in 270, kar da odsev čez diagonalo namesto zasuka: usmerjenost matrike se obrne glede na nezasukani primer. Oba kota še vedno »izgledata zasukana«, bitna slika ima zamenjani širini in višini, povratna pot od strani do pogleda in nazaj vrne izhodiščno točko, zato preizkusi dimenzij in povratnih poti vsi uspejo. Edini zanesljiv preizkus je, kjer pristne oznaka kota, primerjana piksel za pikselom z referenčnim izrisovalnikom. Ker so si model pregledovalnika, SIMD izrisovalna zadnja plast in preslikava poudarkov kopirali isto matriko, so bili vsi popravljeni skupaj, koda izravnavanja pa zdaj uporablja isto urno konvencijo kot izrisovalnik
Kako FlattenLoadedPageRotation prepiše stran
FlattenLoadedPageRotation(PageRange, Info) obdela vsako stran v PageRange, katere dejanski zasuk je 90, 180 ali 270, in vrne število strani, ki jih je izravnila. Prazen PageRange pomeni vse strani; sicer niz uporablja običajno eno-osnovno skladnjo '1-3,7', številka strani izven obsega pa sproži izjemo, namesto da bi bila preskočena. Izvirni tokovi vsebine se nikoli ne znova kodirajo. Metoda pred /Contents strani pripne nov tok z q 0 -1 1 0 -Bottom Width+Left cm (za 90 stopinj), na konec pripne tok z Q in na koncu zapiše eksplicitni /Rotate 0 v slovar strani, tako da podedovana vrednost na vozlišču /Pages ne more zavrtiti strani še enkrat
var
Pdf: THotPDF;
Info: THPDFRotationFlattenInfo;
Flattened: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('scanned-batch.pdf') > 0 then
begin
// '' = vse strani; strani na 0 stopinj se preiskajo, a ostanejo pri miru
Flattened := Pdf.FlattenLoadedPageRotation('', Info);
Writeln(Format('Scanned %d, flattened %d pages', [Info.ScannedPageCount, Info.FlattenedPageCount]));
Writeln(Format('Turned %d annotations, %d destinations, %d tagged geometry entries',
[Info.TransformedAnnotationCount, Info.TransformedDestinationCount,
Info.TransformedStructureGeometryCount]));
if Flattened > 0 then
Pdf.SaveLoadedDocument('scanned-batch-upright.pdf');
end;
finally
Pdf.Free;
end;
end;
Zapis THPDFRotationFlattenInfo je vreden beleženja, ne zavrženja. ScannedPageCount je velikost obsega, FlattenedPageCount je enak vrnjeni vrednosti, trije števci Transformed... pa vam povedo, ali je dokument imel povezave, zaznamke ali označeno geometrijo, ki kaže na zavrtene strani. Paket, kjer vsaka datoteka poroča nič ciljev, je v redu; označena datoteka PDF/UA, ki poroča nič strukturne geometrije, ko ste pričakovali ograde slike, pa je znak, da jo pregledate z roko
Katerih okvirjev strani se izravnavanje dotakne in v kakšnem vrstnem redu?
Izravnavanje prepisuje samo okvirje, ki jih stran že ima, in prebere vsak okvir, preden zapiše katerega koli. Vrstni red je pomemben zaradi privzetne verige: GetLoadedPageBox(PageIndex, pbCropBox, ...) vrne /MediaBox, kadar stran nima /CropBox, /BleedBox, /TrimBox in /ArtBox pa privzamejo CropBox (§14.11.2). Zgodnejša verzija je brala, transformirala in zapisovala en okvir naenkrat. Najprej je prepisala MediaBox, nato prebrala »CropBox«, dobila nazaj že zavrti MediaBox, zavrtela ga še enkrat in zapisala CropBox, ki ga stran nikoli ni imela, kar je ležečo stran obrezalo do kvadrata. Pravila podedovanja se delijo enako: MediaBox in CropBox se iščeta po verigi /Parent, Bleed, Trim in ArtBox pa štejejo le, če sedijo na samem slovarju strani, zato odcepljen /TrimBox na vozlišču /Pages velja za odsotnega in se nikoli ne prekopira na stran
procedure DumpPageGeometry(Pdf: THotPDF; PageIndex: Integer);
var
L, B, R, T: Single;
begin
Writeln('Effective /Rotate: ', Pdf.GetLoadedPageRotation(PageIndex));
if Pdf.GetLoadedPageBox(PageIndex, pbMediaBox, L, B, R, T) then
Writeln(Format('MediaBox [%g %g %g %g]', [L, B, R, T]));
// True tudi brez ključa /TrimBox: vrednost pade nazaj na CropBox, nato MediaBox
if Pdf.GetLoadedPageBox(PageIndex, pbTrimBox, L, B, R, T) then
Writeln(Format('TrimBox [%g %g %g %g]', [L, B, R, T]));
// Prednastavljen Letter; GetLoadedPageVisibleBox pusti izhode nedotaknjene ob odpovedi
L := 0; B := 0; R := 612; T := 792;
Pdf.GetLoadedPageVisibleBox(PageIndex, L, B, R, T);
Writeln(Format('Visible [%g %g %g %g]', [L, B, R, T]));
end;
Pomožnik poženite pred izravnavanjem in po njem, številke pa se razložijo same. Za stran na 90 stopinj z MediaBox [0 0 612 792] postane izravnani MediaBox [0 0 792 612]; vsak prepisani okvir je preslikan skozi isti urni zasuk, relativno na izhodišče izvirnega MediaBox, zato novi MediaBox vedno začne na izhodišču in ostali okvirji obdržijo svoj položaj znotraj njega. GetLoadedPageVisibleBox vrne to, kar prikažejo pregledovalniki in natisnejo tiskalniki, CropBox obrezan na MediaBox in normaliziran tako, da je Left manjši od Right, izrisovalnik, izvoz SVG, pregledovalnik in tiskalna pot HotPDF pa vsi uporabljajo ta isti okvir. Ko potrebujete velikost strani, ki jo vidi človek, pokličite GetLoadedPageVisibleBox, namesto da bi brali /MediaBox
Zakaj se opome pokvarijo, če zavrtite samo /Rect?
Opome se pokvarijo, ker tok videza ni risan neposredno v /Rect. Po §12.5.5 pregledovalnik najprej preoblikuje /BBox obrazca z njegovo /Matrix, nato pa ograde tega rezultata skalira in prevedi v /Rect. Zavrtite samo /Rect in žig 200 × 40 bo stisnjen v režo 40 × 200, neberljiv in na boku. FlattenLoadedPageRotation torej z desne pomnoži urni zasuk strani na vsak /Matrix videza (za 90 stopinj [0 -1 1 0 0 0] v konvenciji vrstičnih vektorjev), čez videze /N, /R in /D ter vsako stanje znotraj njih. En tok videza si lahko deli več opomb ali stanj, zato se vsak tok zavrti točno enkrat na klic. Primer brez čistega odgovora je tok, ki si ga deli več strani z različnimi zasuki; sledi prvi strani, ki do njega pride
Še dve pravili držita polja obrazcev in lepljive listke na mestu. Vnos /MK /R gradnika (§12.5.6.19) je kot v nasprotni smeri urinega kazalca, zato se urni kot strani od njega odšteje, po modulu 360; izpustite to in naslednja ponovna izdelava videza nariše tekst polja v napačno smer. Opome z zastavico NoRotate (bitni položaj 5, vrednost 16, §12.5.3) ostanejo pokončne na zasukani strani in se vrtijo okoli zgornjega levega kota svojega /Rect, zato izravnavanje obdrži njihovo širino, višino in pokončni videz ter samo premakne ta kot tja, kamor ga spravi zasuk. Poleg opomb metoda zavrti tudi /QuadPoints, /Vertices, /L in /InkList, prepiše eksplicitne cilje, ki poimenujejo stran (točke /XYZ, pravokotnike /FitR ter /FitH in /FitV zamenjana pri 90 in 270 stopinjah, §12.3.2.2), in preoblikuje označeno geometrijo, kot so vnosi /BBox atributov za strukturne elemente, katerih /Pg je stran
Kaj izravnavanje ne pokrije?
Izravnavanje je geometrijski prepis lastnih objektov ene strani, več situacij pa pade izven nje tiho, ne glasno
- Strani, katerih dejanski zasuk je že 0 ali katerih MediaBox manjka ali ima ničelno širino ali višino, se preskočijo brez napake; primerjajte vrnjeno vrednost s številom strani, za katere ste pričakovali spremembo
- Form XObjects, navedeni iz virov strani, obdržijo svoj
/BBoxv prostoru obrazca, ker ju zunanjicmže zavrti; preiskava drevesa strukture sledi samo/Kin/A, zato nikoli ne vstopi v vire strani ali opome drugič - Cilji se najdejo s preiskavo vsakega posrednega objekta enkrat na izravnano stran, zato velik dokument s stotinami zasukanih strani plača ta sprehod za vsako od njih
- Izrisovalnik strani HotPDF ne riše opomb, zato vizualni preizkus zavrtih žigov najprej potrebuje
FlattenLoadedAnnotations
// Zapečite videze v vsebino, da jih izrisovalnik zna prikazati,
// nato izrišite stran 1 pred odstranitvijo njenega /Rotate in po njej
Pdf.FlattenLoadedAnnotations('1');
Before := Pdf.RenderLoadedPageToBitmap(0, 96);
try
Pdf.FlattenLoadedPageRotation('1', Info);
After := Pdf.RenderLoadedPageToBitmap(0, 96);
try
Assert((Before.Width = After.Width) and (Before.Height = After.Height));
// Tukaj primerjajte piksle oznake kota, ne samo dimenzij
finally
After.Free;
end;
finally
Before.Free;
end;
Za globlje ozadje se strana opomb te zgodbe nadaljuje v izdelavi videzov opomb, preden jih izravnamo, izrisovalnik za primerjavo pred in po je pokrit v izrisu naložene strani PDF v bitno sliko, izrez in N-up spajanje na naloženih PDF pa prikazuje isto tehniko pripetja tokov vsebine, na katero se zanašata predpona in pripona zasuka. HotPDF, vključno s FlattenLoadedPageRotation in bralci okvirjev strani, je na voljo za Delphi in C++Builder na strani komponente HotPDF Delphi PDF