HotPDF pokreće Tesseract unutar vašeg Delphi procesa kroz HPDFCreateTesseractDLLOCREngine, fabriku dodatu u v2.772.0 koja dinamički učitava DLL kompatibilan sa Tesseract 5, 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 prepoznavač već je bio dostižan kroz eksterni tesseract.exe adapter koji piše BMP i parsira TSV. Ta putanja radi, ali svaka stranica plaća pokretanje procesa, privremeni bitmap fajl i tekstualni format bez baznih linija i bez kontrole nad segmentacijom stranica. Pozivanje DLL-a uklanja sve tri. Uklanja i procesni zid, što znači da Pascal vezivanje sedi direktno na C strukturama, C boolean-ima i C-alociranim stringovima. Većina onoga što vredi znati o ovom adapteru je gde to vezivanje može tiho poći naopako
Kako pokrenuti Tesseract in-process iz Delphi-ja sa HotPDF-om?
Pokretanje Tesseract-a in-process sa HotPDF-om traži jedan poziv fabrike u HPDFTesseractRecognition jedinici i isti poziv ApplyLoadedOCRTextLayer koji svaki HotPDF OCR engine koristi. Fabrika validira rano. DLL fajl i tessdata direktorijum moraju postojati, jezički identifikator sme sadržati samo ASCII slova, cifre, _ i +, svaki model u kombinaciji poput chi_sim+eng mora imati odgovarajući .traineddata fajl, i svih 21 potrebnih izvoza mora se razrešiti pre nego što se engine vrati. Greške konfiguracije podižu EArgumentException; DLL koji ne uspe da se učita podiže EOSError sa Windows kodom greške i nagoveštajem da proverite arhitekturu i zavisnosti
uses
SysUtils, HPDFDoc, HPDFTesseractRecognition;
procedure MakeSearchable(const SourceFile, TargetFile: string);
var
Doc: THotPDF;
Engine: IHPDFOCREngine;
Options: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
// Win64 aplikacija traži 64-bitni DLL; DLL-ovi zavisnosti idu pored 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 preskaču se
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. Piksel budžet je važniji nego što izgleda. US Letter stranica na podrazumevanih 300 DPI renderuje se u 2.550 × 3.300 piksela, oko 8,4 miliona, što staje. Ista stranica na 600 DPI je 5.100 × 6.600, oko 33,7 miliona, i adapter je odbija pre nego što Tesseract vidi piksel. Podignite MaxPixels (plafon je 67.108.864) ili ostavite DPI gde jeste; svaka strana takođe je ograničena na 32.767 piksela
DLL se učitava sa LoadLibraryEx koristeći zastavice pretrage za sopstveni folder DLL-a plus podrazumevane bezbedne direktorijume, pa slikovne biblioteke kojima Tesseract zavisi mogu živeti pored njega bez diranja PATH ili trenutnog direktorijuma. HotPDF ne zbija ni ne preuzima nikakav OCR runtime ni model; vi obezbeđujete oba
Šta se menja u poređenju sa tesseract.exe adapterom?
DLL adapter trguje izolacijom procesa za bogatiji izlaz i manji trošak po stranici. Oba adaptera priključuju se na isti cevovod tekstualnog sloja, pa su mapiranje koordinata, filtriranje poverenja i uveravanje sve-ili-ništa identični; razlikuje se kako pikseli ulaze i reči izlaze
| Aspekt | tesseract.exe adapter | Tesseract DLL adapter |
|---|---|---|
| Fabrika | HPDFCreateTesseractOCREngine | HPDFCreateTesseractDLLOCREngine |
| Pikseli ulaze | BMP fajl u privatnom privremenom direktorijumu | 8-bitni grayscale bafer u memoriji |
| Reči izlaze | TSV nivoa reči, ograničen na 64 MiB | Iterator rezultata, UTF-8 po reči |
| Bazne linije | Nedostupne | Prosleđene iz TessPageIteratorBaseline |
| Segmentacija stranica i režim engine-a | Samo automatska segmentacija | THPDFTesseractPageSegMode, THPDFTesseractEngineMode |
| Rok | Tvrdo: podproces se prekida | Kooperativno: Tesseract mora primetiti |
| Izolacija pada i memorije | Odvojen proces | Nema, deli vaš adresni prostor |
Jedna cena ne nestaje. Svaki poziv Recognize stvara sopstvenu API instancu i zove TessBaseAPIInit2, pa se jezički modeli inicijalizuju po stranici, a ne jednom po engine-u. Fajl keš operativnog sistema omekšava ponovno učitavanje, ali na velikim višejezičnim skupovima modela i dalje je dominantan fiksni trošak po stranici, i računa se u rok prepoznavanja. In-process RapidOCR DLL engine uzima suprotan dizajn i drži svoje ONNX modele rezidentne za vek engine-a; problemi granice (C ABI, pozajmljeni baferi, neprekidiva nativna dela) ista su porodica
Zašto Delphi ne može kopirati Tesseract monitor strukturu?
Delphi ne može bezbedno ogledati Tesseract monitor napretka jer ETEXT_DESC sadrži verziji-zavisna interna polja, pa ručno kopiran zapis stavlja cancel callback i rok na pogrešne ofsete na nekim verzijama. Ništa ne pada glasno kad se to desi. Tesseract jednostavno čita vaš callback pokazivač iz polja koje sada drži nešto drugo, ili nikada ne vidi rok
HotPDF zato tretira monitor kao neproziran pokazivač i dodiruje ga samo kroz izvezene funkcije: TessMonitorCreate, TessMonitorSetCancelThis, TessMonitorSetCancelFunc, TessMonitorSetDeadlineMSecs i TessMonitorDelete. Ako sami vezujete C API za drugu svrhu, isti obrazac važi. Skica ispod je vaš sopstveni kod vezivanja, ne HotPDF API, i ogleda deklaracije koje HotPDF interno koristi
type
// C: typedef bool (*TessCancelFunc)(void *cancel_this, int words);
TTessCancelFunc = function(CancelThis: Pointer; Words: Integer): Boolean; cdecl;
TTessMonitorCreate = function: Pointer; cdecl; // ETEXT_DESC*, nikada ne dereferenciran
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
// Radi na Tesseract steku: čitaj zastavice i sat, nikada ne podiži
Result := (CancelThis = nil) or POCRJob(CancelThis)^.CancelRequested or
(GetTickCount64 >= POCRJob(CancelThis)^.DeadlineTick);
end;
// Upotreba, sa pokazivačima funkcija razrešenim kroz 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 namerni su. Callback vraća Boolean, što je jedan bajt i u Delphi-ju i u Free Pascalu, poklapajući se sa C bool u TessCancelFunc. Četvorobajtni Windows BOOL ili Delphi LongBool izgleda zamenljivo i nije: kad jedna strana piše jedan bajt a druga čita četiri, gornji bajtovi povratnog registra su ono što je tamo ostalo, i false može stići kao true. Isti header dalje komplikuje stvari, jer funkcije poput TessPageIteratorBoundingBox vraćaju int, koji HotPDF deklariše kao Integer. Čitajte C tip svake povratne vrednosti umesto da pretpostavite jednu konvenciju za ceo API
Drugi detalj je da callback nikada ne podiže. Delphi izuzetak koji se odmotava kroz Tesseract C++ okvire nedefinisano je ponašanje, pa HotPDF callback čita samo token otkazivanja i monotonsku GetTickCount64 vrednost. Adapter pretvara rezultat u dijagnostiku otkazivanja ili roka posle što se TessBaseAPIRecognize vrati, i izvodi tu proveru bez obzira na nativni povratni kod
Koje nativne pokazivače Delphi strana poseduje?
HotPDF Tesseract DLL adapter poseduje tri nativna objekta po zahtevu, API instancu, monitor i iterator rezultata, a pozajmljuje sve ostalo. Svaki poziv Recognize stvara svoj skup i otpušta ga u finally bloku: TessResultIteratorDelete, pa TessMonitorDelete, pa TessBaseAPIDelete. Otpuštanje interfejsa engine-a istovara biblioteku
TessResultIteratorGetPageIteratorvraća pozajmljen pogled u iterator rezultata, ne novi objekat. HotPDF ga koristi zaTessPageIteratorBoundingBoxiTessPageIteratorBaselinei nikada ga ne oslobađa; brisanje odvojeno oslobodilo bi istu memoriju dvaputTessResultIteratorGetUTF8Textvraća string alociran sopstvenim runtime-om DLL-a. HotPDF ga kopira i vraća krozTessDeleteTextufinallybloku; PascalFreeMemoslobodio bi ga na pogrešnom hipu- Tekst reči dekodira se sa strogom UTF-8 validacijom i proverom dužine pre konverzije. Reči sa kontrolnim karakterima, deformisanim UTF-8, kutijama van slike, obrnutim pravougaonicima ili poverenjem van 0–100 padaju zahtev umesto da se tiho zakrpe
- Ukupan tekst po zahtevu ograničen je na 1.048.576 UTF-16 code jedinica, i broj reči mora stati u budžet zahteva predat s naniže od
ApplyLoadedOCRTextLayer
Poverenje stiže kao 0–100 i skalira se na 0–1, pa THPDFOCRTextLayerOptions.MinimumConfidence znači isto za svaki engine. Kad Tesseract prijavi baznu liniju, oba kraja se prosleđuju; inače se cevovod tekstualnog sloja vraća na svoju geometrijsku procenu, tačno kao za TSV unos
Zašto validirati enum pre nego što stigne do DLL-a?
HotPDF kopira sirovi ordinal od PageSegMode i EngineMode u Integer pre provere opsega, jer kompajler može pretpostaviti da enum promenljiva uvek drži deklarisanu vrednost i skupiti Ord(X) > Ord(High(T)) u konstantu false. Ordinali nisu dekoracija: THPDFTesseractPageSegMode prati Tesseract numeraciju segmentacije stranica od 0 do 13, THPDFTesseractEngineMode prati numeraciju režima engine-a od 0 do 3, i oba idu u DLL kao obični celobrojni. Zapis opcija građen sa FillChar, popunjen iz toka ili predat iz C++Builder-a sa pretvorenim celim brojem može nositi bajt poput 200. Validiranje kopiranog ordinala pretvara to u EArgumentException u vreme fabrike umesto nedefinisanog režima unutar nativnog koda. Fabrika takođe odbija tpsOSDOnly i tpsAutoOnly, koji ne proizvode reči, i traži osd.traineddata za tpsAutoOSD i tpsSparseTextOSD
Šta rok prepoznavanja zapravo garantuje?
Rok Tesseract DLL-a je kooperativan: HotPDF može zaustaviti svoj rad i zamoliti Tesseract da stane, ali ne može naterrati nativni kod da se vrati. Sat kreće kad Recognize počne, pa konverzija bitmape i inicijalizacija modela troše isti budžet kao prepoznavanje. HotPDF proverava proteklo vreme i token otkazivanja tokom grayscale konverzije i između reči dok iterira rezultate, i predaje preostale milisekunde TessMonitorSetDeadlineMSecs pre poziva TessBaseAPIRecognize
Praznina je unutar nativnog poziva. Tesseract monitor pita se tokom prepoznavanja reči, ne tokom TessBaseAPIInit2 ili analize rasporeda stranice, pa sporo učitavanje modela ili patološki raspored može pretrčati rok pre nego što se istek prijavi. Piksel i izlazni budžeti takođe ne ograničavaju sopstvenu upotrebu memorije nativne biblioteke. Ako treba radnik koga možete ubiti, koristite procesni adapter; to je pošteno prilagođavanje, ne nedostajuća funkcija
Segmentacija stranica je gde DLL adapter zarađuje svoj hljeb na teškom unosu. Obrasci, etikete i skenirane tabele sa rasutim poljima često se prepoznaju bolje sa tpsSparseText nego sa automatskom segmentacijom, koja pokušava sklopiti kolone i pasuse 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 sklapanja kolona
TessOptions.EngineMode := temLSTMOnly; // traži LSTM modele 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 pokazuje se kao otlsEngineError sa dijagnostikom Tesseract DLL OCR timed out, dok otkazani token pokazuje se kao otlsCancelled. U oba slučaja ApplyLoadedOCRTextLayer prepoznao je svaku izabranu stranicu pre nego što počne transakciju uveravanja, pa neuspeh na stranici 40 od 50 ostavlja učitani dokument tačno kakav je bio. Zapamtite da tpsSingleLine, tpsSingleBlock i tpsSparseText menjaju samo segmentaciju; nijedan ne ispravi iskrivljen sken
Free Pascal i Lazarus: zastareli pikseli i izgubljeni kineski
Oba Tesseract fabriku rade u Windows Free Pascal i Lazarus Win32 i Win64 verzijama od v2.772.1, posle dve FPC-specifične popravke. Prvo ponovo izgradite Lazarus paket za ciljnu arhitekturu; opšti port pokriven je u HotPDF na Free Pascal i Lazarus Win64
Prva popravka se tiče piksela. LCL TBitmap pisan kroz scanline može ažurirati svoju sirovu sliku bez osvežavanja Windows bitmap handle-a, pa GetDIBits na tom handle-u vraća stare piksele. Simptom je bio zbunjujući: tekst nacrtan direktno na bitmapu prepoznavao se, dok je stranica renderovana HotPDF PDF renderer-om davala praznu listu reči. Na FPC-u adapter sada čita snapshot svestan formata kroz CreateIntfImage, koji poštuje piksel format i redosled redova sirove slike. Delphi verzija zadržava GetDIBits putanju na privatnoj 24-bitnoj kopiji. Nijedna verzija ne menja bitmapu pozivaoca
Druga popravka pripada tesseract.exe adapteru. FPC TStringList čuva ANSI stringove, pa je dodela dekodiranog UTF-8 TSV teksta Lines.Text tiho bacala svaki kineski ili dopunsko-ravanski karakter koji sistemski ANSI kod stranice nije mogao predstaviti. FPC putanja sada čuva TSV kao UTF-8 bajtove, skida BOM na nivou bajtova i dekodira svaku reč u UnicodeString pojedinačno. DLL adapter nikada nije imao ovaj problem jer dekodira svaku reč direktno iz iteratora
Brzi pregled
- Fabrika:
HPDFCreateTesseractDLLOCREngine(LibraryPath, TessDataDirectory, Language[, Options])uHPDFTesseractRecognition, dodata u v2.772.0, FPC podrška u v2.772.1 - Podrazumevane vrednosti:
tpsAuto,temDefault, 60.000 ms, 16.777.216 piksela; opseg roka 1–3.600.000 ms, piksel plafon 67.108.864 - Uskladite bitnost DLL-a sa aplikacijom i postavite DLL-ove zavisnosti pored Tesseract DLL-a
- Tretirajte monitor kao neproziran; nikada ne kopirajte
ETEXT_DESCu Pascal zapis - Deklarišite cancel callback kao
cdeclsaBooleanrezultatom od jednog bajta, i nikada ne pustite izuzetak da pobegne iz njega - Oslobađajte tekst iteratora sa
TessDeleteText; nikada ne oslobađajte iterator stranica dobijen iz iteratora rezultata - Očekujte da je rok kooperativan: inicijalizacija modela i analiza rasporeda mogu ga pretrčati
- Koristite tesseract.exe adapter kad treba tvrdo prekidanje ili izolacija padova
Tesseract DLL adapter, procesni adapteri i ugrađeni OCR engine svi se isporučuju sa HotPDF Delphi PDF komponentom za Delphi, C++Builder i Free Pascal; pogledajte stranicu proizvoda HotPDF za izdanja i preuzimanja