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

HotPDF In-Process RapidOCR: εγγενές DLL OCR στο Delphi

Το HotPDF κάνει σελίδες σαρωμένων PDF αναζητήσιμες με in-process RapidOCR μέσω του HPDFCreateRapidOCRDLLOCREngine, ενός factory που μπήκε στο v2.774.0 και φορτώνει το HotPDFRapidOCR.dll, κρατά τα ONNX models ανίχνευσης, ταξινόμησης γωνίας και αναγνώρισης μόνιμα στη μνήμη, και επιστρέφει IHPDFOCREngine. Εκείνο το engine το περνάτε στο THotPDF.ApplyLoadedOCRTextLayer, που αποδίδει κάθε σελίδα, τρέχει CPU inference χωρίς Python ή θυγατρική διεργασία, και δεσμεύει ένα αόρατο κείμενο Unicode σαν layer

Το κίνητρο είναι το κόστος ανά σελίδα. Ο process adapter RapidOCR που βγήκε νωρίτερα, το HPDFCreateRapidOCREngine, ξεκινά worker Python για κάθε κλήση Recognize, και εκείνος ο worker κάνει import το runtime του και φορτώνει τα ONNX models του πριν διαβάσει έστω ένα pixel. Σε αρχείο 500 σελίδων εκείνος ο φόρος εκκίνησης επαναλαμβάνεται 500 φορές, και το deployment σημαίνει αποστολή περιβάλλοντος Python δίπλα σε εκτελέσιμο Delphi. Το εγγενές DLL φορτώνει τα models μία φορά, τη στιγμή που δημιουργείτε το engine, και το deployment μικραίνει στο DLL, στα model files του και σε ένα character dictionary. Αυτό που παρατάτε σε αντάλλαγμα είναι η δυνατότητα να σκοτώσετε ένα κολλημένο recognizer, και το μεγαλύτερο μέρος της μηχανικής σε αυτόν τον adapter αφορά το να ζείτε μαζί του τίμια

Πώς κάνετε αναζητήσιμο ένα σαρωμένο PDF με το DLL RapidOCR;

Η δημιουργία αναζητήσιμου PDF με το εγγενές DLL RapidOCR θέλει μία κλήση factory και την ίδια κλήση ApplyLoadedOCRTextLayer που χρησιμοποιεί κάθε engine OCR του HotPDF. Το factory ζει στη unit HPDFRapidOCRRecognition και επικυρώνει πρόωρα: ο DLL και ο κατάλογος models πρέπει να υπάρχουν, κάθε model και αρχείο dictionary πρέπει να λύνεται, η έκδοση ABI πρέπει να είναι 1, και όλα τα απαιτούμενα exports πρέπει να υπάρχουν πριν αρχικοποιηθεί οποιοδήποτε model. Λάθη διαμόρφωσης πετούν EArgumentException· ένα model που αποτυγχάνει να φορτώσει πετά EInvalidOperation που κουβαλά το διαγνωστικό κείμενο που έγραψε ο DLL

Ακολουθία επικύρωσης factory του DLL RapidOCR στο HotPDF για το HPDFCreateRapidOCRDLLOCREngine: οι διαδρομές και τα model files πρέπει να υπάρχουν, το HPDFRapidOCRAbiVersion πρέπει να επιστρέφει 1, τα απαιτούμενα exports πρέπει να λύνονται, και το HPDFRapidOCRCreate πρέπει να αρχικοποιήσει τα models, με EArgumentException ή EInvalidOperation να πετιούνται πρόωρα πριν τρέξει οποιαδήποτε αναγνώριση, με το δεύτερο να κουβαλά το εγγενές διαγνωστικό κείμενο
η επικύρωση είναι πρόωρη επίτηδες: προβλήματα διαμόρφωσης πετούν πριν αρχικοποιηθεί οποιοδήποτε model, οπότε λάθος διαδρομή ή ABI δεν φτάνει ποτέ σε προθεσμία αναγνώρισης
uses
  SysUtils, HPDFTypes, HPDFDoc, HPDFRapidOCRRecognition;

