Τεχνικό Άρθρο

HotPDF Tesseract DLL OCR: κλήση του C API από Delphi

Το HotPDF τρέχει Tesseract μέσα στη διεργασία Delphi σας μέσω του HPDFCreateTesseractDLLOCREngine, ενός factory που μπήκε στο v2.772.0 και φορτώνει δυναμικά DLL συμβατό με Tesseract 5, οδηγεί το C API του (TessBaseAPIInit2, TessBaseAPIRecognize, τον result iterator) και επιστρέφει IHPDFOCREngine. Το THotPDF.ApplyLoadedOCRTextLayer χρησιμοποιεί εκείνο το engine για να προσθέσει αόρατο, αναζητήσιμο text layer Unicode σε σαρωμένες σελίδες PDF

Ο ίδιος recognizer ήταν ήδη προσβάσιμος μέσω του external adapter tesseract.exe που γράφει BMP και κάνει parse TSV. Εκείνη η διαδρομή δουλεύει, αλλά κάθε σελίδα πληρώνει εκτόξευση διεργασίας, προσωρινό αρχείο bitmap και μορφή κειμένου χωρίς baselines και χωρίς έλεγχο στη σελιδοτομή. Η κλήση του DLL αφαιρεί και τα τρία. Αφαιρεί επίσης το τοίχωμα διεργασίας, που σημαίνει ότι ένα binding Pascal κάθεται απευθείας πάνω σε δομές C, booleans C και strings δεσμευμένες από C. Το μεγαλύτερο μέρος όσων αξίζει να ξέρετε για αυτόν τον adapter είναι το πού μπορεί εκείνο το binding να πάει στραβά αθόρυβα

Πώς τρέχετε Tesseract in-process από Delphi με το HotPDF;

Το να τρέξετε Tesseract in-process με το HotPDF θέλει μία κλήση factory στη unit HPDFTesseractRecognition και την ίδια κλήση ApplyLoadedOCRTextLayer που χρησιμοποιεί κάθε engine OCR του HotPDF. Το factory επικυρώνει πρόωρα. Το αρχείο DLL και ο κατάλογος tessdata πρέπει να υπάρχουν, ο γλωσσικός αναγνωριστικός επιτρέπεται να περιέχει μόνο ASCII γράμματα, ψηφία, _ και +, κάθε model σε συνδυασμό όπως chi_sim+eng πρέπει να έχει ταιριαστό αρχείο .traineddata, και όλα τα 21 απαιτούμενα exports πρέπει να λύνονται πριν επιστραφεί το engine. Λάθη διαμόρφωσης πετούν EArgumentException· DLL που αποτυγχάνει να φορτώσει πετά EOSError με τον κωδικό σφάλματος Windows και υπόδειξη να ελέγξετε αρχιτεκτονική και εξαρτήσεις

uses
  SysUtils, HPDFDoc, HPDFTesseractRecognition;

procedure MakeSearchable(const SourceFile, TargetFile: string);
var
  Doc: THotPDF;
  Engine: IHPDFOCREngine;
  Options: THPDFOCRTextLayerOptions;
  Info: THPDFOCRTextLayerInfo;
begin
  // Μια εφαρμογή Win64 θέλει DLL 64-bit· τα dependency DLLs πάνε δίπλα του
  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
    // Κενή λίστα σελίδων σημαίνει κάθε σελίδα· σελίδες που έχουν ήδη κείμενο παραλείπονται
    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 θέτει το PageSegMode σε tpsAuto, το EngineMode σε temDefault, το TimeoutMilliseconds σε 60.000 και το MaxPixels σε 16.777.216. Ο pixel προϋπολογισμός μετράει περισσότερο απ' όσο φαίνεται. Σελίδα US Letter στα προεπιλεγμένα 300 DPI αποδίδει σε 2.550 × 3.300 pixels, γύρω στα 8,4 εκατομμύρια, που χωράει. Η ίδια σελίδα στα 600 DPI είναι 5.100 × 6.600, γύρω στα 33,7 εκατομμύρια, και ο adapter την απορρίπτει πριν το Tesseract δει ένα pixel. Ανασηκώστε το MaxPixels (το ταβάνι είναι 67.108.864) ή αφήστε το DPI εκεί που είναι· κάθε πλευρά επίσης περικόπτεται στα 32.767 pixels

