HotPDF pokreće Tesseract unutar vašeg Delphi procesa kroz HPDFCreateTesseractDLLOCREngine, tvornicu dodanu u v2.772.0 koja dinamički učitava Tesseract 5 kompatibilan DLL, vozi njegov C API (TessBaseAPIInit2, TessBaseAPIRecognize, iterator rezultata) i vraća IHPDFOCREngine. THotPDF.ApplyLoadedOCRTextLayer koristi taj engine da doda nevidljivi, pretraživi Unicode tekstualni sloj skeniranim PDF stranicama
Isti je prepoznavatelj već bio dostupan kroz vanjski tesseract.exe adapter koji piše BMP i parsira TSV. Taj put radi, ali svaka stranica plaća pokretanje procesa, privremenu bitmapnu datoteku i tekstovni format bez baselinea i bez kontrole nad segmentacijom stranica. Pozivanje DLL-a uklanja sve tri. Uklanja i procesni zid, što znači da Pascal binding sjedi izravno na C strukturama, C booleanima i C-om alociranim stringovima. Najveći dio onoga što vrijedi znati o ovom adapteru jest gdje se taj binding može tiho pokvariti
Kako pokrenuti Tesseract in-process iz Delphija s HotPDF-om?
Pokretanje Tesseracta in-process s HotPDF-om traži jedan poziv tvornice u HPDFTesseractRecognition jedinici i isti poziv ApplyLoadedOCRTextLayer koji svaki HotPDF OCR engine koristi. Tvornica validira rano. Datoteka DLL-a i tessdata mapa moraju postojati, jezični identifikator smije sadržavati samo ASCII slova, znamenke, _ i +, svaki model u kombinaciji poput chi_sim+eng mora imati odgovarajuću .traineddata datoteku, i svih 21 potrebnih izvoza mora se razriješiti prije nego se engine vrati. Pogreške konfiguracije dižu EArgumentException; DLL koji ne uspije učitati se diže EOSError s Windows kodom pogreške i nagovještajem da se provjere arhitektura i ovisnosti
uses
SysUtils, HPDFDoc, HPDFTesseractRecognition;
procedure MakeSearchable(const SourceFile, TargetFile: string);
var
Doc: THotPDF;
Engine: IHPDFOCREngine;
Options: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
// Win64 aplikacija treba 64-bitni DLL; DLL-ovi ovisnosti idu uz njega
Engine := HPDFCreateTesseractDLLOCREngine('C:\OCR\Win64\libtesseract-5.dll',
'C:\OCR\tessdata', 'chi_sim+eng'); // THPDFTesseractOptions.Default
Doc := THotPDF.Create(nil);
try
Doc.AutoLaunch := False;
if Doc.LoadFromFile(SourceFile) < 1 then
raise Exception.Create('Cannot load ' + SourceFile);
Options := THPDFOCRTextLayerOptions.Default; // 300 DPI, MinimumConfidence 0.5
// Prazna lista stranica znači svaku stranicu; stranice koje već imaju tekst se preskaču
if not Doc.ApplyLoadedOCRTextLayer([], Engine, Options, Info) then
raise Exception.Create(string(Info.Diagnostic));
Writeln(string(Info.EngineName), ': ', Info.AcceptedWordCount,
' words accepted, ', Info.DroppedWordCount, ' dropped');
Doc.SaveLoadedDocument(TargetFile);
finally
Doc.Free;
end;
end;
THPDFTesseractOptions.Default postavlja PageSegMode na tpsAuto, EngineMode na temDefault, TimeoutMilliseconds na 60.000 i MaxPixels na 16.777.216. Pikselni proračun važniji je no što izgleda. US Letter stranica na zadanih 300 DPI renderira u 2.550 × 3.300 piksela, oko 8,4 milijuna, što staje. Isti stranica na 600 DPI 5.100 je × 6.600, oko 33,7 milijuna, i adapter ju odbija prije nego Tesseract vidi piksel. Podignite MaxPixels (strop je 67.108.864) ili držite DPI gdje jest; svaka je strana također ograničena na 32.767 piksela
DLL se učitava s LoadLibraryEx koristeći pretraživačke zastavice za vlastitu mapu DLL-a plus zadane sigurne direktorije, pa slikovne biblioteke kojima Tesseract ovisi mogu živjeti uz njega bez diranja PATH-a ili trenutačnog direktorija. HotPDF ne pakira ni ne preuzima nijedan OCR runtime ni model; oba osigurate vi
Što se mijenja u odnosu na tesseract.exe adapter?
DLL adapter trguje izolacijom procesa za bogatiji izlaz i niži trošak po stranici. Oba adaptera priključuju se na isti pipeline tekstualnog sloja, pa su koordinatno mapiranje, filtriranje pouzdanosti i izvršenje sve-ili-ništa identični; razlikuje se kako pikseli ulaze i riječi izlaze
| Aspekt | tesseract.exe adapter | Tesseract DLL adapter |
|---|---|---|
| Tvornica | HPDFCreateTesseractOCREngine | HPDFCreateTesseractDLLOCREngine |
| Pikseli ulaze | BMP datoteka u privatnom privremenom direktoriju | 8-bitni grayscale međuspremnik u memoriji |
| Riječi izlaze | Word-level TSV, ograničen na 64 MiB | Iterator rezultata, UTF-8 po riječi |
| Baselinei | Nedostupni | Prosljeđeni iz TessPageIteratorBaseline |
| Segmentacija stranica i engine način | Samo automatska segmentacija | THPDFTesseractPageSegMode, THPDFTesseractEngineMode |
| Rok | Tvrdo: dječji se proces terminira | Suradnički: Tesseract mora primijetiti |
| Izolacija rušenja i memorije | Odvojeni proces | Nema, dijeli vaš adresni prostor |
Jedan trošak ne nestaje. Svaki poziv Recognize stvara vlastitu API instancu i poziva TessBaseAPIInit2, pa se jezični modeli inicijaliziraju po stranici umjesto jednom po engineu. Datoteka predmemorija operativnog sustava omekšava ponovno učitavanje, ali na velikim višejezičnim skupovima modela i dalje je dominantni fiksni trošak po stranici, i računa se u rok prepoznavanja. In-process RapidOCR DLL engine uzima suprotni dizajn i drži svoje ONNX modele rezidentnima kroz životni vijek enginea; granični problemi (C ABI, posuđeni međuspremnici, neprekinivi nativni posao) ista su obitelj
Zašto Delphi ne može kopirati Tesseract monitor strukturu?
Delphi ne može sigurno preslikati Tesseract monitor napretka jer ETEXT_DESC sadrži unutarnja polja ovisna o verziji, pa ručno kopiran zapis stavlja cancel callback i rok na pogrešne pomake na nekim verzijama. Ništa ne pada glasno kad se to dogodi. Tesseract jednostavno čita vaš callback pokazivač iz polja koje sada drži nešto drugo, ili rok nikad ne vidi
HotPDF stoga tretira monitor kao neprozirni pokazivač i dira ga samo kroz izvođene funkcije: TessMonitorCreate, TessMonitorSetCancelThis, TessMonitorSetCancelFunc, TessMonitorSetDeadlineMSecs i TessMonitorDelete. Ako sami vežete C API za drugu svrhu, isti obrazac vrijedi. Skica dolje vaš je vlastiti binding kod, a ne HotPDF API, i preslikava deklaracije koje HotPDF koristi interno
type
// C: typedef bool (*TessCancelFunc)(void *cancel_this, int words);
TTessCancelFunc = function(CancelThis: Pointer; Words: Integer): Boolean; cdecl;
TTessMonitorCreate = function: Pointer; cdecl; // ETEXT_DESC*, nikad ne dereferencirati
TTessMonitorDelete = procedure(Monitor: Pointer); cdecl;
TTessMonitorSetCancelFunc = procedure(Monitor: Pointer; Func: TTessCancelFunc); cdecl;
TTessMonitorSetCancelThis = procedure(Monitor, CancelThis: Pointer); cdecl;
TTessMonitorSetDeadlineMSecs = procedure(Monitor: Pointer; MSecs: Integer); cdecl;
TTessBaseAPIRecognize = function(Handle, Monitor: Pointer): Integer; cdecl;
TOCRJob = record
CancelRequested: Boolean;
DeadlineTick: UInt64;
end;
POCRJob = ^TOCRJob;
function ShouldCancel(CancelThis: Pointer; Words: Integer): Boolean; cdecl;
begin
// Izvodi se na Tesseractovu stogu: čitaj zastavice i sat, nikad ne diži
Result := (CancelThis = nil) or POCRJob(CancelThis)^.CancelRequested or
(GetTickCount64 >= POCRJob(CancelThis)^.DeadlineTick);
end;
// Upotreba, s pokazivačima funkcija razriješenim preko GetProcAddress:
// Monitor := MonitorCreate();
// try
// MonitorSetCancelThis(Monitor, @Job);
// MonitorSetCancelFunc(Monitor, ShouldCancel);
// MonitorSetDeadlineMSecs(Monitor, RemainingMs);
// RC := BaseAPIRecognize(API, Monitor);
// finally
// MonitorDelete(Monitor);
// end;
Dva detalja u toj skici namjerna su. Callback vraća Boolean, koji je jedan bajt i u Delphiju i u Free Pascalu, poklapajući se s C boolom u TessCancelFunc. Četverobajtni Windows BOOL ili Delphi LongBool izgleda zamjenjivo i nije: kad jedna strana piše jedan bajt, a druga čita četiri, gornji bajtovi povratnog registra ono su što je tamo ostalo, i false može stići kao true. Isto zaglavlje dodatno komplicira jer funkcije poput TessPageIteratorBoundingBox vraćaju int, koji HotPDF deklarira kao Integer. Čitajte C tip svake povratne vrijednosti umjesto da pretpostavite jednu konvenciju za cijeli API
Drugi je detalj da callback nikad ne diže. Delphi iznimka koja se odmotava kroz Tesseractove C++ okvire nedefinirano je ponašanje, pa HotPDF callback čita samo token otkazivanja i monotonu GetTickCount64 vrijednost. Adapter pretvara rezultat u dijagnostiku otkazivanja ili isteka vremena nakon što TessBaseAPIRecognize vrati, i tu provjeru izvodi bez obzira na nativni povratni kod
Koje nativne pokazivače posjeduje Delphi strana?
HotPDF Tesseract DLL adapter posjeduje tri nativna objekta po zahtjevu, API instancu, monitor i iterator rezultata, a sve ostalo posuđuje. Svaki poziv Recognize stvara vlastiti skup i oslobađa ga u finally bloku: TessResultIteratorDelete, pa TessMonitorDelete, pa TessBaseAPIDelete. Oslobađanje sučelja enginea iskrcava biblioteku
TessResultIteratorGetPageIteratorvraća posuđen prikaz u iterator rezultata, a ne novi objekt. HotPDF ga koristi zaTessPageIteratorBoundingBoxiTessPageIteratorBaselinei nikad ga ne oslobađa; brisanje odvojeno oslobodilo bi istu memoriju dvaputTessResultIteratorGetUTF8Textvraća string alociran runtimeom samog DLL-a. HotPDF ga kopira i predaje natrag prekoTessDeleteTextufinallybloku; PascalFreeMemoslobodio bi ga na pogrešnom heapu- Tekst riječi dekodira se uz strogu UTF-8 validaciju i provjeru duljine prije pretvorbe. Riječi s kontrolnim znakovima, neispravnim UTF-8, okvirima izvan slike, okrenutim pravokutnicima ili pouzdanošću izvan 0–100 obaraju zahtjev umjesto da se tiho zakrpe
- Ukupan tekst po zahtjevu ograničen je na 1.048.576 UTF-16 kodnih jedinica, i broj riječi mora stati u proračun zahtjeva predan od
ApplyLoadedOCRTextLayer
Pouzdanost stiže kao 0–100 i skalira se na 0–1, pa THPDFOCRTextLayerOptions.MinimumConfidence znači isto za svaki engine. Kad Tesseract prijavi baseline, oba se kraja prosljeđuju; inače se pipeline tekstualnog sloja vraća na svoju geometrijsku procjenu, točno kao za TSV ulaz
Zašto validirati enum prije nego dođe do DLL-a?
HotPDF kopira sirovi ordinal PageSegMode i EngineMode u Integer prije provjere raspona, jer kompajler može pretpostaviti da enum varijabla uvijek drži deklariranu vrijednost i saviti Ord(X) > Ord(High(T)) u konstantni false. Ordinali nisu dekoracija: THPDFTesseractPageSegMode slijedi Tesseractovu numeraciju segmentacije stranica od 0 do 13, THPDFTesseractEngineMode slijedi numeraciju engine načina od 0 do 3, i oboje ide u DLL kao obični cijeli brojevi. Zapis opcija građen s FillCharom, popunjen iz toka ili predan iz C++Buildera s castanim cijelim brojem može nositi bajt poput 200. Validacija kopiranog ordinala pretvara to u EArgumentException u trenutku tvornice umjesto u nedefinirani način unutar nativnog koda. Tvornica također odbija tpsOSDOnly i tpsAutoOnly, koji ne proizvode riječi, i zahtijeva osd.traineddata za tpsAutoOSD i tpsSparseTextOSD
Što rok prepoznavanja zapravo jamči?
Tesseract DLL rok je suradnički: HotPDF može zaustaviti vlastiti posao i zamoliti Tesseract da stane, ali ne može nativni kod natjerati da se vrati. Sat kreće kad Recognize počne, pa pretvorba bitmape i inicijalizacija modela troše isti proračun kao prepoznavanje. HotPDF provjerava proteklo vrijeme i token otkazivanja tijekom grayscale pretvorbe i između riječi dok iterira rezultate, i predaje preostale milisekunde TessMonitorSetDeadlineMSecsu prije poziva TessBaseAPIRecognize
Praznina je unutar nativnog poziva. Tesseractov se monitor konzultira tijekom prepoznavanja riječi, a ne tijekom TessBaseAPIInit2 ili analize rasporeda stranice, pa sporo učitavanje modela ili patološki raspored može preći rok prije nego se istek vremena prijavi. Pikselni i izlazni proračuni također ne ograničavaju vlastitu upotrebu memorije nativne biblioteke. Ako trebate workera kojeg možete ubiti, koristite procesni adapter; to je poštena razmjena, a ne nedostajuća značajka
Segmentacija stranica mjesto je gdje se DLL adapter isplati na teškom ulazu. Obrasci, oznake i skenirane tablice s rasutim poljima često se bolje prepoznaju s tpsSparseText nego s automatskom segmentacijom, koja pokušava sastaviti stupce i odlomke kojih nema
procedure OCRFormPages(Doc: THotPDF; const Pages: array of Integer);
var
Engine: IHPDFOCREngine;
TessOptions: THPDFTesseractOptions;
LayerOptions: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
TessOptions := THPDFTesseractOptions.Default;
TessOptions.PageSegMode := tpsSparseText; // rasuta polja, bez sastavljanja stupaca
TessOptions.EngineMode := temLSTMOnly; // treba LSTM modeli u tessdata
TessOptions.TimeoutMilliseconds := 20000; // uključuje inicijalizaciju modela
Engine := HPDFCreateTesseractDLLOCREngine('C:\OCR\Win64\libtesseract-5.dll',
'C:\OCR\tessdata', 'eng+deu', TessOptions);
LayerOptions := THPDFOCRTextLayerOptions.Default;
LayerOptions.MinimumConfidence := 0.6;
if not Doc.ApplyLoadedOCRTextLayer(Pages, Engine, LayerOptions, Info) then
case Info.Status of
otlsCancelled:
Writeln('OCR cancelled, document unchanged');
otlsEngineError:
Writeln('Tesseract failed or timed out: ', string(Info.Diagnostic));
else
Writeln(string(Info.Diagnostic));
end;
end;
Istek vremena izlazi kao otlsEngineError s dijagnostikom Tesseract DLL OCR timed out, dok otkazani token izlazi kao otlsCancelled. U oba slučaja ApplyLoadedOCRTextLayer prepoznao je svaku odabranu stranicu prije nego počne transakcija izvršenja, pa neuspjeh na stranici 40 od 50 ostavlja učitani dokument točno kakav je bio. Primijetite da tpsSingleLine, tpsSingleBlock i tpsSparseText mijenjaju samo segmentaciju; nijedan ne izravnava kosi sken
Free Pascal i Lazarus: zastarjeli pikseli i izgubljeni kineski
Obje Tesseract tvornice rade u Windows Free Pascal i Lazarus Win32 i Win64 verzijama od v2.772.1, nakon dva FPC-specifična popravka. Prvo ponovno izgradite Lazarus paket za ciljnu arhitekturu; opći port obrađen je u HotPDF na Free Pascalu i Lazarus Win64
Prvi popravak tiče se piksela. LCL TBitmap pisan kroz scanlinije može ažurirati svoju sirovu sliku bez osvježavanja Windows handlea bitmape, pa GetDIBits na tom handleu vraća stare piksele. Simptom je bio zbunjujuć: tekst nacrtan izravno na bitmapu prepoznavao se, dok je stranica renderirana HotPDF PDF rendererom proizvodila praznu listu riječi. Na FPC-u adapter sada čita snapshot osviješten o formatu kroz CreateIntfImage, koji poštuje pikselni format i redoslijed redaka sirove slike. Delphi verzija zadržava GetDIBits put na privatnoj 24-bitnoj kopiji. Nijedna verzija ne mijenja pozivateljevu bitmapu
Drugi popravak pripada tesseract.exe adapteru. FPC TStringList sprema ANSI stringove, pa je dodjela dekodiranog UTF-8 TSV teksta Lines.Textu tiho ispustila svaki kineski ili dopunski plan znak koji sustavna ANSI kodna stranica nije mogla predstaviti. FPC put sada zadržava TSV kao UTF-8 bajtove, skida BOM na razini bajtova i dekodira svaku riječ u UnicodeString pojedinačno. DLL adapter nikad nije imao ovaj problem jer dekodira svaku riječ izravno iz iteratora
Brza referenca
- Tvornica:
HPDFCreateTesseractDLLOCREngine(LibraryPath, TessDataDirectory, Language[, Options])uHPDFTesseractRecognition, dodana u v2.772.0, FPC podrška u v2.772.1 - Zadane vrijednosti:
tpsAuto,temDefault, 60.000 ms, 16.777.216 piksela; raspon roka 1–3.600.000 ms, pikselni strop 67.108.864 - Uskladite DLL bitness s aplikacijom i postavite DLL-ove ovisnosti uz Tesseract DLL
- Tretirajte monitor kao neproziran; nikad ne kopirajte
ETEXT_DESCu Pascal zapis - Deklarirajte cancel callback
cdecls jednobajtnimBooleanrezultatom, i nikad mu ne pustite iznimku da pobjegne - Oslobađajte tekst iteratora s
TessDeleteText; nikad ne oslobađajte page iterator dobiven iz iteratora rezultata - Očekujte da je rok suradnički: inicijalizacija modela i analiza rasporeda mogu ga prebaciti
- Koristite tesseract.exe adapter kad trebate tvrdu terminaciju ili izolaciju rušenja
Tesseract DLL adapter, procesni adapteri i ugrađeni OCR engine svi se isporučuju s HotPDF Delphi PDF komponentom za Delphi, C++Builder i Free Pascal; pogledajte HotPDF stranicu proizvoda za izdanja i preuzimanja