procedure MakeSearchable(const SourceFile, TargetFile: string);
var
  Doc: THotPDF;
  Engine: IHPDFOCREngine;
  Options: THPDFOCRTextLayerOptions;
  Info: THPDFOCRTextLayerInfo;
begin
  // Τα models φορτώνονται εδώ, έξω από κάθε προθεσμία αναγνώρισης.
  // Σχετικά ονόματα models στο THPDFRapidOCRDLLOptions.Default λύνονται
  // σε σχέση με τον κατάλογο models.
  Engine := HPDFCreateRapidOCRDLLOCREngine(
    'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models');
  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,
      ' lines accepted, ', Info.DroppedWordCount, ' dropped');
    Doc.SaveLoadedDocument(TargetFile);
  finally
    Doc.Free;
  end;
end;

Το THPDFRapidOCRDLLOptions.Default κατονομάζει τα ch_PP-OCRv3_det_infer.onnx, ch_PP-OCRv3_rec_infer.onnx, ch_ppocr_mobile_v2.0_cls_infer.onnx, και ppocr_keys_v1.txt, με ένα νήμα CPU, όριο εισόδου 16.777.216 pixels, και προθεσμία αναγνώρισης 60.000 ms. Από το v2.775.0, το THPDFRapidOCRDLLOptions.ForLanguage αντικαθιστά ταιριάζον model αναγνώρισης και dictionary για Παραδοσιακά Κινεζικά, Ρωσικά, Ιαπωνικά, Αραβικά, και άλλα προφίλ· το γιατί model και dictionary πρέπει να αλλάζουν μαζί καλύπτεται στο RapidOCR multilingual models και CTC dictionaries στο HotPDF. Το engine αυτοαναφέρεται ως RapidOCR (native DLL) στο Info.EngineName, που κρατά τα logs αναμφίβολα δίπλα στον external process adapter Tesseract OCR και στο built-in engine OCR template-matching

Γιατί το C ABI μιλάει μόνο int32_t και bytes UTF-8;

Το ABI του HotPDFRapidOCR.dll χρησιμοποιεί μόνο σταθερού πλάτους ακέραιους, ωμούς δείκτες, και ρητά μήκη bytes επειδή το Delphi, το C++Builder και το Free Pascal δεν μοιράζονται τίποτα με το MSVC πέρα από τη σύμβαση κλήσης C. Ένα std::string, ένα std::vector, ή μια exception C++ έχει διάταξη και μοντέλο unwinding που ανήκουν σε έναν μεταγλωττιστή και μία runtime βιβλιοθήκη. Αφήστε οποιοδήποτε από αυτά να διασχίσει το όριο και η αποτυχία είναι χαλασμένη στοίβα ή block heap ελευθερωμένο από λάθος allocator, όχι καθαρό σφάλμα

Η έκδοση ABI 1 ακολουθεί λοιπόν έναν σύντομο κατάλογο κανόνων. Κάθε export είναι cdecl και επιστρέφει κατάσταση int32_t, όπου 1 σημαίνει επιτυχία και 0 αποτυχία. Κάθε συνάρτηση που μπορεί να αποτύχει παίρνει buffer διαγνωστικών ιδιοκτησίας καλούντος και τη χωρητικότητά του σε bytes· ο DLL γράφει μήνυμα UTF-8 με τερματισμό NUL κομμένο να χωρέσει, και ο adapter το αποκωδικοποιεί με σκληρό τερματισμό στο τελευταίο byte του δικού του buffer 4.096 bytes. Το σώμα κάθε export τυλίγεται σε try με τόσο catch (const std::exception &) όσο και catch (...), οπότε ένα σφάλμα ONNX Runtime, μια assertion OpenCV, ή ένα άκυρο dictionary γίνεται κατάσταση 0 συν κείμενο, ποτέ exception που δραπετεύει σε κώδικα Pascal