Ο DLL φορτώνεται με LoadLibraryEx με τα search flags για τον δικό του φάκελο του DLL συν τους προεπιλεγμένους ασφαλείς καταλόγους, οπότε οι βιβλιοθήκες εικόνων που εξαρτάται το Tesseract μπορούν να ζουν δίπλα του χωρίς να αγγίξετε το PATH ή τον τρέχοντα κατάλογο. Το HotPDF δεν πακετάρει ούτε κατεβάζει κανένα runtime ή model OCR· τα προμηθεύεστε εσείς

Τι αλλάζει σε σύγκριση με τον adapter tesseract.exe;

Ο adapter DLL ανταλλάσσει απομόνωση διεργασίας για πλουσιότερη έξοδο και χαμηλότερο overhead ανά σελίδα. Και οι δύο adapters μπαίνουν στον ίδιο αγωγό text-layer, οπότε χαρτογράφηση συντεταγμένων, φιλτράρισμα εμπιστοσύνης και η δέσμευση all-or-nothing είναι πανομοιότυπα· ό,τι διαφέρει είναι πώς μπαίνουν τα pixels και πώς βγαίνουν οι λέξεις

ΠτυχήAdapter tesseract.exeAdapter Tesseract DLL
FactoryHPDFCreateTesseractOCREngineHPDFCreateTesseractDLLOCREngine
Pixels μέσαΑρχείο BMP σε ιδιωτικό προσωρινό κατάλογοBuffer grayscale 8-bit στη μνήμη
Λέξεις έξωTSV επιπέδου λέξης, περικομμένο στα 64 MiBResult iterator, UTF-8 ανά λέξη
BaselinesΜη διαθέσιμεςΠερασμένες μέσα από TessPageIteratorBaseline
Σελιδοτομή και λειτουργία engineΜόνο αυτόματη τομήTHPDFTesseractPageSegMode, THPDFTesseractEngineMode
TimeoutΣκληρό: η θυγατρική διεργασία τερματίζεταιΣυνεργατικό: το Tesseract πρέπει να το προσέξει
Απομόνωση crash και μνήμηςΞεχωριστή διεργασίαΚαμία, μοιράζεται τον χώρο διευθύνσεών σας

Ένα κόστος δεν εξαφανίζεται. Κάθε κλήση Recognize δημιουργεί το δικό της instance API και καλεί TessBaseAPIInit2, οπότε τα γλωσσικά models αρχικοποιούνται ανά σελίδα αντί για μία φορά ανά engine. Το file cache του λειτουργικού συστήματος μαλακώνει την επαναφόρτωση, αλλά σε μεγάλα σύνολα models πολλών γλωσσών εξακολουθεί να είναι το κυρίαρχο σταθερό κόστος ανά σελίδα, και μετράει μέσα στην προθεσμία αναγνώρισης. Το in-process engine DLL RapidOCR παίρνει τον αντίθετο σχεδιασμό και κρατά τα ONNX models του μόνιμα για τη διάρκεια ζωής του engine· τα προβλήματα ορίου (C ABI, δανεικά buffers, αδιατάρακτη εγγενής δουλειά) είναι η ίδια οικογένεια

Γιατί δεν μπορεί το Delphi να αντιγράψει τη δομή monitor του Tesseract;

Το Delphi δεν μπορεί να καθρεφτίσει με ασφάλεια το monitor προόδου του Tesseract επειδή το ETEXT_DESC περιέχει πεδία εσωτερικά εξαρτώμενα από την έκδοση, οπότε χειροποίητο αντιγραμμένο record βάζει το cancel callback και την προθεσμία σε λάθος offsets σε μερικά builds. Τίποτα δεν αποτυγχάνει δυνατά όταν συμβεί αυτό. Το Tesseract απλώς διαβάζει τον δείκτη callback σας από πεδίο που πλέον κρατά κάτι άλλο, ή δεν βλέπει ποτέ την προθεσμία

