HotPDF izravnava rotaciju PDF stranice s THotPDF.FlattenLoadedPageRotation: metoda umota sadržaj svake rotirane stranice u cm transformaciju po kazaljci, prepravi svaku page kutiju koju stranica stvarno ima, okrene geometriju anotacija, appearance matrice, izričite destinacije i geometriju tagirane strukture za isti kut, pa zatim postavi /Rotate na 0. Stranica u pregledniku izgleda identično, ali je njezin koordinatni sustav sada uspravan. To postaje bitno u trenutku kad nizvodni alat, print RIP ili vaš vlastiti kod za pečate ignorira /Rotate i stvari postavlja u sirovi user space
Tipičan je okidač skener ili mobilna capture aplikacija koja pejzažne stranice zapisuje kao portret medium s /Rotate 90. Svaki preglednik ih prikazuje ispravno, pa nitko ne primijeti dok netko ne ispeča broj stranice „dolje desno" i on ne sleti bočno uz lijevi rub, ili dok korak za impoziciju koji čita samo /MediaBox ne posloži portret slot za pejzažnu stranicu. Izravnavanje zvuči kao matični posao od jednog retka. U praksi dira pet page kutija, tri vrste geometrije anotacija, linkove mete dokumenta i strukturno stablo, a svako od toga ima svoje pravilo u ISO 32000-1
Na koju stranu /Rotate okreće PDF stranicu?
/Rotate okreće stranicu po kazaljci radi prikaza i ispisa, u umnošcima od 90 stupnjeva (ISO 32000-1 §7.7.3.3, Tablica 30). Na 90 stupnjeva lijevi rub medija postane gore, a gornji rub postane desna strana, pa u y-down device spaceu mapiranje je X = (y - Bottom) * Scale i Y = (x - Left) * Scale. Na 270 stupnjeva desni rub postane gore. /Rotate je i jedno od svega četiriju nasljedivih svojstava stranice, uz /Resources, /MediaBox i /CropBox (§7.7.3.4), pa rječnik stranice bez vlastitog /Rotate može i dalje okrenuti /Pages predak. THotPDF.GetLoadedPageRotation prošeta /Parent lanac i normalizira rezultat u 0–359, a to je vrijednost koju želite, ne sirovi ključ na stranici
Smjer je lako pokvariti na način koji preživi testiranje, i stariji HotPDF buildovi točno to i napravili. Stara page-to-device matrica zamijenila je y komponente za 90 i 270, što proizvodi zrcaljenje preko dijagonale umjesto rotacije: orijentacija matrice okrene se u odnosu na nerotirani slučaj. Oba kuta i dalje „izgledaju rotirano", bitmapa ima zamijenjene širinu i visinu, i round trip od stranice do prikaza i natrag vraća početnu točku, pa prolaze sve provjere dimenzija i round-trip testovi. Jedina pouzdana provjera jest gdje završi marker u uglu, uspoređen pixel po pixel s referentnim rendererom. Pošto su viewer model, SIMD render backend i mapiranje highlightova kopirali istu matricu, svi su ispravljeni zajedno, i kod izravnavanja sada koristi istu konvenciju po kazaljci kao renderer
Kako FlattenLoadedPageRotation prepravlja stranicu
FlattenLoadedPageRotation(PageRange, Info) obrađuje svaku stranicu u PageRange čija je efektivna rotacija 90, 180 ili 270, i vraća broj stranica koje je izravnao. Prazan PageRange znači sve stranice; inače string koristi uobičajenu sintaksu od jedan baziranu '1-3,7', a broj stranice izvan raspona baca iznimku umjesto da se preskoči. Izvorni se content streamovi nikad ne reenkodiraju. Metoda doda novi stream s q 0 -1 1 0 -Bottom Width+Left cm (za 90 stupnjeva) ispred /Contents stranice, doda stream s Q na kraj, i napokon upiše izričit /Rotate 0 u rječnik stranice da naslijeđena vrijednost na /Pages čvoru ne može stranicu okrenuti drugi put
var
Pdf: THotPDF;
Info: THPDFRotationFlattenInfo;
Flattened: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('scanned-batch.pdf') > 0 then
begin
// '' = sve stranice; stranice na 0 stupnjeva se skeniraju ali se ostave na 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;
THPDFRotationFlattenInfo zapis vrijedi logirati umjesto baciti. ScannedPageCount je veličina raspona, FlattenedPageCount jednak je povratnoj vrijednosti, a tri brojača Transformed... govore je li dokument imao linkove, bookmarkse ili tagiranu geometriju uperenu u okrenute stranice. Serija u kojoj svaka datoteka javlja nula destinacija u redu je; tagirana PDF/UA datoteka koja javlja nulu strukturne geometrije dok ste očekivali bounding kutije slika signal je da je pregledate ručno
Koje page kutije izravnavanje prepravlja i kojim redom?
Izravnavanje prepravlja samo kutije koje stranica već ima, i pročita svaku kutiju prije nego išta zapiše. Redoslijed je bitan zbog zadanog lanca: GetLoadedPageBox(PageIndex, pbCropBox, ...) vraća /MediaBox kad stranica nema /CropBox, a /BleedBox, /TrimBox i /ArtBox zadano su CropBox (§14.11.2). Ranija je verzija čitala, transformirala i zapisivala po jednu kutiju istovremeno. Prepravila je MediaBox prvi, pa pročitala „CropBox", dobila natrag već okrenuti MediaBox, okrenula ga drugi put i zapisala CropBox koji stranica nikad nije imala, čime je pejzažnu stranicu izrezala na kvadrat. Pravila nasljeđivanja dijele se isto: MediaBox i CropBox traže se duž /Parent lanca, dok Bleed, Trim i ArtBox računaju samo ako sjede na samom rječniku stranice, pa zalutali /TrimBox na /Pages čvoru tretira se kao nepostojeći i nikad se ne kopira na stranicu
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]));
// Istina čak i bez /TrimBox ključa: vrijednost pada natrag na CropBox, pa MediaBox
if Pdf.GetLoadedPageBox(PageIndex, pbTrimBox, L, B, R, T) then
Writeln(Format('TrimBox [%g %g %g %g]', [L, B, R, T]));
// Pretpostavljeni Letter; GetLoadedPageVisibleBox ostavlja izlaze nedirnutima na padu
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;
Pokrenite tog helpera prije i poslije izravnavanja i brojevi sami objasne sebe. Za stranicu od 90 stupnjeva s MediaBoxom [0 0 612 792], izravnavani MediaBox postaje [0 0 792 612]; svaka prepravljena kutija mapira se kroz isti okret po kazaljci, relativno u odnosu na ishodište izvornog MediaBoxa, pa novi MediaBox uvijek kreće od ishodišta, a ostale kutije zadržavaju svoj položaj unutar njega. GetLoadedPageVisibleBox vraća ono što preglednici prikazuju i pisači ispisuju, CropBox izrezan na MediaBox i normaliziran tako da je Left manji od Right, i HotPDF-ov renderer, SVG izvoz, viewer i print put koriste tu istu kutiju. Kad trebate veličinu stranice kakvu vidi čovjek, zovite GetLoadedPageVisibleBox umjesto da čitate /MediaBox
Zašto se anotacije slome kad okrenete samo /Rect?
Anotacije se slome jer se appearance stream ne crta ravno u /Rect. Pod §12.5.5 preglednik najprije transformira /BBox forme njegovom /Matrixom, a onda bounding kutiju tog rezultata skalira i prevede u /Rect. Okrenite samo /Rect pa će se pečat 200 × 40 utisnuti u slot 40 × 200, nečitak i na boku. FlattenLoadedPageRotation zato umnoži s desna okret stranice po kazaljci na svaku appearance /Matrix (za 90 stupnjeva, [0 -1 1 0 0 0] u row-vector konvenciji), kroz appearance /N, /R i /D i svako stanje unutar njih. Jedan appearance stream može dijeliti više anotacija ili stanja, pa se svaki stream okreće točno jednom po pozivu. Slučaj bez čistog odgovora jest stream dijeljen preko stranica s različitim rotacijama; slijedi prvu stranicu koja ga dosegne
Još dva pravila drže polja forme i ljepljive bilješke na mjestu. Unos /MK /R widgeta (§12.5.6.19) kut je obrnut od kazaljke, pa se kut stranice po kazaljci oduzme od njega, modulo 360; preskočite to i sljedeća regeneracija appearancea nacrta tekst polja u krivom smjeru. Anotacije s NoRotate flagom (bitna pozicija 5, vrijednost 16, §12.5.3) ostaju uspravne na rotiranoj stranici i okreću se oko gornjeg lijevog kuta svojeg /Recta, pa izravnavanje zadržava njihovu širinu, visinu i uspravni izgled i samo premjesti taj kut tamo gdje ga okret smjesti. Iza anotacija, metoda također okreće /QuadPoints, /Vertices, /L i /InkList, prepravlja izričite destinacije koje imenuju stranicu (točke /XYZ, pravokutnike /FitR, te /FitH / /FitV zamijenjene na 90 i 270 stupnjeva, §12.3.2.2), i transformira tagiranu geometriju poput unosa /BBox atributa za strukturne elemente čiji je /Pg ta stranica
Što izravnavanje ne pokriva?
Izravnavanje je geometrijsko prepravljanje vlastitih objekata jedne stranice, i nekoliko situacija pada izvan njega tiho, a ne glasno
- Stranice čija je efektivna rotacija već 0, ili čiji MediaBox nedostaje ili ima nultu širinu ili visinu, preskaču se bez pogreške; usporedite povratnu vrijednost s brojem stranica za koje ste očekivali da će se promijeniti
- Form XObjects referencirani iz resursa stranice čuvaju vlastiti
/BBoxu form spaceu, jer ih vanjskicmveć okreće; skeniranje strukturnog stabla slijedi samo/Ki/Apa nikad ne kroči u resurse stranice ni u anotacije drugi put - Destinacije se pronalaze skeniranjem svakog indirektnog objekta jednom po izravnavanoj stranici, pa veliki dokument sa stotinama rotiranih stranica plaća taj obilazak za svaku
- HotPDF-ov page renderer ne crta anotacije, pa vizualna provjera okrenutih pečata treba najprije
FlattenLoadedAnnotations
// Upeciraj appearancee u sadržaj da ih renderer može prikazati,
// pa renderiraj stranicu 1 prije i poslije uklanjanja njenog /Rotate
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));
// Usporedite pixel markera u uglu ovdje, ne samo dimenzije
finally
After.Free;
end;
finally
Before.Free;
end;
Za dublju pozadinu, strana anotacija ove priče nastavlja se u sintezi appearancea anotacija prije njihova izravnavanja, renderer iza usporedbe prije-poslije pokriva renderiranje učitane PDF stranice u bitmapu, a redakcija i N-up šivanje na učitanim PDF-ovima pokazuje istu tehniku nadodavanja content streamu na koju se oslanjaju prefiks i sufiks rotacije. HotPDF, uključivo FlattenLoadedPageRotation i čitače page kutija, dostupan je za Delphi i C++Builder na stranici HotPDF Delphi PDF komponente