ExportΡόλοςΠότε τον λύνει ο adapter
HPDFRapidOCRAbiVersionΕπιστρέφει 1· κάθε άλλη τιμή απορρίπτεταιΠρώτος, πριν από οτιδήποτε άλλο
HPDFRapidOCRCreateΦορτώνει models ανίχνευσης, προαιρετικής ταξινόμησης, αναγνώρισης και το dictionaryΣτο factory
HPDFRapidOCRRecognizeΤρέχει ένα bitmap και εκπέμπει ένα callback ανά γραμμή κειμένουΣτο factory
HPDFRapidOCRDestroyΕλευθερώνει το instance του modelΣτο factory
HPDFRapidOCRSetReadingDirectionΠροαιρετική σειρά γραμμών από δεξιά προς αριστερά, μπήκε στο v2.775.0Μόνο όταν είναι ορισμένο το RightToLeft

Το προαιρετικό export λύνεται τεμπέλικα επίτηδες: ένα DLL v2.774.0 που το στερείται εξακολουθεί να σερβίρει αιτήματα αριστερά-προς-δεξιά. Ο DLL φορτώνεται με LoadLibraryEx με search flags που καλύπτουν τον δικό του φάκελο του DLL συν τους προεπιλεγμένους ασφαλείς καταλόγους, οπότε εξαρτήσεις ONNX Runtime ή OpenCV τοποθετημένες δίπλα στο HotPDFRapidOCR.dll βρίσκονται χωρίς να αγγίξετε το PATH. Οι διαδρομές model και dictionary ταξιδεύουν ως UTF-8 και ο DLL τις μετατρέπει με MultiByteToWideChar σε αυστηρή λειτουργία πριν ανοίξει αρχεία μέσω wide-character APIs, οπότε κατάλογος models κάτω από κινεζικό ή κυριλλικό όνομα χρήστη δουλεύει αντί να πλατυθνεί byte προς byte σε αλαμπουρνέζικα

Ένας κανόνας ζει στο build αντί για στο header. Ο DLL συνδέει στατικά ONNX Runtime και OpenCV, και η προεπιλεγμένη διαμόρφωση CMake χρησιμοποιεί static release CRT (/MT). Στατικές βιβλιοθήκες μεταγλωττισμένες με /MD ανακατεμένες σε DLL /MT παράγουν link errors στην καλύτερη περίπτωση και δύο ανεξάρτητους heaps στη χειρότερη, οπότε οι προμηθευμένες βιβλιοθήκες πρέπει να ταιριάζουν με όποια λειτουργία CRT χρησιμοποιεί ο DLL

Τι συμβαίνει ανάμεσα σε ένα TBitmap και μια γραμμή κειμένου;

Το HotPDF παραδίδει στον DLL ένα ανεξάρτητο snapshot BGR top-down της αποδιδομένης σελίδας, και ο DLL παραδίδει πίσω ένα callback ανά αναγνωρισμένη γραμμή κειμένου με δανεικό κείμενο UTF-8 που ο adapter πρέπει να αντιγράψει πριν επιστρέψει

Σε Delphi ο adapter αναθέτει το bitmap της σελίδας σε ιδιωτικό TBitmap, επιβάλλει pf24bit, και διαβάζει γραμμές με GetDIBits χρησιμοποιώντας αρνητικό biHeight, που δίνει γραμμές top-down με γέμισμα σε στοίχιση τεσσάρων bytes· εκείνο το stride περνάει ρητά. Σε FPC διαβάζει μέσω CreateIntfImage, επειδή εγγραφές scanline της LCL μπορούν να ενημερώσουν την ωμή εικόνα χωρίς να ανανεώσουν το handle GDI. Το bitmap του καλούντος δεν τροποποιείται ποτέ, και ο προϋπολογισμός pixels (MaxPixels, 16.777.216 by default και ρυθμιζόμενο έως 67.108.864) και το όριο 32.767 pixels ανά διάσταση ελέγχονται πριν δεσμευτεί ο buffer του snapshot

Αγωγός DLL RapidOCR HotPDF από bitmap σε layer κειμένου: ο adapter σαρώνει τη σελίδα ως pf24bit BGR top-down, ο DLL γεμίζει, ανιχνεύει, ταξινομεί και αναγνωρίζει crops, παραδίδει ένα callback ανά γραμμή με δανεικό κείμενο UTF-8, box και confidence, και ο adapter επικυρώνει κάθε γραμμή πριν τη δέσμευση layer κειμένου
τα pixels διασχίζουν το ABI μία φορά ως snapshot, οι γραμμές επιστρέφουν ένα callback τη φορά, και τίποτα δεν φτάνει στο αναζητήσιμο layer μέχρι κάθε έλεγχος να περάσει