Το HotPDF μεταχειρίζεται λοιπόν το monitor ως αδιαφανή δείκτη και τον αγγίζει μόνο μέσω εξαγόμενων συναρτήσεων: TessMonitorCreate, TessMonitorSetCancelThis, TessMonitorSetCancelFunc, TessMonitorSetDeadlineMSecs και TessMonitorDelete. Αν δένετε ο ίδιος το C API για άλλο σκοπό, το ίδιο μοτίβο ισχύει. Το σκίτσο παρακάτω είναι ο δικός σας κώδικας binding, όχι API του HotPDF, και καθρεφτίζει τις δηλώσεις που χρησιμοποιεί εσωτερικά το HotPDF

Χειρισμός monitor DLL Tesseract HotPDF: η αντιγραφή του record ETEXT_DESC εξαρτώμενου από έκδοση βάζει το cancel callback και την προθεσμία σε λάθος offsets και αποτυγχάνει αθόρυβα, ενώ το HotPDF μεταχειρίζεται το monitor ως αδιαφανές, οδηγεί τα TessMonitorCreate, TessMonitorSetCancelThis, TessMonitorSetCancelFunc και TessMonitorSetDeadlineMSecs, και κρατά το cdecl callback χωρίς exceptions
ένας αδιαφανής δείκτης συν πέντε exports είναι όλη η σύμβαση· το callback μένει Boolean ενός byte που διαβάζει μόνο flag και ρολόι
type
  // C: typedef bool (*TessCancelFunc)(void *cancel_this, int words);
  TTessCancelFunc = function(CancelThis: Pointer; Words: Integer): Boolean; cdecl;
  TTessMonitorCreate = function: Pointer; cdecl;   // ETEXT_DESC*, ποτέ dereference
  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
  // Τρέχει στη στοίβα του Tesseract: διαβάστε flags και ρολόι, μην πετάτε ποτέ
  Result := (CancelThis = nil) or POCRJob(CancelThis)^.CancelRequested or
    (GetTickCount64 >= POCRJob(CancelThis)^.DeadlineTick);
end;

// Χρήση, με τους δείκτες συναρτήσεων λυμένους από GetProcAddress:
//   Monitor := MonitorCreate();
//   try
//     MonitorSetCancelThis(Monitor, @Job);
//     MonitorSetCancelFunc(Monitor, ShouldCancel);
//     MonitorSetDeadlineMSecs(Monitor, RemainingMs);
//     RC := BaseAPIRecognize(API, Monitor);
//   finally
//     MonitorDelete(Monitor);
//   end;

Δύο λεπτομέρειες σε εκείνο το σκίτσο είναι σκόπιμες. Το callback επιστρέφει Boolean, που είναι ένα byte τόσο στο Delphi όσο και στο Free Pascal, ταιριάζοντας το C bool στο TessCancelFunc. Το τεσσάρων byte Windows BOOL ή Delphi LongBool φαίνεται εναλλάξιμο και δεν είναι: όταν η μία πλευρά γράφει ένα byte και η άλλη διαβάζει τέσσερα, τα ψηλά bytes του καταχωρητή επιστροφής είναι ό,τι έμεινε εκεί, και ένα false μπορεί να φτάσει ως true. Το ίδιο header μπερδεύει περαιτέρω, επειδή συναρτήσεις όπως η TessPageIteratorBoundingBox επιστρέφουν int, που το HotPDF δηλώνει ως Integer. Διαβάστε τον C τύπο κάθε επιστρεφόμενης τιμής αντί να υποθέσετε μία σύμβαση για όλο το API

Η δεύτερη λεπτομέρεια είναι ότι το callback δεν πετά ποτέ. Exception Delphi που ξετυλίγεται μέσα από frames C++ του Tesseract είναι undefined behavior, οπότε το callback του HotPDF διαβάζει μόνο το token ακύρωσης και μια μονότονη τιμή GetTickCount64. Ο adapter γυρνά το αποτέλεσμα σε διαγνωστικό ακύρωσης ή timeout αφού επιστρέψει το TessBaseAPIRecognize, και εκτελεί εκείνον τον έλεγχο ανεξαρτήτως του εγγενή κωδικού επιστροφής

Ποιοι εγγενείς δείκτες ανήκουν στην πλευρά Delphi;

