HotPDF PDF puslapio pasukimą suvienodina su THotPDF.FlattenLoadedPageRotation: metodas kiekvieno pasukto puslapio turinį apgaubia pagal laikrodžio rodyklę einančiu cm transformavimu, perrašo kiekvieną puslapio rėmelį, kurį puslapis iš tiesų turi, ta pačia kampu pasuka anotacijų geometriją, išvaizdų matricas, atvirus tikslus ir žymėtosios struktūros geometriją, o tada nustato /Rotate į 0. Puslapis peržiūryklėje atrodo identiškai, bet jo koordinačių sistema dabar stati. Tai ima rūpėti akimirką, kai kitas įrankis, spausdinimo RIP arba jūsų paties antspaudavimo kodas ignoruoja /Rotate ir deda daiktus į žalią vartotojo erdvę
Įprastas trigeris yra skaitytuvas arba mobili fiksavimo programėlė, kurie horizontalius puslapius rašo kaip vertikalią media su /Rotate 90. Kiekviena peržiūryklė juos rodo teisingai, tad niekas nepastebi, kol kas nors uždeda puslapio numerį „apačioje dešinėje“ ir jis nusileidžia į šoną palei kairįjį kraštą, arba kol išklotinės žingsnis, skaitantis vien /MediaBox, vertikaliam puslapiui paruošia vertikalų langelį. Suvienodinimas skamba kaip matricos darbas viena eilute. Praktikoje jis liečia penkis puslapio rėmelius, tris rūšis anotacijų geometrijos, dokumento nuorodų tikslus ir struktūros medį, ir kiekvienas iš jų turi savo taisyklę ISO 32000-1
Kuria kryptimi /Rotate pasuka PDF puslapį?
/Rotate puslapį rodymui ir spausdinimui pasuka pagal laikrodžio rodyklę, 90 laipsnių kartotiniais (ISO 32000-1 §7.7.3.3, 30 lentelė). Esant 90 laipsnių media kairysis kraštas tampa viršumi, o viršutinis kraštas – dešiniąja puse, tad į apačią krentančioje įrenginio erdvėje atvaizdavimas yra X = (y - Bottom) * Scale ir Y = (x - Left) * Scale. Esant 270 laipsnių dešinysis kraštas tampa viršumi. /Rotate yra ir vienas iš tik keturių paveldimų puslapio atributų, kartu su /Resources, /MediaBox ir /CropBox (§7.7.3.4), tad puslapio žodynas be savo /Rotate vis tiek gali būti pasuktas /Pages protėvio. THotPDF.GetLoadedPageRotation eina /Parent grandine ir rezultatą suvienodina į 0–359 – tai reikšmė, kurios jums reikia, o ne žali raktas pačiame puslapyje
Kryptį lengva sugadinti taip, kad gedimas išgyvena testavimą, ir ankstesnės HotPDF laidos padarė lygiai tai. Senoji puslapio-į-įrenginį matrica 90 ir 270 kampams sukeisdavo y dedamąsias, o tai duoda atspindį per įstrižainę vietoj pasukimo: matricos orientacija apsiverčia, lyginant su nesuktu atveju. Abu kampai vis tiek „atrodo pasukti“, taškinis vaizdas turi sukeistas plotį ir aukštį, o round-trip iš puslapio į vaizdą ir atgal grąžina pradinį tašką, tad matmenų patikros ir round-trip testai visi praeina. Vienintelė patikima patikra yra tai, kur atsiduria kampinis ženklas, lyginant pikselis po pikselio su atskaitiniu atvaizduotoju. Kadangi peržiūryklės modelis, SIMD atvaizdavimo posistemė ir žymėjimo atvaizdavimas buvo nukopijavę tą pačią matricą, visi jie ištaisyti kartu, o suvienodinimo kodas dabar naudoja tą pačią pagal laikrodžio rodyklę einančią konvenciją kaip atvaizduotojas
Kaip FlattenLoadedPageRotation perrašo puslapį
FlattenLoadedPageRotation(PageRange, Info) apdoroja kiekvieną PageRange puslapį, kurio faktinis pasukimas yra 90, 180 arba 270, ir grąžina suvienodintų puslapių skaičių. Tuščias PageRange reiškia visus puslapius; kitu atveju eilutė naudoja įprastą nuo vieno skaičiuojamą '1-3,7' sintaksę, o už ribų esantis puslapio numeris kelia išimtį, o ne praleidžiamas. Originalūs turinio srautai niekada neperkoduojami. Metodas prieš puslapio /Contents prikiša naują srautą su q 0 -1 1 0 -Bottom Width+Left cm (90 laipsnių atveju), gale prideda srautą su Q, o galiausiai į puslapio žodyną įrašo atvirą /Rotate 0, kad /Pages mazge paveldėta reikšmė negalėtų puslapio pasukti antrą kartą
var
Pdf: THotPDF;
Info: THPDFRotationFlattenInfo;
Flattened: Integer;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('scanned-batch.pdf') > 0 then
begin
// '' = visi puslapiai; 0 laipsnių puslapiai nuskaitomi, bet paliekami ramybėje
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 įrašo verta įrašinėti į žurnalą, o ne išmesti. ScannedPageCount yra diapazono dydis, FlattenedPageCount lygus grąžinamai reikšmei, o trys Transformed... skaitikliai pasako, ar dokumente buvo nuorodų, gairių arba žymėtosios geometrijos, rodančios į pasuktus puslapius. Paketas, kuriame kiekvienas failas praneša nulį tikslų, yra tvarkoje; žymėtas PDF/UA failas, pranešantis nulinę struktūros geometriją, kai tikėjatės paveikslų rėmelių, yra signalas apžiūrėti jį rankomis
Kurius puslapio rėmelius suvienodinimas perrašo ir kokia tvarka?
Suvienodinimas perrašo tik rėmelius, kuriuos puslapis jau turi, ir skaito kiekvieną rėmelį dar prieš parašydamas bet kurį iš jų. Tvarka svarbi dėl numatytosios grandinės: GetLoadedPageBox(PageIndex, pbCropBox, ...) grąžina /MediaBox, kai puslapis neturi /CropBox, o /BleedBox, /TrimBox ir /ArtBox pagal nutylėjimą remiasi CropBox (§14.11.2). Ankstesnė versija vienu metu skaitė, transformuodavo ir rašydavo po vieną rėmelį. Ji pirmiausiai perrašydavo MediaBox, tada skaitydavo „CropBox“, gaudavo jau pasuktą MediaBox, pasukdavo jį antrą kartą ir parašydavo CropBox, kurio puslapis niekada neturėjo – tai horizontalų puslapį nukirpdavo iki kvadrato. Paveldimumo taisyklės skyla taip pat: MediaBox ir CropBox ieškoma /Parent grandine, o Bleed, Trim ir ArtBox skaičiuojami tik tada, kai sėdi pačiame puslapio žodyne, tad atsitiktinė /TrimBox ant /Pages mazgo laikoma nebūtima ir niekada nekopijuojama ant puslapio
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]));
// Teisinga net be /TrimBox rakto: reikšmė grįžta į CropBox, paskui į MediaBox
if Pdf.GetLoadedPageBox(PageIndex, pbTrimBox, L, B, R, T) then
Writeln(Format('TrimBox [%g %g %g %g]', [L, B, R, T]));
// Iš anksto nustatytas Letter; GetLoadedPageVisibleBox nesėkmės atveju palieka išvestis nepaliestas
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;
Paleiskite tą pagalbinę procedūrą prieš suvienodinimą ir po jo, ir skaičiai pasakys patys. 90 laipsnių puslapiui su MediaBox [0 0 612 792] suvienodintas MediaBox tampa [0 0 792 612]; kiekvienas perrašomas rėmelis atvaizduojamas per tą patį pagal laikrodžio rodyklę einantį posūkį, priskiriant originalios MediaBox pradžiai, tad naujas MediaBox visuomet prasideda nuo pradžios taško, o kiti rėmeliai išlaiko savo vietą jame. GetLoadedPageVisibleBox grąžina tai, ką rodo peržiūryklės ir spausdina spausdintuvai – CropBox, apkarpytą MediaBox ir suvienodintą taip, kad Left būtų mažesnis už Right – ir HotPDF atvaizduotojas, SVG eksportas, peržiūryklė bei spausdinimo kelias naudoja tą patį rėmelį. Kai reikia žmogui matomo puslapio dydžio, kvieskite GetLoadedPageVisibleBox, o ne skaitykite /MediaBox
Kodėl anotacijos sulūžta, kai pasuki vien /Rect?
Anotacijos sulūžta, nes išvaizdos srautas nėra piešiamas tiesiai į /Rect. Pagal §12.5.5 peržiūryklė pirmiausiai formos /BBox transformuoja jos /Matrix, tada to rezultato aptinkamąjį rėmelį ištempia ir perkelia į /Rect. Pasukus vien /Rect, 200 × 40 antspaudas suspaudžiamas į 40 × 200 vietą – neskaitytinas ir gulintis ant šono. FlattenLoadedPageRotation todėl puslapio posūkį pagal laikrodžio rodyklę dešinėja sudaugina su kiekviena išvaizdos /Matrix (90 laipsnių atveju [0 -1 1 0 0 0] eilučių-viktorės konvencijoje) per /N, /R ir /D išvaizdas ir kiekvieną jų būseną. Vienas išvaizdos srautas gali būti bendras kelioms anotacijoms ar būsenoms, tad kiekvienas srautas per iškvietimą pasukamas lygiai kartą. Vienintelis atvejis be švaraus atsakymo yra srautas, bendras puslapiams su skirtingais pasukimais; jis seka pirmąjį puslapį, kuris jį pasiekia
Dar dvi taisyklės laiko formos laukus ir lipnius lapelius savo vietose. Valdiklio /MK /R įrašas (§12.5.6.19) yra kampas prieš laikrodžio rodyklę, tad puslapio kampas pagal laikrodžio rodyklę iš jo atimamas, modulis 360; praleiskite tai, ir kita išvaizdos atkūrimo iteracija nupieš lauko tekstą netinkama kryptimi. Anotacijos su NoRotate vėliavėle (bito pozicija 5, reikšmė 16, §12.5.3) pasuktame puslapyje lieka statios ir sukasi aplink savo /Rect viršutinį kairįjį kampą, tad suvienodinimas išlaiko jų plotį, aukštį ir statų pavidalą ir tik tą kampą perkelia ten, kur jį padeda posūkis. Už anotacijų ribų metodas taip pat pasuka /QuadPoints, /Vertices, /L ir /InkList, perrašo atvirus tikslus, įvardijančius puslapį (/XYZ taškus, /FitR stačiakampius, o /FitH / /FitV sukeistus ties 90 ir 270 laipsnių, §12.3.2.2), ir transformuoja žymėtąją geometriją, pavyzdžiui, atributų /BBox įrašus struktūros elementams, kurių /Pg yra tas puslapis
Ko suvienodinimas nedengia?
Suvienodinimas yra geometrinis vieno puslapio savų objektų perrašymas, ir kelios situacijos iš jo iškrenta tyliai, o ne garsiai
- Puslapiai, kurių faktinis pasukimas jau 0, arba kurių MediaBox dingęs arba turi nulinį plotį arba aukštį, praleidžiami be klaidos; grąžinamą reikšmę palyginkite su puslapių, kurių tikėtasi pakeisti, skaičiumi
- Formos XObjects, nurodyti iš puslapio išteklių, savo
/BBoxformos erdvėje palieka sau, nes išoriniscmjuos jau pasuka; struktūros medžio skenavimas seka tik/Kir/A, tad antrą kartą niekada neužbėga į puslapio išteklius ar anotacijas - Tikslai randami nuskaitant kiekvieną netiesioginį objektą po kartą kiekvienam suvienodintam puslapiui, tad didelis dokumentas su šimtais pasuktų puslapių už tą apėjimą sumoka po kartą kiekvienam
- HotPDF puslapių atvaizduotojas anotacijų nededo, tad pasuktų antspaudų vizualinei patikrai pirmiausiai prireikia
FlattenLoadedAnnotations
// Išvaizdas įkepkite į turinį, kad atvaizduotojas jas parodytų,
// tada atvaizduokite 1 puslapį prieš ir po jo /Rotate pašalinimo
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));
// Čia palyginkite kampinio ženklo pikselius, o ne vien matmenis
finally
After.Free;
end;
finally
Before.Free;
end;
Dėl gilesnio konteksto šios istorijos anotacijų pusė tęsiasi anotacijų išvaizdų sintezėje prieš suvienodinimą, atvaizduotojas už prieš-po lyginimo aprašytas pakrauto PDF puslapio atvaizdavime į taškinį vaizdą, o juodinimas ir N-up suklijavimas pakrautuose PDF rodo tą pačią turinio srauto priklijavimo techniką, kuria remiasi pasukimo priešdėlis ir galūnė. HotPDF, įskaitant FlattenLoadedPageRotation ir puslapių rėmelių skaitytuvus, prieinamas Delphi ir C++Builder HotPDF Delphi PDF komponento puslapyje