Μέσα στον DLL το snapshot γεμίζει με 50 λευκά pixels, οι περιοχές κειμένου ανιχνεύονται με μέγιστη πλευρά 1.024 pixels, τα boxes ταξινομούνται σε οριζόντιες γραμμές, και κάθε crop προαιρετικά περιστρέφεται από τον classifier γωνίας πριν την αναγνώριση. Κάθε γραμμή κειμένου περνά μετά από callback που λαμβάνει const char*, πλήθος bytes, ακέραιο box σε pixels πρωτότυπης εικόνας, και μέση εμπιστοσύνη χαρακτήρων. Ο δείκτης κειμένου είναι έγκυρος μόνο κατά το callback, οπότε ο adapter τον αντιγράφει αμέσως, και είναι αυστηρός με ό,τι δέχεται:

  • Το UTF-8 αποκωδικοποιείται με MB_ERR_INVALID_CHARS· κακοδιατυπωμένη ακολουθία αποτυγχάνει τη σελίδα αντί να παράγει χαρακτήρες αντικατάστασης σε αναζητήσιμο layer
  • Χαρακτήρες ελέγχου C0 και C1 απορρίπτονται, και γραμμές μόνο με κενά παραλείπονται
  • Το box πρέπει να βρίσκεται μέσα στο bitmap και η εμπιστοσύνη πρέπει να είναι πεπερασμένη τιμή από 0 έως 1
  • Το κείμενο μετράται σε σχέση με το MaxTextCodeUnits του αιτήματος με σκληρό ταβάνι 1.048.576 μονάδες UTF-16 ανά κλήση, και χαρακτήρες supplementary plane κοστίζουν δύο μονάδες
  • Κάθε exception Pascal μέσα στο callback συλλαμβάνεται εκεί, αποθηκεύεται, και γίνεται επιστροφή 0, που κάνει τον DLL να σταματήσει και να αναφέρει αποτυχία· το αποθηκευμένο μήνυμα γίνεται μετά το διαγνωστικό

Δύο συνέπειες μετράνε για tuning. Πρώτον, η μονάδα εξόδου είναι γραμμή, όχι λέξη: κάθε γραμμή καταναλώνει μία θέση MaxWords, τα Info.AcceptedWordCount και Info.DroppedWordCount μετρούν γραμμές, και η επισήμανση αναζήτησης εκτείνεται στο box της γραμμής. Δεύτερον, το MinimumConfidence (0.5 by default) συγκρίνεται με τη μέση εμπιστοσύνη χαρακτήρων της γραμμής, οπότε μια γραμμή με έναν δυσανάγνωστο χαρακτήρα ανάμεσα σε είκοσι καθαρούς συνήθως επιβιώνει. Ο DLL δεν παραδίδει baseline, οπότε ο αγωγός text-layer την εκτιμά από το box. Κενή σελίδα πετυχαίνει με μηδέν γραμμές, και κάθε αποτυχία καθαρίζει μερικά αποτελέσματα ώστε η δέσμευση πολλών σελίδων μένει all-or-nothing

Ιδιοκτησία models και thread safety

Κάθε engine DLL RapidOCR κατέχει ακριβώς ένα instance model για όλη τη ζωή του, και οι κλήσεις Recognize σε εκείνο το engine σειριοποιούνται από critical section. Το κράτημα της διεπαφής IHPDFOCREngine είναι αυτό που κρατά τα models ζεστά, οπότε το σωστό μοτίβο για δουλειά παρτίδας είναι να δημιουργήσετε το engine μία φορά και να το ξαναχρησιμοποιήσετε σε έγγραφα

procedure OcrBatch(const Files: TStrings; const OutputDir: string);
var
  Models: THPDFRapidOCRDLLOptions;
  Engine: IHPDFOCREngine;
  Doc: THotPDF;
  Options: THPDFOCRTextLayerOptions;
  Info: THPDFOCRTextLayerInfo;
  I: Integer;
