Stvarna PDF redakcija u Delphiju znači brisanje samih bajtova u pozadini, a ne samo crtanje preko njih. losLab PDF Library povlači tu granicu pomoću dva API-ja: RedactRegion uređuje tok sadržaja stranice tako da uklonjeni tekst, vektori i slike fizički nestaju, dok SanitizeDocument čisti metapodatke, skripte i radnje u kojima se skrivaju redigirani podaci. Pogriješite li u bilo kojem od ova dva koraka, isporučit ćete datoteku koja na zaslonu izgleda cenzurirano, ali otkriva tajnu svakome tko kopira tekst ili otvori svojstva dokumenta
Ovaj propust je općepoznat. Novine, sudovi i vladine agencije objavljivali su PDF dokumente s crnim pravokutnikom postavljenim preko imena ili broja, da bi čitatelj jednostavno označio tekst ispod njega, kopirao ga i zalijepio navodno skriveni niz znakova na vidjelo. Pravokutnik je bio samo crtež. Tekst je i dalje bio tamo, smješten u toku sadržaja jedan sloj ispod boje, potpuno netaknut i spreman za označavanje. losLab PDF Library, Delphi i C++Builder PDF sustav izložen kroz klasu TPDFlib, tretira tu razliku kao smisao cijele redakcije, a ne kao sporednu stvar
Zašto crtanje crnog okvira preko PDF teksta nije stvarna redakcija?
losLab PDF Library izlaže MaskRect za slučajeve kada je prekrivanje uistinu ono što želite: vodeni žig, vizualno zatamnjenje ili dokazni pečat. MaskRect(Page, Left, Top, Width, Height, Red, Green, Blue) dodaje pravokutnik u tok sadržaja stranice i crta ga pomoću operatora za izgradnju putanje re, nakon čega slijedi operator ispune f (ISO 32000-1 §8.5). Svaki bajt koji je već bio na stranici — glifovi imena koje ste prekrili, vektorske linije, ugrađena slika — ostaje točno tamo gdje je i bio, jednu instrukciju ranije u istom toku. Standardni preglednik crta crni okvir na kraju, pa on vizualno nadvladava ostalo. Prekrivanje ne mijenja ništa ispod sebe
Svatko može dohvatiti izvorni sadržaj na tri načina: označavanjem i kopiranjem teksta izravno kroz neprozirni okvir, pokretanjem alata za izdvajanje teksta na stranici ili brisanjem prekrivajućeg pravokutnika iz toka sadržaja. MaskRect je iskren u svom nazivu — on samo maskira, ne uklanja. Rezultat je naljepnica preko riječi koju i dalje možete pročitati jednostavnim uklanjanjem naljepnice
Kako RedactRegion briše sadržaj na razini instrukcija
RedactRegion(Page, Left, Top, Width, Height, Options) radi jedan sloj ispod boje. losLab PDF Library raščlanjuje svaki sloj sadržaja stranice u TPDFContentProgram, prolazi kroz popis instrukcija s analizatorom koji prati CTM (FindInstructionsInRect u modelu sadržaja) i označava svaki operator za prikaz teksta, crtanje putanje i sliku Do čije se oslikano područje siječe s vašim pravokutnikom. Te se instrukcije uklanjaju pomoću TPDFContentProgram.Delete, a uređeni sloj se zapisuje natrag pomoću WritePageContentLayer. Bajtovi ne klize iza pokrova — oni napuštaju tok. Alat za izdvajanje teksta pokrenut nakon toga ne pronalazi ništa jer se nema što pronaći
Dva detalja implementacije vrijedi imati na umu pri donošenju odluka. RedactRegion prima gornji lijevi pravokutnik u trenutačnom ishodištu i jedinicama i interno ga pretvara u donji lijevi korisnički prostor koji koristi tok sadržaja, tako da navodite područje onako kako ga vidite na stranici. Kada pravokutnik pokriva nekoliko instrukcija, RedactRegion ih briše u silaznom redoslijedu indeksa, jer bi uklanjanje instrukcije 4 prije instrukcije 7 pomaknulo svaki kasniji indeks i oštetilo raspon. Ako proslijedite Options = 0, losLab PDF Library također postavlja puni crni okvir preko očišćenog područja kao vidljivi marker — ali taj je marker kozmetički, primijenjen nakon što je stvarni sadržaj već uklonjen
U praksi rijetko ručno upisujete koordinate pravokutnika. Pretražujete stranicu za povjerljivi niz znakova i čitate njegov granični okvir — isto pretraživanje stranice i nabrajanje elemenata obrađeno u članku o pronalaženju teksta i elemenata stranice u Delphiju — a zatim taj pravokutnik prosljeđujete metodi RedactRegion:
var
PDF: TPDFlib;
begin
PDF := TPDFlib.Create;
try
if PDF.LoadFromFile('contract.pdf', '') = 1 then
begin
// Delete everything painted inside a 220 x 14 pt box on page 1.
// Coordinates are top-left, in the current origin and units.
PDF.RedactRegion(1, 90, 705, 220, 14, 0); // Options=0 stamps a black marker
PDF.SaveToFile('contract-redacted.pdf');
end;
finally
PDF.Free;
end;
end;
Gdje se još skrivaju redigirani podaci u PDF-u?
Redakcija koja se zaustavi na vidljivom sloju ostavlja trag jer PDF pohranjuje informacije na mjestima na kojima čitatelj nikada ne gleda. losLab PDF Library svrstava curenja u nekoliko značajnih kanala. Rječnik informacija o dokumentu i XMP tok metapodataka redovito sadrže podatke o autoru (Author), proizvođaču (Producer) ili ključnim riječima (Keywords) koji imenuju upravo osobu ili slučaj koji ste uklonili iz tijela dokumenta. JavaScript na razini dokumenta i kataloška radnja OpenAction mogu se pokrenuti pri otvaranju i pristupiti podacima za koje ste mislili da su nestali. Svaka bilješka nosi opcionalnu radnju /A, a sama bilješka — ljepljiva bilješka, zastarjelo polje obrasca, poveznica — može stajati izravno preko redigiranog mjesta s vlastitom kopijom teksta. Ništa od ovoga nije zaštićeno šifriranjem; šifrirana datoteka s XMP paketom u čistom tekstu i dalje otkriva svoj naslov svakom indeksatoru, što je propust koji sam po sebi zahtijeva provjeru šifriranja i dopuštenja. Pouzdano čišćenje mora posjetiti svako od ovih skrivenih mjesta, a ne samo stranicu koju ste gledali
Čišćenje dokumenta pomoću SanitizeDocument
losLab PDF Library odgovara na ova curenja pomoću metode SanitizeDocument(Flags), koordiniranog poziva koji pokreće skup neovisnih operacija čišćenja odabranih bitnom maskom i vraća broj primijenjenih operacija. Zastavice se mogu kombinirati. SANITIZE_JAVASCRIPT uklanja svaki JavaScript paket na razini dokumenta i bilo koju OpenAction skriptu. SANITIZE_ACTIONS uklanja /A rječnik radnji iz svake bilješke putem nove metode TPDFAnnots.RemoveAnnotAction i čisti kataloški OpenAction. SANITIZE_METADATA prazni polja autor, predmet, ključne riječi, kreator i proizvođač u rječniku informacija o dokumentu (ISO 32000-1 §14.3.3) i XMP toku metapodataka (§14.3.2). SANITIZE_ANNOTATIONS briše sve bilješke u cijelom dokumentu, a SANITIZE_OPEN_ACTION uklanja kataloški unos /OpenAction. SANITIZE_ALL predstavlja uniju svih pet zastavica
Konvencije o indeksiranju unutar ovih operacija upravo su ono što tiho kvari ručno pisane petlje, što je i glavni razlog zašto SanitizeDocument postoji kao jedan poziv. GlobalJavaScriptPackageName počinje od 0, a RemoveGlobalJavaScript smanjuje popis kako radi, pa operacija za JavaScript uvijek čita indeks paketa 0 i uklanja ih dok broj ne dosegne nulu. Nasuprot tome, DeleteAnnotation počinje od 1. AnnotationCount daje izvješće za trenutačno odabranu stranicu, tako da operacije za bilješke odabiru svaku stranicu redom prije brojanja. losLab PDF Library ispravno rješava ove granice interno, tako da prosljeđujete jedan skup zastavica i primate natrag jedan broj, umjesto da ponavljate pet različitih pravila iteracije
Cjelokupni radni tijek redakcije i čišćenja
Kando to dvoje spojite, cijeli postupak je kratak. losLab PDF Library uklanja vidljivi sadržaj pomoću RedactRegion, stranicu po stranicu, a zatim čisti svaki skriveni kanal pomoću SanitizeDocument(SANITIZE_ALL) prije nego što se datoteka zapiše. Budući da se redakcija gotovo uvijek izvodi na dokumentima koji su stigli izvan vaše kontrole, vrijedi ih učitati kroz zaštićeni put — isti obrambeni stav opisan u članku o sigurnom raščlanjivanju nepouzdanih PDF-ova — kako bi neispravan unos zakazao na jasan način, a ne usred postupka redakcije
var
PDF: TPDFlib;
Applied: Integer;
begin
PDF := TPDFlib.Create;
try
if PDF.LoadFromFile('incoming.pdf', '') = 1 then
begin
PDF.RedactRegion(1, 90, 705, 220, 14, 0); // delete the sensitive line
Applied := PDF.SanitizeDocument(SANITIZE_ALL); // clear metadata, JS, actions, annots
PDF.SaveToFile('published.pdf');
end;
finally
PDF.Free;
end;
end;
Gdje se zaustavlja redakcija toka sadržaja
RedactRegion radi na toku sadržaja, što je točno mjesto gdje se nalazi digitalno stvoreni tekst, a ne skenirani tekst. Kada je stranica skenirana slika, riječi su pikseli unutar slikovnog objekta XObject, a ne tekstualni operatori, i losLab PDF Library ne može izrezati ime iz sredine rastera na način na koji briše glif. Njezino rukovanje slikama je namjerno konzervativno: svaka slika čiji se položaj siječe s pravokutnikom uklanja se u cijelosti, pa okvir za redakciju na skeniranoj stranici odnosi cijeli skenirani sadržaj, a ne samo njegov dio. Redakcija područja unutar slike znači rasterizaciju, crtanje i ponovno ugrađivanje na razini piksela, što je drugačija operacija od brisanja toka sadržaja. Isti oprez vrijedi i za OCR tekstualni sloj preko skenirane stranice: RedactRegion uklanja tekstualne operatore koje vidi, ali slika ispod ostaje netaknuta osim ako se nen slikovni objekt XObject također ne siječe s okvirom
Dva fina detalja čine rezultate točnima. Ispitivanje sjecišta procjenjuje širinu svakog teksta na temelju broja znakova i veličine fonta, umjesto mjerenja točne metrike glifova, pa se vrlo kratka riječ u proporcionalnom fontu može provući kroz usko nacrtani pravokutnik — dajte okviru malu marginu. Brisanje je također granulirano na razini instrukcija: RedactRegion uklanja cijele operatore koji prikazuju tekst, pa pravokutnik koji zahvaća samo dio teksta može ukloniti i susjedne znakove koji su dijelili isti operator. Niti jedno ograničenje nije razlog za nepovjerenje u mehanizam, već samo razlog da pažljivo odredite granice pravokutnika i provjerite rezultat
Konačni korak svakog radnog tijeka redakcije je provjera, a ne povjerenje. Redigirajte područje, očistite dokument, spremite u novu datoteku, ponovno je otvorite i pokušajte dohvatiti tekst koji ste uklonili i metapodatke koje ste očistili; ako oboje budu prazni, redakcija je uspjela. API-jevi RedactRegion i SanitizeDocument prikazani ovdje dolaze uz losLab PDF Library za Delphi i C++Builder, zajedno s potpunom referencom modela sadržaja i čišćenja