Το HotPDF εκτελεί κινεζικό και πολύγλωσσο OCR σε Delphi μέσω του εγγενή adapter του για DLL RapidOCR: το THPDFRapidOCRDLLOptions.ForLanguage αντιστοιχίζει γλωσσική ετικέτα όπως 'zh-CN', 'zh-TW', 'ru' ή 'ar' σε ταιριασμένο model αναγνώρισης και character dictionary, και το THotPDF.ApplyLoadedOCRTextLayer γυρνά τις αναγνωρισμένες γραμμές σε αόρατο, αναζητήσιμο text layer Unicode πάνω σε σαρωμένες σελίδες PDF
Το να δουλέψει ένα demo λατινικής γραφής είναι το εύκολο κομμάτι. Οι ενδιαφέρουσες αποτυχίες ξεκινούν όταν αλλάξετε σε Παραδοσιακά Κινεζικά ή Ρωσικά και η έξοδος γίνεται σίγουρο, καλογραμμένο αλαμπουρνέζικο, ή όταν κάθε γραμμή χάνει αθόρυβα τον τελευταίο της χαρακτήρα, ή όταν μια αραβική σελίδα επιστρέφει με τα text boxes της σε λάθος σειρά. Κανένα από αυτά δεν πετά exception από μόνο του. Τα γλωσσικά presets που πρόσθεσε το HotPDF v2.775.0 υπάρχουν ως επί το πλείστον για να κλείσουν εκείνα τα κενά, και οι τέσσερις παγίδες παρακάτω αξίζει να τις κατανοήσετε ακόμα κι αν δεν αγγίξετε ποτέ τον εγγενή κώδικα, επειδή καθεμιά εξηγεί ένα σύμπτωμα που αλλιώς θα κυνηγούσατε μια ολόκληρη μέρα
Πώς διαλέγει το ForLanguage model και dictionary;
Το THPDFRapidOCRDLLOptions.ForLanguage λύνει μια ετικέτα σε ένα από εννέα προφίλ και επιστρέφει options που δείχνουν σε <profile>/recognition.onnx και <profile>/dictionary.txt κάτω από τον κατάλογο models σας, κρατώντας τον κοινό detector, τον προαιρετικό classifier γωνίας, και τις προεπιλογές νημάτων, pixels και timeout από το THPDFRapidOCRDLLOptions.Default. Η μέθοδος μικραίνει το tag, γυρνά underscores σε hyphens και κόβει περιβάλλοντα κενά, οπότε 'zh_TW', 'ZH-tw' και ' zh-tw ' προσγειώνονται όλα στο ίδιο προφίλ. Τα aliases είναι ρητή λίστα και όχι prefix match: το 'zh-Hant-TW' γίνεται δεκτό επειδή απαριθμείται, ενώ αυθαίρετη περιφερειακή παραλλαγή που δεν απαριθμείται πετά EArgumentException πριν φορτώσει οποιοδήποτε model
| Προφίλ | Γλώσσες | Παραδείγματα ετικετών | Καρφωμένο model |
|---|---|---|---|
ch | Απλοποιημένα Κινεζικά και Αγγλικά | zh, zh-CN, zh-Hans, chi_sim | PP-OCRv4 |
chinese_cht | Παραδοσιακά Κινεζικά | zh-TW, zh-HK, zh-Hant, chi_tra | PP-OCRv3 |
en | Αγγλικά | en, en-US, en-GB, eng | PP-OCRv4 |
latin | Γαλλικά, Γερμανικά, Ισπανικά, Πορτογαλικά, Ιταλικά, Ολλανδικά, Τουρκικά | fr, de, es-419, pt-BR, tr | PP-OCRv3 |
japan | Ιαπωνικά | ja, ja-JP, jpn | PP-OCRv4 |
korean | Κορεατικά | ko, ko-KR, kor | PP-OCRv4 |
cyrillic | Ρωσικά, Ουκρανικά, Βουλγαρικά, Λευκορωσικά | ru, ru-RU, uk, bg | PP-OCRv3 |
arabic | Αραβικά, Περσικά, Ουρντού | ar, ar-SA, fa, ur | PP-OCRv4 |
devanagari | Χίντι, Μαράθι, Νεπάλι | hi, mr, ne | PP-OCRv4 |
Ο adapter ο ίδιος δεν κατεβάζει ποτέ τίποτα. Προμηθεύεστε τα αρχεία μία φορά με το δέμα βοηθός, για παράδειγμα tools/Install-RapidOCRModels.ps1 -Destination C:/OCR/models -Language ch,chinese_cht,cyrillic (ή -Language All για όλα τα εννέα προφίλ), και ο βοηθός τοποθετεί κοινό detector και classifier στα ονόματα αρχείων ρίζας που περιμένει το Default. Μετά από εκεί, μια σάρωση Απλοποιημένων Κινεζικών γίνεται αναζητήσιμη με λίγες γραμμές. Η υδραυλική του engine είναι η ίδια ραφή IHPDFOCREngine που περιγράφεται στο άρθρο για το in-process DLL RapidOCR και το ABI όριο του, οπότε αυτό μεντά και εστιάζει στις γλώσσες
uses
SysUtils, HPDFDoc, HPDFRapidOCRRecognition;
procedure MakeChineseScanSearchable(const SourceFile, TargetFile: string);
var
Doc: THotPDF;
Engine: IHPDFOCREngine;
Models: THPDFRapidOCRDLLOptions;
Layer: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
// ch/recognition.onnx + ch/dictionary.txt, κοινός detector και classifier
Models := THPDFRapidOCRDLLOptions.ForLanguage('zh-CN');
Engine := HPDFCreateRapidOCRDLLOCREngine(
'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models', Models);
Doc := THotPDF.Create(nil);
try
Doc.AutoLaunch := False;
if Doc.LoadFromFile(SourceFile) < 1 then
raise Exception.Create('Cannot load ' + SourceFile);
Layer := THPDFOCRTextLayerOptions.Default; // 300 DPI, MinimumConfidence 0.5
// κενή λίστα σελίδων σημαίνει κάθε σελίδα· σελίδες που έχουν ήδη κείμενο παραλείπονται
if not Doc.ApplyLoadedOCRTextLayer([], Engine, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
Writeln(string(Info.EngineName), ': ', Info.AcceptedWordCount,
' lines, ', Info.UniqueScalarCount, ' distinct characters');
Doc.SaveLoadedDocument(TargetFile);
finally
Doc.Free;
end;
end;
Δύο λεπτομέρειες σε εκείνη την έξοδο αξίζουν σημείωση. Ο εγγενής αγωγός επιστρέφει ένα αποτέλεσμα ανά ανιχνευθείσα γραμμή κειμένου, όχι ανά λέξη, οπότε το AcceptedWordCount μετρά εδώ γραμμές, και το MinimumConfidence συγκρίνεται με τη μέση εμπιστοσύνη χαρακτήρων όλης της γραμμής: γραμμή με μέσο όρο 0.45 απορρίπτεται ως μονάδα. Το UniqueScalarCount αναφέρει πόσα ξεχωριστά Unicode scalars χρειάστηκε να χαρτογραφήσει το text layer στη γραμματοσειρά του και στον πίνακα ToUnicode του, χρήσιμος έλεγχος υγείας ότι CJK κείμενο έφτασε πραγματικά αντί για μια χούφτα Λατινικά fallbacks. Κρατήστε τη διεπαφή engine ζωντανή σε έγγραφα επειδή η αρχικοποίηση models γίνεται στο factory και είναι το ακριβό βήμα
Γιατί η αλλαγή μόνο του model αναγνώρισης παράγει σκουπίδια;
Ένα model αναγνώρισης CTC δεν εξάγει ποτέ χαρακτήρες, μόνο δείκτες κλάσεων, και το dictionary είναι το μοναδικό πράγμα που γυρνά τον δείκτη 1.204 σε glyph. Ανταλλάξτε το ch/recognition.onnx με το cyrillic/recognition.onnx αλλά κρατήστε το κινεζικό dictionary, και το model θα εκπέμψει ευχαρίστως έγκυρους κυριλλικούς δείκτες που το παλιό dictionary μεταφράζει σε τυχαίους χαρακτήρες Han. Το αποτέλεσμα μοιάζει με κείμενο, περνά επικύρωση UTF-8, και είναι αναζητήσιμο για το τίποτα ακριβώς. Γι αυτό το ForLanguage ορίζει πάντα RecognitionModel και CharacterDictionary μαζί, και γι αυτό χειροποίητα options δεν πρέπει ποτέ να αλλάξουν το ένα χωρίς το άλλο
Ο φανερός έλεγχος ασφαλείας, η σύγκριση του μεγέθους dictionary με το πλάτος εξόδου του model, είναι απαραίτητος αλλά όχι επαρκής. Δύο dictionaries μπορούν να έχουν τον ίδιο αριθμό εγγραφών σε διαφορετική σειρά, και μια απόκλιση κατά ένα στη σειρά μετατοπίζει κάθε χαρακτήρα κατά ένα code point. Το HotPDF ελέγχει λοιπόν σε δύο στάδια όταν το factory αρχικοποιεί το model. Πρώτον, το πλήθος κλάσεων εξόδου πρέπει να ισούται με τις εγγραφές dictionary συν δύο. Δεύτερον, όταν το αρχείο ONNX ενσωματώνει λίστα μεταδεδομένων character, κάθε εγγραφή dictionary συγκρίνεται μαζί της με τη σειρά, και ασυμφωνία αποτυγχάνει την αρχικοποίηση με EInvalidOperation και εγγενές διαγνωστικό αντί να παράγει πειστικά σκουπίδια αργότερα
Το "συν δύο" προέρχεται από τη διάταξη κλάσεων. Η κλάση 0 είναι το CTC blank, οι κλάσεις 1 έως N είναι οι γραμμές dictionary σε σειρά αρχείου, και η τελική κλάση είναι κενό. Μερικά dictionaries κουβαλάνε επίσης δική τους εγγραφή κενού, και εκείνη η γραμμή πρέπει να κρατηθεί ακριβώς όπως είναι. Εδώ ένα καλόβουλο Trim κάνει πραγματική ζημιά: γυρνά εγγραφή ενός μόνο κενού σε κενή συμβολοσειρά και μετατοπίζει ή σπάει τον πίνακα. Η μοναδική κανονικοποίηση που είναι ασφαλής είναι η αφαίρεση trailing carriage return, ώστε dictionary αποθηκευμένο με line endings CRLF να φορτώνει σωστά, ενώ BOM UTF-8, κενή γραμμή, ή εγγραφή που περιέχει tab απορρίπτεται. Το σκίτσο παρακάτω δείχνει τη διάταξη σε Pascal· είναι επεξηγηματικός κώδικας, όχι API του HotPDF
// Μόνο για επίδειξη: ο πίνακας κλάσεων που περιμένει recognizer CTC
uses
SysUtils, IOUtils;
function BuildCTCClassTable(const FileName: string): TArray<string>;
var
Text, Entry: string;
Lines: TArray<string>;
I, Last: Integer;
begin
Text := TEncoding.UTF8.GetString(TFile.ReadAllBytes(FileName));
if (Text <> '') and (Text[1] = #$FEFF) then
raise EArgumentException.Create('Dictionary must be UTF-8 without a BOM');
Lines := Text.Split([#10]);
Last := High(Lines);
if (Last >= 0) and (Lines[Last] = '') then
Dec(Last); // newline στο τέλος του αρχείου
SetLength(Result, Last + 3);
Result[0] := ''; // κλάση 0: CTC blank
for I := 0 to Last do
begin
Entry := Lines[I];
if (Entry <> '') and (Entry[Length(Entry)] = #13) then
SetLength(Entry, Length(Entry) - 1); // CRLF: πέστε μόνο το CR
if (Entry = '') or (Pos(#9, Entry) > 0) then
raise EArgumentException.Create('Invalid dictionary entry');
Result[I + 1] := Entry; // ποτέ Trim: το ' ' είναι κλάση
end;
Result[Last + 2] := ' '; // τελική κλάση: κενό
// Το Length(Result) πρέπει να ισούται με το πλήθος κλάσεων εξόδου του model
end;
Τι κάνει στην πραγματικότητα η πεινασμένη αποκωδικοποίηση CTC;
Η πεινασμένη αποκωδικοποίηση CTC διαλέγει την υψηλότερα βαθμολογημένη κλάση σε κάθε βήμα χρόνου, καταρρέει διαδοχικές επαναλήψεις σε έναν χαρακτήρα, και πετά την κλάση blank· το blank είναι ό,τι επιτρέπει σε γνήσια διπλασιασμένα γράμματα να επιβιώσουν. Ένα model αναγνώρισης κοιτάζει μια γραμμή κειμένου ως αλληλουχία στενών κάθετων τομών, και για κάθε τομή, ή βήμα χρόνου, εξάγει πιθανότητα για κάθε κλάση. Μια γραμμή που περιέχει AA中 μπορεί να παράγει αλληλουχία argmax A A blank A 中 space. Η κατάρρευση των δύο πρώτων βημάτων A δίνει ένα A, το blank το χωρίζει από το επόμενο A, και το αποτέλεσμα είναι AA中 με το trailing space ανέπαφο. Χωρίς τον κανόνα blank, το book και το bok θα ήταν αδιαχώριστα
Επειδή ο decoder είναι μόνο μια ντουζίνα γραμμές, είναι εύκολο να πάρεις λάθος τα όρια, και οι αποτυχίες είναι αθόρυβες. Αν ο εσωτερικός βρόχος argmax σταματήσει μία κλάση νωρίτερα, η κλάση κενού δεν μπορεί ποτέ να κερδίσει και κάθε γραμμή επιστρέφει χωρίς κενά λέξεων, που γκρεμίζει αναζήτηση φράσεων σε σελίδες Αγγλικών και Λατινικών. Αν ο εξωτερικός βρόχος σταματήσει ένα βήμα χρόνου νωρίτερα, ο τελευταίος χαρακτήρας κάθε γραμμής εξαφανίζεται, που για σύντομη γραμμή μπορεί να είναι το ένα τρίτο του κειμένου. Και αν ο φρουρός επανάληψης δεν μηδενίζεται από blank, διπλασιασμένοι χαρακτήρες όπως ll ή κινεζικές επαναλήψεις όπως 谢谢 καταρρέουν σε έναν. Ο decoder του HotPDF συμπεριλαμβάνει την τελευταία κλάση και το τελευταίο βήμα χρόνου, κρατά επαναλήψεις χωρισμένες από blank, και απορρίπτει επιπλέον βαθμολογίες που δεν είναι πεπερασμένες ή πέφτουν έξω από 0 έως 1, και οποιοδήποτε πλήθος κλάσεων που δεν ταιριάζει το dictionary. Ορίστε η ίδια λογική ως Pascal επίδειξη
// Μόνο για επίδειξη: πεινασμένη αποκωδικοποίηση CTC με σωστά όρια.
// Το Scores κρατά Steps * Classes πιθανότητες, μία γραμμή ανά βήμα χρόνου
function GreedyCTCDecode(const Scores: array of Single;
Steps, Classes: Integer; const Characters: array of string): string;
var
Step, C, Best, Previous: Integer;
BestScore: Single;
begin
if (Classes < 3) or (Length(Characters) <> Classes) or
(Length(Scores) <> Steps * Classes) then
raise EArgumentException.Create('Model output does not match the dictionary');
Result := '';
Previous := 0; // η κλάση 0 είναι το CTC blank
for Step := 0 to Steps - 1 do // συμπεριλάβετε το τελευταίο βήμα χρόνου
begin
Best := 0;
BestScore := Scores[Step * Classes];
for C := 1 to Classes - 1 do // συμπεριλάβετε την τελευταία κλάση (κενό)
if Scores[Step * Classes + C] > BestScore then
begin
Best := C;
BestScore := Scores[Step * Classes + C];
end;
if (Best <> 0) and (Best <> Previous) then
Result := Result + Characters[Best];
Previous := Best; // ένα blank μηδενίζει τον φρουρό επανάληψης
end;
end;
Η πεινασμένη αποκωδικοποίηση δεν είναι η πιο ακριβής διαθέσιμη στρατηγική CTC· beam search με γλωσσικό model μπορεί να διορθώσει μερικές αμφίβολες τομές. Για τυπωμένα έγγραφα στα 300 DPI το πεινασμένο αποτέλεσμα είναι συνήθως ό,τι έχει να προσφέρει το model, και ο decoder δεν είναι το μέρος για να αναπληρώσετε αδυναμίες model. Το λατινικό model PP-OCRv3, για παράδειγμα, μπορεί να διαβάσει το ñ ως n ακόμα και σε καθαρή είσοδο. Το HotPDF δεν το κουκουλώνει με post-processing αντικαταστάσεις χαρακτήρων, επειδή πίνακας υποκατάστασης που διορθώνει Ισπανικά σπάει κάτι άλλο, και λάθος χαρακτήρας σε αναζητήσιμο layer είναι χειρότερος από τίμια αστοχία
Πώς ταξινομεί το HotPDF γραμμές κειμένου, συμπεριλαμβανομένου αραβικού από δεξιά προς αριστερά;
Το HotPDF ταξινομεί ανιχνευμένα text boxes από πάνω προς τα κάτω, ομαδοποιεί boxes σε γραμμή όταν αλληλοκαλύπτονται κατακόρυφα κατά τουλάχιστον το μισό του ύψους του μικρότερου box, και ταξινομεί κάθε γραμμή αριστερά προς δεξιά, ή δεξιά προς αριστερά όταν το RightToLeft είναι ενεργό· οι χαρακτήρες μέσα σε κάθε αναγνωρισμένη γραμμή δεν αντιστρέφονται ποτέ. Η ομαδοποίηση μετράει επειδή ένας detector συχνά σπάει μία οπτική γραμμή σε αρκετά boxes, για παράδειγμα ετικέτα και τιμή χωρισμένες από φαρδύ κενό, και καθαρή ταξινόμηση κατά πάνω συντεταγμένη θα τις πλέκουσε με τη γειτονική γραμμή όποτε τα πάνω τους διαφέρουν κατά ένα δύο pixels
Το αραβικό preset θέτει RightToLeft := True, που λέει στον DLL να ταξινομεί τα boxes κάθε γραμμής κατά το δεξί τους άκρο, από το δεξί περιθώριο προς τα μέσα. Αυτό είναι όλο το αποτέλεσμα. Το κείμενο που επιστρέφει το model για μια γραμμή είναι ήδη σε Unicode λογική σειρά, τη σειρά που διαβάζει και πληκτρολογεί ένας Αραβόφωνος αναγνώστης, και εκείνη είναι επίσης η σειρά που περιμένουν η εξαγωγή και η αναζήτηση PDF κειμένου. Η μηχανική αντιστροφή της συμβολοσειράς για να "φαίνεται σωστή" σε debugger θα έσπασε αναζήτηση, αντιγραφή και επικόλληση, και screen readers. Η αμφίδρομη προβολή και το glyph shaping είναι δουλειά του viewer
Ένα engine εξυπηρετεί ένα γλωσσικό προφίλ. Δεν υπάρχει αυτόματη ανίχνευση γραφής, οπότε έγγραφο που αναμειγνύει γραφές θέλει ένα engine ανά προφίλ, εφαρμοσμένο στις σελίδες που το χρησιμοποιούν. Επειδή το ApplyLoadedOCRTextLayer παίρνει ρητή λίστα σελίδων και δεσμεύει κάθε κλήση ως δική της all-or-nothing συναλλαγή, είναι ευθύγραμμο
uses
SysUtils, HPDFDoc, HPDFRapidOCRRecognition;
function CreateRapidEngine(const Tag: string): IHPDFOCREngine;
var
Models: THPDFRapidOCRDLLOptions;
begin
// πετά EArgumentException για άγνωστη ετικέτα, πριν φορτώσει οποιοδήποτε model
Models := THPDFRapidOCRDLLOptions.ForLanguage(Tag);
Models.MaxPixels := 33554432; // χώρος για σελίδες A3 στα 300 DPI
Result := HPDFCreateRapidOCRDLLOCREngine(
'C:\OCR\Win64\HotPDFRapidOCR.dll', 'C:\OCR\models', Models);
end;
procedure OCRMixedArchive(Doc: THotPDF);
var
Chinese, Arabic: IHPDFOCREngine;
Layer: THPDFOCRTextLayerOptions;
Info: THPDFOCRTextLayerInfo;
begin
Chinese := CreateRapidEngine('zh-TW'); // προφίλ chinese_cht
Arabic := CreateRapidEngine('ar-SA'); // προφίλ arabic, RightToLeft = True
Layer := THPDFOCRTextLayerOptions.Default;
if not Doc.ApplyLoadedOCRTextLayer([0, 1, 2], Chinese, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
if not Doc.ApplyLoadedOCRTextLayer([3], Arabic, Layer, Info) then
raise Exception.Create(string(Info.Diagnostic));
end;
Η γραμμή MaxPixels είναι εκεί για κάποιο λόγο. Τα options του DLL προεπιλέγονται σε 16.777.216 pixels ανά αίτημα, που καλύπτει A4 και US Letter στα 300 DPI άνετα, αλλά μια σελίδα A3 στα 300 DPI είναι περίπου 3508 επί 4961 pixels, γύρω στα 17,4 εκατομμύρια, και το αίτημα απορρίπτεται ως εκτός προϋπολογισμού. Ανασηκώστε το MaxPixels (το ταβάνι είναι 67.108.864) ή χαμηλώστε το THPDFOCRTextLayerOptions.DPI για μεγάλα formats. Η ταξινόμηση από δεξιά προς αριστερά χρησιμοποιεί το προαιρετικό export HPDFRapidOCRSetReadingDirection της έκδοσης ABI 1· ο adapter το απαιτεί μόνο όταν είναι ορισμένο το RightToLeft, οπότε παλαιότερος DLL εξακολουθεί να σερβίρει γλώσσες αριστερά-προς-δεξιά και αποτυγχάνει στη δημιουργία engine με EArgumentException που κατονομάζει το λείπον export για Αραβικά
Γιατί νεότερα OCR models αποτυγχάνουν να φορτώσουν;
Το DLL RapidOCR του HotPDF συνδέει static ONNX Runtime 1.14, που δεν μπορεί να διαβάσει models αποθηκευμένα με ONNX IR έκδοση 10, και νεότερα exports όπως models PP-OCRv5 μπορεί να απαιτούν νεότερο runtime από εκείνο· τέτοιο model αποτυγχάνει στη δημιουργία engine με εγγενές διαγνωστικό. Εκείνος ο περιορισμός είναι ο λόγος που τα γλωσσικά πακέτα είναι καρφωμένα σε συγκεκριμένα ζεύγη recognizer και dictionary PP-OCRv3 και PP-OCRv4 αντί για "τελευταία", και γιατί ο πίνακας παραπάνω αναμειγνύει τις δύο γενιές: κάθε καρφωμένο ζεύγος είναι ένα που φορτώνει και επαληθεύεται κάτω από εκείνο το runtime"
Ο installer επιβάλλει το ζευγάρωμα. Κάθε αρχείο στο manifest του κουβαλά hash SHA256, υπάρχον αρχείο με διαφορετικό hash σταματά την εγκατάσταση αντί να ξαναγραφτεί, και κάθε λήψη προσγειώνεται κάτω από προσωρινό όνομα και μετακινείται στη θέση της μόνο αφού το hash της ταιριάξει. Εκείνο προστατεύει από την αθόρυβη εκδοχή του προβλήματος dictionary: κάποιος ρίχνει νεότερο recognition.onnx σε φάκελο προφίλ στο χέρι, το πλήθος κλάσεων τυχαίνει να ταιριάζει, και τίποτα δεν αποτυγχάνει μέχρι ένας πελάτης να αναφέρει ότι η αναζήτηση δεν βρίσκει λέξεις που βλέπει φανερά. Σε χρόνο εκτέλεσης ο adapter μένει offline και δεν αντλεί ποτέ λείπον model. Ο recognizer επικυρώνει επίσης το σχήμα του model στη φόρτωση, δέχεται είσοδο NCHW με σταθερό ύψος 32 ή 48 pixels ή δυναμικό ύψος, που το τρέχει στα 48
Αν χρειάζεστε γραφή που κανένα από τα εννέα προφίλ δεν καλύπτει, μπορείτε ακόμα να δείξετε τα RecognitionModel και CharacterDictionary στα δικά σας αρχεία. Οι ίδιοι έλεγχοι ισχύουν, που είναι και το νόημα: λάθος ζευγαρωμένο ζεύγος αποτυγχάνει στην αρχικοποίηση, όχι στο αρχείο του πελάτη σας. Για σελίδες όπου κανένα προφίλ RapidOCR δεν ταιριάζει, το adapter Tesseract για αναζητήσιμο PDF μπαίνει στην ίδια κλήση ApplyLoadedOCRTextLayer, και για φόρμες ASCII μηχανόγραφου το built-in engine OCR template-matching δεν θέλει καθόλου models
Σύντομη αναφορά: λίστα ελέγχου multilingual RapidOCR
- Δημιουργήστε options με
THPDFRapidOCRDLLOptions.ForLanguageκαι μεταχειριστείτεEArgumentExceptionως μη υποστηριζόμενη ετικέτα, όχι ως σφάλμα runtime - Αλλάξτε
RecognitionModelκαιCharacterDictionaryμαζί, ποτέ το ένα μόνο· ίσα πλήθη κλάσεων δεν αποδεικνύουν ίση σειρά χαρακτήρων - Κρατήστε dictionaries ως UTF-8 χωρίς BOM, μην κάνετε ποτέ trim εγγραφές, και περιμένετε το model να έχει N + 2 κλάσεις: blank, N εγγραφές, κενό
- Ένας custom decoder CTC πρέπει να καλύπτει την τελευταία κλάση και το τελευταίο βήμα χρόνου και να κρατά επαναλήψεις χωρισμένες από blank
- Χρησιμοποιήστε ένα engine ανά γλωσσικό προφίλ και περάστε ρητές λίστες σελίδων για έγγραφα μικτών γραφών
- Το
RightToLeftαλλάζει μόνο τη σειρά boxes· το αναγνωρισμένο κείμενο μένει σε Unicode λογική σειρά - Εγκαταστήστε models με
Install-RapidOCRModels.ps1ώστε τα pins SHA256 να κρατούν το ζευγάρωμα model και dictionary· θέστεUseAngleClassifier := Falseαν εγκαταστήσατε με-SkipClassifier - Ανασηκώστε το
MaxPixelsπάνω από την προεπιλογή 16.777.216 πριν τρέξετε σελίδες A3 ή μεγαλύτερες στα 300 DPI
Τα γλωσσικά presets RapidOCR, ο εγγενής adapter DLL και ο αγωγός OCR text layer είναι μέρος του HotPDF Delphi PDF Component για Delphi, C++Builder και Windows FPC/Lazarus, ξεκινώντας από το v2.775.0 για τα πολύγλωσσα προφίλ