Ο adapter DLL Tesseract του HotPDF κατέχει τρία εγγενή objects ανά αίτημα, το instance API, το monitor και τον result iterator, και δανείζεται όλα τα άλλα. Κάθε κλήση Recognize δημιουργεί το δικό της σύνολο και το απελευθερώνει σε block finally: TessResultIteratorDelete, μετά TessMonitorDelete, μετά TessBaseAPIDelete. Η απελευθέρωση της διεπαφής engine ξεφορτώνει τη βιβλιοθήκη

Ιδιοκτησία objects DLL Tesseract HotPDF ανά κλήση Recognize: ο result iterator, το monitor και το instance API κατέχονται και ελευθερώνονται με αυτή τη σειρά μέσα σε finally, ο page iterator από TessResultIteratorGetPageIterator είναι δανεική θέα που δεν πρέπει ποτέ να ελευθερωθεί, και strings GetUTF8Text αντιγράφονται και παραδίδονται πίσω μέσω TessDeleteText
τρία objects σε ιδιοκτησία, όλα τα άλλα δανεικά: ελευθερώστε με τη σταθερή σειρά, μην κάνετε ποτέ διπλή απελευθέρωση του page iterator, και μην αναμειγνύετε ποτέ allocators
  • Το TessResultIteratorGetPageIterator επιστρέφει δανεική θέα μέσα στον result iterator, όχι νέο object. Το HotPDF το χρησιμοποιεί για TessPageIteratorBoundingBox και TessPageIteratorBaseline και δεν το ελευθερώνει ποτέ· η ξεχωριστή διαγραφή του θα ελευθέρωνε την ίδια μνήμη δύο φορές
  • Το TessResultIteratorGetUTF8Text επιστρέφει συμβολοσειρά δεσμευμένη από το δικό του runtime του DLL. Το HotPDF την αντιγράφει και την παραδίδει πίσω μέσω TessDeleteText σε block finally· Pascal FreeMem θα την απελευθέρωνε στον λάθος heap
  • Το κείμενο λέξεων αποκωδικοποιείται με αυστηρή επικύρωση UTF-8 και έλεγχο μήκους πριν τη μετατροπή. Λέξεις με χαρακτήρες ελέγχου, κακοδιατυπωμένο UTF-8, boxes έξω από την εικόνα, αντεστραμμένα ορθογώνια ή εμπιστοσύνη έξω από 0-100 αποτυγχάνουν το αίτημα αντί να επιδιορθωθούν αθόρυβα
  • Το συνολικό κείμενο ανά αίτημα περικόπτεται στα 1.048.576 μονάδες κώδικα UTF-16, και το πλήθος λέξεων πρέπει να χωράει τον προϋπολογισμό αιτήματος που κατέβηκε από το ApplyLoadedOCRTextLayer

Η εμπιστοσύνη φτάνει ως 0-100 και κλιμακώνεται σε 0-1, οπότε το THPDFOCRTextLayerOptions.MinimumConfidence σημαίνει το ίδιο πράγμα για κάθε engine. Όταν το Tesseract αναφέρει baseline, και τα δύο άκρα περνούν μέσα· αλλιώς ο αγωγός text-layer υποχωρεί στη γεωμετρική του εκτίμηση, ακριβώς όπως κάνει για είσοδο TSV

Γιατί να επικυρώσετε enum πριν φτάσει στον DLL;

Το HotPDF αντιγράφει το ωμό ordinal των PageSegMode και EngineMode σε Integer πριν τον έλεγχο εύρους, επειδή ένας μεταγλωττιστής μπορεί να υποθέσει ότι μεταβλητή enum κρατά πάντα δηλωμένη τιμή και να διπλώσει το Ord(X) > Ord(High(T)) σε σταθερό false. Τα ordinals δεν είναι διακόσμηση: το THPDFTesseractPageSegMode ακολουθεί την αρίθμηση σελιδοτομής του Tesseract από 0 έως 13, το THPDFTesseractEngineMode ακολουθεί την αρίθμηση λειτουργίας engine από 0 έως 3, και τα δύο πάνε στον DLL ως σκέτοι ακέραιοι. Record options χτισμένο με FillChar, γεμισμένο από stream, ή περασμένο από C++Builder με cast ακέραιο μπορεί να κουβαλά byte όπως 200. Η επικύρωση του αντιγραμμένου ordinal το γυρνά σε EArgumentException τη στιγμή του factory αντί για αόριστη λειτουργία μέσα σε εγγενή κώδικα. Το factory απορρίπτει επίσης τα tpsOSDOnly και tpsAutoOnly, που δεν παράγουν λέξεις, και απαιτεί osd.traineddata για tpsAutoOSD και tpsSparseTextOSD

