PDFium Component iz Delphija prek ApplyOcrSearchLayer skeniranim stranem PDF doda iskalno besedilno plast. Upodobi vsako izbrano stran, slikovne pike preda ponudniku OCR, ki ga priskrbite sami, in prepoznane besede zapiše nazaj kot nevidne besedilne objekte, postavljene čez besede na skenu. Izvirna slika strani ni nikoli dekodirana, ponovno kodirana ali zamenjana, zato je vizualni rezultat bajt za bajtom enak strani, s katero ste začeli
Mehanizem za prepoznavanje namerno ni del knjižnice. PDFium izpostavlja upodabljanje strani, preslikavo koordinat, nalaganje pisav, ustvarjanje besedilnih objektov in nevidne načine upodabljanja, ne vsebuje pa nobenega mehanizma OCR, pretvarjanje, da je drugače, pa bi pomenilo vgraditev tujega izdelka za prepoznavanje v komponento PDF. Namesto tega prepoznavanje živi za vmesnikom IPdfOcrProvider: knjižnica poda slikovne pike BGRA s fiksno postavitvijo in izhodiščem zgoraj, ponudnik pa vrne besedilo Unicode, vrednosti zaupanja in štirikotnike besed
Kaj je pravzaprav iskalna besedilna plast?
Skeniran PDF je slika dokumenta. Vsebina strani je ena velika slika, ničesar pa ni mogoče izbrati, iskati, kopirati ali indeksirati. Iskalna besedilna plast na vrh te slike doda prave besedilne objekte z načinom upodabljanja nastavljenim na nevidno, tako da pregledovalniki ne narišejo ničesar, izbiranje, iskanje in izvlečenje pa besede najdejo natanko tam, kjer se pojavijo
Postavitev je vsa igra. Če je nevidno besedilo zamaknjeno za nekaj pik, poudarki izbire pristanejo ob besedah in ne na njih, kopiranje odstavka pa da besedilo v napačnem vrstnem redu. Zato mora geometrija priti iz istih transformacij, ki jih PDFium uporablja za upodabljanje strani, in ne iz sorazmerne ocene
Implementacija ponudnika
Pogodba ponudnika je ena sama metoda. Prejme zapis slike strani, ki nosi dimenzije, korak (stride), DPI, obliko slikovnih pik in same bajte slikovnih pik, plus žeton za preklic, vrne pa besede ali sporočilo o napaki:
uses
PDFium;
type
TMyOcrProvider = class(TInterfacedObject, IPdfOcrProvider)
public
function RecognizePage(const Image: TPdfOcrImage;
const CancellationToken: IPdfCancellationToken;
out Words: TPdfOcrWords; out ErrorMessage: string): Boolean;
end;
function TMyOcrProvider.RecognizePage(const Image: TPdfOcrImage;
const CancellationToken: IPdfCancellationToken;
out Words: TPdfOcrWords; out ErrorMessage: string): Boolean;
var
I: Integer;
begin
// Image.Pixels nosi vrstice BGRA z izhodiščem zgoraj, dolge Image.Stride bajtov.
// Predajte jih svojemu mehanizmu, nato pa zapolnite en vnos na prepoznano besedo
SetLength(Words, RecognisedCount);
for I := 0 to RecognisedCount - 1 do
begin
Words[I].Text := EngineWordText(I);
Words[I].Confidence := EngineWordConfidence(I); // 0..1
Words[I].Quad := TPdfOcrQuad.FromRectangle(
EngineLeft(I), EngineTop(I), EngineRight(I), EngineBottom(I));
end;
ErrorMessage := '';
Result := True;
end;
Štirikotniki namesto pravokotnikov, ker sken redko poteka pravokotno na stran. Beseda na rahlo zasukani strani zaseda paralelogram, TPdfOcrQuad pa nosi štiri kotne točke, tako da poševne in zasukane besede ohranijo natančno območje izbire. Mehanizmi, ki javijo samo osno poravnane okvirje, lahko uporabijo FromRectangle, ki zgradi degeneriran štirikotnik
Zakaj položajev besed ni mogoče sorazmerno raztegniti?
Skušnjava je pretvoriti koordinato slikovne pike v koordinato strani tako, da jo delite s širino upodobitve in množite s širino strani. To deluje samo za strani brez zasuka, s CropBox, enakim MediaBox, in izhodiščem pri nič, veliko skeniranih dokumentov pa ne izpolnjuje vsaj enega od teh pogojev
PDFium Component vsako od štirih kotnih točk štirikotnika preslika posamično prek FPDF_DeviceToPage, iste preslikave, ki jo je upodabljalnik uporabil za izdelavo slikovnih pik, tako da so vnosi /Rotate in zamaknjeni obrezovalni okvirji obravnavani že po zasnovi. Afina matrika za besedilni objekt je nato zgrajena iz treh preslikanih točk — spodnjega levega, spodnjega desnega in zgornjega levega kota — kar je natanko dovolj za izražanje položaja, merila, zasuka in strižnosti
Besedilni objekt sam je ustvarjen z enotsko velikostjo pisave, tako da je mogoče izmeriti njegove prave meje pisave, izmerjene meje objekta pa se nato preslikajo na ciljni štirikotnik. Dimenzioniranje z uganjeno velikostjo v pikah v upanju, da se ujema s skenirano besedo, bi z vsako zamenjavo pisave zaneslo; merjenje vnaprej naredi prileganje neodvisno od tega, katero pisavo plast uporablja
Zagon čez dokument
Zapis možnosti nadzoruje ločljivost, filtriranje in vsak proračun. Filtriranje po zaupanju je pomembnejše, kot je videti: smetne besede z nizkim zaupanjem trajno onesnažijo rezultate iskanja, in za razliko od napačnega upodabljanja tega nihče ne opazi, dokler iskanje ne vrne nesmisla:
var
Pdf: TPdf;
Options: TPdfOcrOptions;
Report: TPdfOcrReport;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'scanned-contract.pdf';
Pdf.LoadDocument;
Options := TPdfOcrOptions.Default;
Options.Dpi := 300; // ločljivost prepoznavanja
Options.MinConfidence := 0.60; // zavrzi negotove besede
Options.SkipPagesWithText := True; // pusti izvorno digitalne strani pri miru
Options.ContinueOnError := True; // ena slaba stran ne sme ustaviti opravila
Options.MaxPixelsPerPage := 40 * 1000 * 1000;
if Pdf.ApplyOcrSearchLayer(TMyOcrProvider.Create, Options, Report) then
Pdf.SaveAs('scanned-contract-searchable.pdf');
for I := 0 to High(Report.Pages) do
if Report.Pages[I].Status = popsFailed then
Writeln(Format('page %d failed: %s',
[Report.Pages[I].PageNumber, Report.Pages[I].ErrorMessage]));
Writeln(Format('%d word(s) inserted, %d rejected, %d page(s) skipped',
[Report.InsertedWordCount, Report.RejectedWordCount,
Report.SkippedPageCount]));
finally
Pdf.Free;
end;
end;
SkipPagesWithText si v mešanih arhivih zasluži poudarek. PDF, ki že nosi pravo besedilo, bodisi izvorno digitalno bodisi predhodno obdelano, dobi drugo besedilno plast, če čez njega slepo poženete OCR, podvojitev pa povzroči, da izvlečenje vrne vsako besedo dvakrat. Stanje po strani popsSkippedExistingText vam natanko pove, katere strani so ostale pri miru
Proračuni, preklic in omejevanje napak
Vsaka količina, ki jo lahko napihne sovražen ali zgolj ogromen dokument, ima zgornjo mejo: slikovne pike na stran in skupaj, besede na stran in skupaj, ter znake na besedo. Vse te se preverijo, preden je stran zapisana, ne po tem, ocena slikovnih pik pa se izračuna iz dimenzij strani in DPI, preden je dodeljena katera koli bitna slika. Zvišanje DPI s 150 na 300 poštirikrati pomnilnik na stran, zato je zgornja meja na stran parameter, ki ga je treba prvega nastaviti, ko paketno opravilo pri velikih formatih začne odpovedovati
Žeton za preklic se preplete skozi celotno pot: progresivno upodabljanje, klic ponudnika in zanko vstavljanja po besedah. To pomeni, da se uporabnik, ki prekliče med prepoznavanjem 400-stranske datoteke, ustavi znotraj ene strani in ne šele ob koncu dokumenta, isti vzorec žetona, uporabljen drugje v komponenti in opisan v preklicljivem progresivnem upodabljanju, pa velja tudi tu nespremenjen
Omejevanje napak je po strani. Knjižnica zbere ročice objektov, ki jih je vstavila na stran, in po tem, ko so vse besede postavljene, enkrat pokliče FPDFPage_GenerateContent. Če karkoli sredi poti spodleti, bodisi napaka ponudnika bodisi težava s pisavo, se objekti, vstavljeni na tisti strani, odstranijo v obratnem vrstnem redu, vsebina strani pa se znova ustvari, tako da se neuspela stran vrne v svoje izvirno stanje, namesto da bi obdržala polovico besedilne plasti. Zanka dokumenta se nato nadaljuje ali ustavi glede na ContinueOnError, aktivna stran pa je vedno obnovljena
Preverjanje, da se slike res ni nihče dotaknil
Najmočnejša razpoložljiva preverba je hkrati tudi najpreprostejša: upodobite stran pred in po uveljavitvi plasti v isti velikosti ter primerjajte bitni sliki. Morali bi biti enaki bajt za bajtom, ker nevidno besedilo ne nariše ničesar, tok slike pa nikoli ni bil dekodiran. Vsaka razlika pomeni, da je stran spremenilo nekaj drugega kot besedilna plast
Nato preverite še besedilno stran tako, da izvlečete iz obdelane datoteke in potrdite, da položaji besed pristanejo na skenu. Pot izvlečenja je ista, kot je opisana v izvlečenju besedila iz dokumentov PDF, za hiter vizualni pregled poravnave pa vam upodabljanje strani v slike, kot v pretvorbi PDF-strani v JPEG, omogoči prekrivanje okvirjev besed čez sken
Plastenje OCR, upodabljanje, izvlečenje in urejanje vsi tečejo nad istim objektom dokumenta v Delphiju, C++Builderju in Lazarusu; celotna površina API je opisana na strani PDFium Component za Delphi