Ant jūsų stalo nusileidžia užduotis: paimti jau sugeneruotų išrašų paketą, užtušuoti sąskaitų numerius ir sudėti po du puslapius į vieną lapą, kad būtų taupomas popierius. Abi šios užduoties dalys yra darbo su jūsų nekurtu PDF turinio srautais chirurgija, todėl čia nėra draugiškos puslapio drobės piešimui ir nėra šriftų valdiklio, kuriuo būtų galima remtis. Jūs tiesiogiai redaguojate įkelto dokumento objektų grafiką, pridėdami neapdorotus braižymo operatorius į puslapį, kurį išdėliojo kita priemonė. HotPDF tam pateikia lygiai du įėjimo taškus, ir pavojingesnis iš jų yra tas, kuris atrodo nekaltas
HotPDF yra vietinis VCL PDF komponentas, skirtas Delphi ir C++Builder. Jo devintojo etapo įkelto dokumento API pridėjo pirmuosius metodus, kurie sukuria visiškai naują turinį puslapyje, atidarytame iš disko, o ne sukurtame nuo nulio. Čia kalbama apie du iš jų: RedactLoadedRect, kuris nudažo nepermatomą stačiakampį virš srities, ir StitchLoadedPage, kuris pakeičia vieno puslapio mastelį ir nupiešia jį ant kito. Abu veikia rašydami ISO 32000-1 §8.5 turinio srauto operatorius į puslapio /Contents srautą. Suprasti, ką tie operatoriai daro, ir ne mažiau svarbu ko jie nedaro, yra skirtumas tarp veikiančio įrankio ir duomenų nutekėjimo
Operatorių pridėjimas prie įkelto puslapio
Kai puslapį kuriate įprastu HotPDF API, komponentas pats valdo turinio srautą ir serializuoja jūsų TextOut bei vektorinius kvietimus. Įkeltas puslapis kitoks: jo /Contents jau yra egzistuojantis srauto objektas, galbūt bendrinamas, galbūt turinio masyvo dalis, ir į jį reikia įsipjauti nesugadinant to, kas jau ten yra. Devintasis etapas pridėjo tris mažus pagalbinius metodus, kurie tai padaro saugiai. NewIndirectStream paskiria naują netiesioginį THPDFStreamObject su tuščiu buferiu ir /Length 0 įrašu; ResolveLoadedStream nuseka netiesioginę nuorodą iki pagrindinio srauto; o AppendLoadedStream įrašo žalius baitus srauto gale ir perrašo /Length, kad išsaugomas objektas liktų taisyklingos formos
Abu viešieji metodai laikosi to paties modelio. Suraskite puslapio /Contents, išspręskite jį iki srauto, o jei tinkamo srauto nėra, sukurkite jį ir prijunkite. Tada pridėkite operatorius. Kadangi nauji baitai atsiduria srauto pabaigoje, tapytojo modelis garantuoja, kad jie bus atvaizduoti virš visko, ką nupiešė pradinis išdėstymas. Ši eiliškumo taisyklė ir yra visas redagavimo stačiakampio veikimo mechanizmas, taip pat priežastis, kodėl tas stačiakampis nėra tai, ką dauguma žmonių įsivaizduoja
RedactLoadedRect: nepermatomas uždangalas, o ne ištrynimas
RedactLoadedRect priima nuliniu pagrindu skaičiuojamą puslapio indeksą, keturias naudotojo erdvės koordinates ir tris spalvos komponentus 0-1 intervale:
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('statement.pdf') > 0 then
begin
// Cover the account-number band on page 1 with solid black.
// Coordinates are PDF user space: origin bottom-left, points.
Pdf.RedactLoadedRect(0, 56, 690, 320, 706, 0, 0, 0);
Pdf.SaveLoadedDocument('statement-covered.pdf');
end;
finally
Pdf.Free;
end;
end;
Viduje metodas į turinio srautą įrašo tris operatorius: užpildo spalvos nustatymą DeviceRGB erdvėje (r g b rg), stačiakampio kelią (x y w h re) ir užpildą (f). Plotis ir aukštis apskaičiuojami kaip X2 - X1 ir Y2 - Y1, todėl jūs perduodate du priešingus kampus, o metodas pats apskaičiuoja apimtį. Perduokite 0, 0, 0 ir gausite juodą juostą; perduokite 1, 1, 1 ir gausite baltą, derančią su baltu puslapiu. Koordinatės priklauso pačio įkelto puslapio naudotojo erdvei, tai reiškia, kad pradžia yra apatiniame kairiajame kampe, o vienetai yra taškai; tai taip pat reiškia, kad norint ką nors tiksliai padėti jums reikia puslapio /MediaBox, o jį pateikia GetLoadedPageBox su pbMediaBox
Perskaitykite tai du kartus: užpildytas stačiakampis tik vizualiai uždengia turinį, bet jo nepašalina. Po stačiakampiu esantis tekstas, vaizdas ar vektorinis piešinys vis dar yra PDF faile, vis dar objektų grafe, vis dar ištraukiamas bet kam, kas nukopijuoja puslapį, paleidžia teksto ištraukiklį arba paprasčiausiai pašalina jūsų stačiakampį iš turinio srauto. Tai vizualinis maskavimas, o ne redagavimas teisine ar saugumo prasme. Jei slepiate tikrai jautrius duomenis - sąskaitų numerius, medicininius įrašus, tapatybes ar bet ką reguliuojamą - uždengti juos juodu stačiakampiu ir išsiųsti failą reiškia uždelstą duomenų nutekėjimą. Tikras redagavimas reikalauja ištrinti pagrindinius turinio objektus, o ne juos uždažyti
Metodo pavadinime yra žodis "Redact", ir tai naudinga užuomina apie tai, kaip rezultatas bus neteisingai suprastas, o ne pažadas apie tai, kas ištrinamas. Pats įgyvendinimas čia sąžiningas: komentare jis save vadina "vizualinio redagavimo primityvu" ir pažymi, kad turinį šalinančiam redagavimui reikia turinio srauto interpretatoriaus, kuris pereitų ir perrašytų esamus operatorius. HotPDF įkelto dokumento kelias to čia nedaro. Todėl saugi taisyklė siaura: naudokite RedactLoadedRect nejautriam kosmetiniam maskavimui - juodraščio vandens ženklui paslėpti, sričiai uždengti prieš ekrano nuotrauką, pasenusiam logotipui uždengti vidiniame makete. Tą akimirką, kai po dėže esantis turinys taptų problema jam nutekėjus, šis metodas yra netinkamas įrankis, o teisingas sprendimas yra sugeneruoti dokumentą iš naujo be tų duomenų arba naudoti tikrą turinio pašalinimo procesą
StitchLoadedPage: keisti mastelį, perkelti, piešti
N-up išdėstymas yra draugiškesnė problema, nes čia niekas neslepiama, tik perrikiuojama. StitchLoadedPage priima tikslinio puslapio indeksą, šaltinio puslapio indeksą, X/Y poslinkį ir mastelio koeficientą, ir nupiešia šaltinio puslapį tiksliniame nurodytoje vietoje bei dydžiu:
// Overlay page 2 (index 1) onto page 1 (index 0),
// scaled to 70% and nudged up-right.
Pdf.StitchLoadedPage(0, 1, 40, 380, 0.7);
// Convenience 2-up: source page on the right half of the target.
Pdf.StitchLoadedPageSideBySide(0, 1);
Operatorių eilutė, kurią metodas prideda, yra standartinė transformavimo ir piešimo seka: q grafinei būsenai išsaugoti, cm matrica su masteliu įstrižainėje ir poslinkiu perkėlimo langeliuose, /StitchSrc Do išoriniam objektui iškviesti ir Q būsenai atkurti. q/Q pora svarbi: ji izoliuoja transformaciją, kad prisiūtas puslapis savo koordinačių sistemos nenutekintų į tai, kas bus pridėta vėliau. Metodas taip pat apsaugo nuo akivaizdžių klaidų - indeksų už intervalo ribų, atvejo kai tikslinis puslapis lygus šaltiniui, neigiamo ar nulinio mastelio (jis sugriežtinamas iki 1.0) - ir tyliai išeina vietoj klaidos kėlimo, todėl tikrinkite įvestis, nes tylus no-op atrodo lygiai taip pat kaip sėkmė
StitchLoadedPageSideBySide yra plona patogumo uždanga virš bendrojo metodo. Jis nuskaito tikslinio puslapio media-box plotį, padalija jį pusiau ir iškviečia StitchLoadedPage su tuo pusiniu pločiu kaip X poslinkiu ir fiksuotu 0.5 masteliu, padėdamas šaltinį dešinėje pusėje. Tas užkoduotas 0.5 daro prielaidą, kad šaltinio ir tikslinio puslapių plotis sutampa; jei taip nėra, šaltinis neužpildys savo pusės švariai, ir tuomet norėsite bendrojo StitchLoadedPage su masteliu, kurį apskaičiuosite patys iš abiejų media-box reikšmių
Supaprastinta XObject strategija ir jos ISO kompromisas
Štai vieta, kur įgyvendinimas pasirenka sąmoningą trumpinį, apie kurį privalote žinoti prieš pasitikėdami išvestimi įvairiose peržiūros programose. Teisingas N-up išdėstymas šaltinio puslapio turinį supakuoja į Form XObject - savarankišką piešiamą objektą, kuriam ISO 32000-1 §8.10.1 reikalauja /Type /XObject, /Subtype /Form ir nuosavo /BBox apkirpimo langelio. HotPDF devintos versijos stitch to apvalkalo nekonstruoja. Vietoj to jis užregistruoja patį puslapio žodyną tiesiogiai po tikslinio puslapio /Resources /XObject vardu StitchSrc ir tada jį piešia su Do. Puslapio žodynas ir Form XObject dalijasi pakankamai turinio modelio - abu nurodo turinio srautą ir resursų žodyną - kad daugelis skaitytuvų rezultatą vis dėlto atvaizduos
Tačiau tai nėra specifikaciją atitinkantis Form XObject. Jam trūksta /Subtype /Form žymens ir nuosavo /BBox, o tai reiškia, kad griežtas vartotojas turi pilną teisę ignoruoti Do arba apkirpti rezultatą kitaip nei tikitės. Šio etapo TechnicalNotes tai pasako tiesiai: toks metodas "atvaizduojamas daugumoje skaitytuvų", bet "nėra griežtai ISO atitinkantis Form XObject", o pilnam atitikimui reikia atskiru žingsniu sintetinti tikrą Form XObject srautą. Todėl su stitch išvestimi elkitės taip, kaip elgtumėtės su bet kokiu neatitinkančiu konstruktu: tikrinkite ją konkrečiose peržiūros programose, kurias naudoja jūsų klientai, o ne tik toje, kurią turite savo kompiuteryje, ir jei jums reikia archyvinių arba griežto validatoriaus švarių PDF, šiuo keliu nepasikliaukite. Ta pati disciplina galioja viskam, ką kuriate ant įkelto objektų grafo, todėl PDF preflight patikra Delphi aplinkoje pelnytai atsiduria leidimo vamzdyne kaskart, kai dokumentai keičiami programiškai
Kur tai tinka, o kur ne
Abu metodai yra turinio srauto įrankiai, todėl mentalinis modelis tas pats, kurį naudojate tiesioginiam piešimui. Jei anksčiau kūrėte puslapius nuo nulio naudodami komponentą, už šių kvietimų esantys vektoriniai ir spalviniai operatoriai atrodys pažįstami iš HotPDF drobės piešimo Delphi aplinkoje; skirtumas tik tas, kad čia jūs pridedate prie srauto, kurį sukūrė kažkas kitas, o ne prie to, kurį valdote patys. Turėkite omenyje tris ribas:
- Redagavimas čia yra kosmetinis.
RedactLoadedRectuždažo turinį, bet jo niekada neištrina. Bet kokiems jautriems duomenims atkurkite šaltinį arba naudokite tikrą turinio pašalinimą - juoda dėžė nėra saugumas - Stitch pagal sumanymą neatitinka standarto. Šaltinio puslapis nurodomas kaip pseudo-XObject be §8.10.1 reikalaujamų
/Subtype /Formir/BBox, todėl patvirtinkite atvaizdavimą savo tikslinėse peržiūros programose ir venkite šio kelio ten, kur reikalinga griežta validacija - Koordinatės yra puslapio naudotojo erdvėje. Pradžia apatiniame kairiajame kampe, vienetai taškais, viską lemia paties puslapio media-box. Prieš ką nors dėdami nuskaitykite langelį su
GetLoadedPageBox, nes įkeltas puslapis gali būti ne tokio dydžio, kokio tikėjotės
Naudojami laikantis šių ribų, abu metodai dengia visai realią darbo eigą: perrikiuoti puslapius spausdinimui, užmaskuoti nekonfidencialias sritis ir išsaugoti rezultatą su SaveLoadedDocument - visa tai be pilno pervaizdavimo. Įkelto dokumento API, kuriai priklauso šie susiuvimo ir maskavimo primityvai, tiekiamas kartu su HotPDF Component, skirtu Delphi ir C++Builder, šalia tos pačios laidos formų laukų, anotacijų ir FDF metodų