Τι εγγυάται στην πραγματικότητα το timeout αναγνώρισης;

Το timeout του DLL Tesseract είναι συνεργατικό: το HotPDF μπορεί να σταματήσει τη δική του δουλειά και να ζητήσει από το Tesseract να σταματήσει, αλλά δεν μπορεί να αναγκάσει εγγενή κώδικα να επιστρέψει. Το ρολόι ξεκινά όταν ξεκινά το Recognize, οπότε η μετατροπή bitmap και η αρχικοποίηση models καταναλώνουν τον ίδιο προϋπολογισμό με την αναγνώριση. Το HotPDF ελέγχει παρέλθοντα χρόνο και token ακύρωσης κατά τη μετατροπή grayscale και ανάμεσα σε λέξεις όσο επαναλαμβάνει αποτελέσματα, και περνά τα εναπομείναντα milliseconds στο TessMonitorSetDeadlineMSecs πριν καλέσει TessBaseAPIRecognize

Το κενό είναι μέσα στην εγγενή κλήση. Το monitor του Tesseract συμβουλεύεται κατά την αναγνώριση λέξεων, όχι κατά το TessBaseAPIInit2 ή την ανάλυση σελιδοτομής, οπότε αργή φόρτωση model ή παθολογική διάταξη μπορεί να τρέξει πέρα από την προθεσμία πριν αναφερθεί το timeout. Οι προϋπολογισμοί pixels και εξόδου επίσης δεν περικόπτουν τη δική της χρήση μνήμης της εγγενής βιβλιοθήκης. Αν θέλετε worker που μπορείτε να σκοτώσετε, χρησιμοποιήστε τον adapter διεργασίας· εκείνος είναι ο τίμιος συμβιβασμός, όχι χαρακτηριστικό που λείπει

Ανατομία συνεργατικού timeout DLL Tesseract HotPDF: το ρολόι ξεκινά όταν ξεκινά το Recognize και καλύπτει μετατροπή grayscale, TessBaseAPIInit2 και ανάλυση διάταξης, αλλά το monitor συμβουλεύεται μόνο κατά την αναγνώριση λέξεων, οπότε φορτώσεις models και διάταξη μπορούν να ξεπεράσουν πριν το HotPDF αναφέρει otlsEngineError ή otlsCancelled
μια προθεσμία εδώ είναι αίτημα, όχι εγγύηση· init και ανάλυση διάταξης μπορούν να τρέξουν πολύ, και worker που σκοτώνεται πραγματικά θέλει τον adapter διεργασίας

Η σελιδοτομή είναι εκεί όπου ο adapter DLL κερδίζει το ψωμί του σε δύσκολη είσοδο. Φόρμες, ετικέτες και σαρωμένοι πίνακες με σκορπισμένα πεδία συχνά αναγνωρίζουν καλύτερα με tpsSparseText παρά με αυτόματη τομή, που προσπαθεί να συναρμολογήσει στήλες και παραγράφους που δεν υπάρχουν

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;  // σκορπισμένα πεδία, καμία συναρμολόγηση στηλών
  TessOptions.EngineMode := temLSTMOnly;     // θέλει LSTM models στο tessdata
  TessOptions.TimeoutMilliseconds := 20000;  // συμπεριλαμβάνει αρχικοποίηση models
  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;

Ένα timeout εμφανίζεται ως otlsEngineError με το διαγνωστικό Tesseract DLL OCR timed out, ενώ ακυρωμένο token εμφανίζεται ως otlsCancelled. Και στις δύο περιπτώσεις το ApplyLoadedOCRTextLayer έχει αναγνωρίσει κάθε επιλεγμένη σελίδα πριν ξεκινήσει τη συναλλαγή δέσμευσης, οπότε αποτυχία στη σελίδα 40 από 50 αφήνει το φορτωμένο έγγραφο ακριβώς όπως ήταν. Σημειώστε ότι τα tpsSingleLine, tpsSingleBlock και tpsSparseText αλλάζουν μόνο την τομή· κανένα δεν ισιώνει στραβό σκανάρισμα