begin
  Models := THPDFRapidOCRDLLOptions.Default;
  Models.UseAngleClassifier := False;    // όρθιες σαρώσεις: κανένα classifier model δεν φορτώνεται
  Models.Threads := 4;                   // 1..64, περικομμένο στο πλήθος λογικών επεξεργαστών
  Models.TimeoutMilliseconds := 120000;  // ανά κλήση Recognize, συνεργατικό
  Engine := HPDFCreateRapidOCRDLLOCREngine(
    'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models', Models);
  Options := THPDFOCRTextLayerOptions.Default;
  for I := 0 to Files.Count - 1 do
  begin
    Doc := THotPDF.Create(nil);
    try
      Doc.AutoLaunch := False;
      if (Doc.LoadFromFile(Files[I]) > 0) and
        Doc.ApplyLoadedOCRTextLayer([], Engine, Options, Info) then
        Doc.SaveLoadedDocument(IncludeTrailingPathDelimiter(OutputDir) +
          ExtractFileName(Files[I]))
      else
        Writeln(Files[I], ': ', string(Info.Diagnostic));
    finally
      Doc.Free;
    end;
  end;
end;  // η τελευταία reference απελευθερώθηκε: models καταστράφηκαν, μετά ξεφορτώνεται ο DLL

Η τιμή Threads ορίζει τόσο τα πλήθη νημάτων intra-op όσο και inter-op κάθε συνεδρίας ONNX, και ο DLL την περικόπτει στο πλήθος ενεργών επεξεργαστών. Δύο νήματα που μοιράζονται ένα engine δεν τρέχουν παράλληλα· το δεύτερο περιμένει το lock. Εκείνη η αναμονή δεν είναι τυφλό EnterCriticalSection: ο adapter καλεί TryEnterCriticalSection κάθε 25 ms και ελέγχει το token ακύρωσης και την προθεσμία ανάμεσα στις προσπάθειες, οπότε ένα αίτημα σε ουρά μπορεί ακόμα να ακυρωθεί ή να λήξει. Αν χρειάζεστε αληθινό παραλληλισμό, δημιουργήστε ένα engine ανά worker και αποδεχτείτε ότι κάθε engine κρατά το δικό του αντίγραφο των models στη μνήμη

Η σειρά αποσυναρμολόγησης είναι σταθερή από τον destructor του engine: το HPDFRapidOCRDestroy ελευθερώνει πρώτα το instance model, μετά το FreeLibrary ξεφορτώνει τον DLL. Στην εγγενή πλευρά, η αρχικοποίηση models είναι εξίσου προσεκτική· όταν το model αναγνώρισης αποτυγχάνει αφού οι συνεδρίες detector και classifier είχαν ήδη χτιστεί, εκείνες οι συνεδρίες απελευθερώνονται πριν αναφερθεί το σφάλμα, και το πλήθος κλάσεων του dictionary ελέγχεται σε σχέση με την έξοδο του model κατά την αρχικοποίηση αντί στην πρώτη σελίδα

Γιατί δεν μπορεί μια εγγενής κλήση OCR να σκοτωθεί στη μέση inference;

Μια εγγενής κλήση RapidOCR δεν μπορεί να σκοτωθεί στη μέση inference επειδή τρέχει στο νήμα σας, μέσα στη διεργασία σας, στη μέση μιας συνεδρίας ONNX Runtime που δεν δέχεται διακοπή. Η ακύρωση στον adapter DLL του HotPDF είναι επομένως συνεργατική: ο DLL καλεί callback ματαίωσης πριν και μετά την ανίχνευση, μετά την ταξινόμηση, και μετά από κάθε αναγνωρισμένη γραμμή, και σταματά στο πρώτο checkpoint όπου το callback επιστρέφει 0. Μια κλήση ONNX Run που έχει ξεκινήσει θα τελειώσει πρώτα