Free Pascal και Lazarus: παρωχημένα pixels και χαμένα Κινεζικά

Και τα δύο factory Tesseract δουλεύουν σε builds Windows Free Pascal και Lazarus Win32 και Win64 από το v2.772.1, μετά από δύο διορθώσεις ειδικές για FPC. Ξαναχτίστε πρώτα το πακέτο Lazarus για την αρχιτεκτονική στόχο· η γενική μεταφορά καλύπτεται στο HotPDF σε Free Pascal και Lazarus Win64

Η πρώτη διόρθωση αφορά pixels. LCL TBitmap γραμμένο μέσω scanlines μπορεί να ενημερώσει την ωμή εικόνα του χωρίς να ανανεώσει το handle bitmap Windows, οπότε GetDIBits πάνω σε εκείνο το handle επιστρέφει τα παλιά pixels. Το σύμπτωμα ήταν μπερδεμένο: κείμενο σχεδιασμένο απευθείας πάνω σε bitmap αναγνωριζόταν, ενώ σελίδα αποδιδομένη από τον renderer PDF του HotPDF παρήγε κενή λίστα λέξεων. Σε FPC ο adapter διαβάζει πλέον snapshot ευαίσθητο σε format μέσω CreateIntfImage, που σέβεται το pixel format και τη σειρά γραμμών της ωμής εικόνας. Το build Delphi κρατά τη διαδρομή GetDIBits πάνω σε ιδιωτικό αντίγραφο 24 bit. Κανένα build δεν τροποποιεί το bitmap του καλούντος

Η δεύτερη διόρθωση ανήκει στον adapter tesseract.exe. Το TStringList του FPC αποθηκεύει strings ANSI, οπότε η ανάθεση αποκωδικοποιημένου κειμένου TSV UTF-8 στο Lines.Text πετούσε αθόρυβα κάθε κινεζικό ή supplementary-plane χαρακτήρα που η ANSI code page του συστήματος δεν μπορούσε να αναπαραστήσει. Η διαδρομή FPC κρατά πλέον το TSV ως bytes UTF-8, αφαιρεί το BOM σε επίπεδο byte και αποκωδικοποιεί κάθε λέξη σε UnicodeString χωριστά. Ο adapter DLL δεν είχε ποτέ αυτό το πρόβλημα επειδή αποκωδικοποιεί κάθε λέξη απευθείας από τον iterator

Σύντομη αναφορά

  • Factory: HPDFCreateTesseractDLLOCREngine(LibraryPath, TessDataDirectory, Language[, Options]) στο HPDFTesseractRecognition, μπήκε στο v2.772.0, υποστήριξη FPC στο v2.772.1
  • Προεπιλογές: tpsAuto, temDefault, 60.000 ms, 16.777.216 pixels· εύρος timeout 1-3.600.000 ms, ταβάνι pixels 67.108.864
  • Ταιριάξτε το bitness του DLL με την εφαρμογή και τοποθετήστε τα dependency DLLs δίπλα στο DLL Tesseract
  • Μεταχειριστείτε το monitor ως αδιαφανές· μην αντιγράψετε ποτέ ETEXT_DESC σε record Pascal
  • Δηλώστε το cancel callback cdecl με αποτέλεσμα Boolean ενός byte, και μην αφήσετε ποτέ exception να δραπετεύσει από αυτό
  • Ελευθερώστε κείμενο iterator με TessDeleteText· μην ελευθερώσετε ποτέ τον page iterator που λήφθηκε από τον result iterator
  • Περιμένετε την προθεσμία συνεργατική: αρχικοποίηση models και ανάλυση διάταξης μπορούν να την ξεπεράσουν
  • Χρησιμοποιήστε τον adapter tesseract.exe όταν θέλετε σκληρό τερματισμό ή απομόνωση crashes

Ο adapter DLL Tesseract, οι process adapters και το built-in engine OCR έρχονται όλα με το HotPDF Delphi PDF component για Delphi, C++Builder και Free Pascal· δείτε τη σελίδα προϊόντος HotPDF για εκδόσεις και λήψεις