Οι εναλλακτικές είναι χειρότερες από την αναμονή. Το TerminateThread θα άφηνε το heap lock της CRT, το thread pool του ONNX Runtime, και κάθε κατάσταση OpenCV σε ό,τι κατάσταση τύχαινε να βρίσκονται, δηλητηριάζοντας την υπόλοιπη διεργασία. Το FreeLibrary ενώ μια κλήση ακόμα εκτελείται ξεφορτώνει κώδικα που βρίσκεται στη στοίβα. Κανένα δεν μπορεί να γίνει ασφαλές, οπότε ο adapter δεν τα επιχειρεί ποτέ. Η προθεσμία στο TimeoutMilliseconds είναι επομένως συνεργατική προθεσμία, και ληγμένη προθεσμία εμφανίζεται ως σφάλμα engine με διαγνωστικό timeout, ενώ ακυρωμένο token εμφανίζεται ως otlsCancelled:

// Το Token δημιουργείται από τον καλούντα και μοιράζεται με το νήμα UI,
// που καλεί Token.Cancel όταν ο χρήστης πατήσει Stop
Options := THPDFOCRTextLayerOptions.Default;
Options.CancellationToken := Token;
if not Doc.ApplyLoadedOCRTextLayer([], Engine, Options, Info) then
  case Info.Status of
    otlsCancelled:
      // επιστρέφει στο επόμενο όριο σταδίου ή γραμμής· το έγγραφο αμετάβλητο
      Writeln('Cancelled');
    otlsEngineError:
      // περιλαμβάνει λήξη συνεργατικής προθεσμίας και εγγενή διαγνωστικά
      Writeln('Engine: ', string(Info.Diagnostic));
    otlsBudgetExceeded:
      Writeln('Budget: ', string(Info.Diagnostic));
  else
    Writeln(string(Info.Diagnostic));
  end;

Αυτός είναι ο βασικός συμβιβασμός ανάμεσα στους process adapters του HotPDF και στο in-process DLL, και καμία πλευρά δεν κερδίζει σε κάθε γραμμή:

Ανταλλαγές adapter OCR HotPDF: οι process adapters ξεκινούν worker και φορτώνουν models σε κάθε σελίδα αλλά μπορούν να σκοτωθούν και να περιέχουν crashes, ενώ το in-process DLL RapidOCR φορτώνει models μία φορά, σταματά μόνο σε συνεργατικά checkpoints, μοιράζεται τον χώρο διευθύνσεων, και αναπτύσσεται ως DLL με τα models και το dictionary του
διαλέξτε ανά workload: μια εφαρμογή desktop μια σελίδα τη φορά κερδίζει από το ζεστό DLL, ενώ ένας server που καταπίνει αναξιόπιστες σαρώσεις πρέπει να πληρώσει το τοίχωμα διεργασίας
  • Κόστος εκκίνησης: οι adapters Tesseract και Python RapidOCR εκτοξεύουν διεργασία και φορτώνουν models για κάθε σελίδα· ο DLL φορτώνει models μία φορά ανά engine
  • Σταμάτημα: μια θυγατρική διεργασία μπορεί να τερματιστεί απευθείας, και ο worker Python τρέχει μέσα σε Job Object kill-on-close ώστε όλο το δέντρο διεργασίας του να πάει μαζί· ο DLL μπορεί να σταματήσει μόνο σε όρια σταδίου και γραμμής
  • Περιορισμός σφαλμάτων: ένα crash στο tesseract.exe χάνει μία σελίδα· μια access violation μέσα στον DLL σας ρίχνει τη διεργασία
  • Deployment: οι process adapters θέλουν εγκατεστημένο πρόγραμμα ή περιβάλλον Python· ο DLL θέλει τον εαυτό του, τα models του, και το dictionary του, ταιριασμένα στο bitness της εφαρμογής
  • Μνήμη: οι process adapters απελευθερώνουν τα πάντα όταν η θυγατρική εξέρχεται· ένας engine DLL κρατά τα models του μόνιμα μέχρι η τελευταία διεπαφική reference να απελευθερωθεί

Για διαδραστική εφαρμογή desktop που κάνει OCR μία σελίδα τη φορά, η ανταπόκριση του DLL συνήθως κερδίζει. Για server που καταπίνει αναξιόπιστες σαρώσεις νύχτα και μέρα, το όριο διεργασίας αξίζει το κόστος εκκίνησής του

Χτίσιμο και ανάπτυξη του HotPDFRapidOCR.dll

Το HotPDFRapidOCR.dll χτίζεται από τις πηγές C++ στο Native/RapidOCR με MSVC, C++17, Windows SDK, και CMake 3.20 ή νεότερο, χρησιμοποιώντας βοηθητικό script που παίρνει τους εγγενείς καταλόγους network sources, ONNX Runtime, και OpenCV συν πλατφόρμα Win32 ή Win64. Χτίστε και τα δύο αν παραδίδετε και τα δύο, επειδή μια εφαρμογή Delphi 32 bit δεν μπορεί να φορτώσει DLL 64 bit, και οι στατικές βιβλιοθήκες που προμηθεύετε πρέπει να ταιριάζουν την αρχιτεκτονική στόχο καθώς και τη λειτουργία CRT

Η πλευρά models έχει τα δικά της όρια συμβατότητας. Ο detector είναι text detector DB· ο recognizer δέχεται models CTC σε διάταξη NCHW με σταθερό ύψος εισόδου 32 ή 48, και χρησιμοποιεί 48 για models με δυναμικό ύψος. Το δέμα static ONNX Runtime δεν μπορεί να φορτώσει models αποθηκευμένα με νεότερη έκδοση IR, οπότε πρόσφατα exports PP-OCRv5 αποτυγχάνουν αρχικοποίηση με διαγνωστικό αντί να φορτώσουν μερικώς. Το dictionary πρέπει να είναι UTF-8 χωρίς BOM, σε ακριβώς τη σειρά χαρακτήρων του model, και το πλήθος κλάσεων του πρέπει να ταιριάζει την έξοδο του model· τα line endings CRLF γίνονται δεκτά. Η αναγνώριση είναι offline: ο DLL δεν κατεβάζει ποτέ λείπον model

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

  • Factory: HPDFCreateRapidOCRDLLOCREngine(LibraryPath, ModelDirectory[, Options]) στο HPDFRapidOCRRecognition, διαθέσιμο από το v2.774.0 σε builds Delphi, C++Builder, και Windows FPC/Lazarus
  • Κρατήστε το επιστρεφόμενο IHPDFOCREngine ζωντανό σε σελίδες και έγγραφα· η απελευθέρωσή του καταστρέφει τα models και ξεφορτώνει τον DLL
  • Ένα engine τρέχει μία αναγνώριση τη φορά· δημιουργήστε αρκετά engines για παράλληλους workers και προϋπολογίστε μνήμη για κάθε αντίγραφο model
  • Η έξοδος είναι μία εγγραφή ανά γραμμή κειμένου με μέση εμπιστοσύνη χαρακτήρων, φιλτραρισμένη από THPDFOCRTextLayerOptions.MinimumConfidence
  • Η ακύρωση και το TimeoutMilliseconds είναι συνεργατικά· ένα τρέχον ONNX πάντα ολοκληρώνεται
  • Ταιριάξτε το bitness του DLL με την εφαρμογή και τη λειτουργία CRT των static βιβλιοθηκών ONNX Runtime και OpenCV με τον DLL
  • Διαλέξτε γλωσσικό προφίλ ανά engine με THPDFRapidOCRDLLOptions.ForLanguage (v2.775.0)· ένα engine δεν ανιχνεύει γλώσσες μόνο του

Ο εγγενής adapter RapidOCR, οι adapters OCR βάσει διεργασίας, ο renderer σελίδων που τους τροφοδοτεί, και ο writer αόρατου text-layer Unicode έρχονται όλοι μαζί στο HotPDF, ένα εγγενές VCL PDF component για Delphi και C++Builder. Αν η εφαρμογή καταγραφής ή αρχειοθέτησης εγγράφων σας θέλει αναζητήσιμη έξοδο χωρίς runtime Python στο μηχάνημα στόχο, το HotPDF Delphi PDF component παραδίδει όλο τον αγωγό με μόνο τον DLL και τα models του να απομένουν για ανάπτυξη