AfArcFileXmlTextRead
![]() |
|||||||||||||||||
AfArcFileXmlTextRead(handle1, int2) : int | |||||||||||||||||
Positionen des erkannten Textes | |||||||||||||||||
|
Mit der Funktion kann in einem Ereignis nach Texterkennung die Positionsinformationen zum erkannten Text eingelesen werden.
Bei der Verwendung des Office-Server der vorhergehenden Generation (Version 4.0.x), werden die Positionsinformationen nur dann erstellt, wenn in der Datei afocr.cfg die Einträge PdfRecognition=3 und OcrCreateXml=1 vorhanden sind.
Die Positionsinformationen stehen nur zur Verfügung, wenn eine Texterkennung durch die OCR-Software erfolgt und in den Einstellungen für den Datentyp die Einstellung "Text mit Position" aktiviert ist.
Im Parameter (int1) muss der Deskriptor eines zuvor mit AfMemAllocate() angelegten Memory-Objekts übergeben werden. In (int2) wird die Seitennummer angeben.
Nach erfolgreicher Ausführung der Anweisung befindet sich ein XML-Dokument im Memory-Objekt. Das Objekt kann mit der Anweisung XmlLoad() (siehe CONZEPT 16 Hilfe) in eine XML-Struktur überführt werden. Im folgenden Beispiel wird das Memory-Objekt in eine externe Datei geschrieben.
Beispiel:
tMemory # AfMemAllocate(_MemAutosize); tMemory->spCharset # _CharSetUTF8; tFile # FsiOpen('c:\temp\ocrtextpositions.xml',_FsiStdWrite); tResult # AfArcFileXmlTextRead(tMemory,1); tResult # FsiWriteMem(tFile,tMemory,1,tMemory->spLen); tFile->FsiClose(); tMemory->MemFree();
Die Datei kann zu Debug-Zwecken ausgewertet werden.
Aufbau der XML-Struktur
- Kopf-Daten
Im Kopfbereich der XML-Struktur befinden sich allgemeine Informationen zu dem Dokument. In dem Eintrag source befinden sich der Dateiname (Attribut file), die horizontale und vertikale Auflösung (dpix, dpiy) und die Größe der Seite (sizex, sizey). Die Größe einer Seite wird berechnet, indem die Punkte durch die DPI geteilt werden (Größe in Zoll) und das Ergebnis mit 25,4 multipliziert wird (Größe in Millimeter).
<?xml version="1.0"?> <!--XML document generated using OCR technology from Nuance Communications, Inc.--> <document xmlns="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <summary> </summary> <page ocr-vers="OmniPageCSDK16" app-vers="ArcFlow"> <description backColor="ffffff"> <source file="..." dpix="400" dpiy="400" sizex="3307" sizey="4678"/> <theoreticalPage size="Custom" marginLeft="0" marginTop="0" marginRight="0" marginBottom="0" width="3307" height="4678"/> </description>
In dem obigen Beispiel ist die Seite 210 mm breit (sizex/dpix*25,4 = 3307/400*25,4 = 209,9945) und 297 mm hoch (sizey/dpiy*25,4 = 4678/400*25,4 = 297,053).
- Textbereiche
Die Seite wird hierarchisch in verschiedenen Bereiche aufgeteilt. Auf oberster Ebene sind das Textbereiche (textZone). Diese werden in Zeilen (ln) und dann weiter in Worte (wd) aufgeteilt. Im Wortbereich befindet sich dann das erkannte Wort (run).
<zones> <textZone l="853" t="853" r="4601" b="1364" fillingMethod="omnifont" recognitionModule="omnifontPlus2w" chrFilter="all"> <ln l="853" t="853" r="4597" b="1361" baseLine="1354" bold="true" underlined="none" fontSize="3400"> <wd l="853" t="853" r="4597" b="1361"><run backColor="ffffff" language="de"> Produktinfo</run> </wd> <space/> </ln> </textZone> ... <zones>
In diesem Beispiel befindet sich in dem Textbereich nur eine Zeile mit dem Wort "Produktinfo". Weitere Textbereiche sind aus Gründen der Übersichtlichkeit ausgeblendet.
Wird eine Tabelle erkannt, befindet sich im Textbereich eine weitere Unterteilung in Spalten (cellZone). Diese wird dann weiter in Zeilen und Wöter aufgeteilt.
Die Position eines Textbereiches, einer Zeile oder eines Wortes kann über die Attribute l, t, r und b ermittelt werden. Die Angabe erfolgt in Twips (1 Twip = 1/1440 Zoll). Die Werte können mit 25,4/1440 multipliziert werden, um Werte in Millimeter zu erhalten. Die Werte entsprechen dem Abstand vom linken bzw. vom oberen Seitenrand.
Der Begriff "Produktinfo" befindet sich im Bereich 15-81 mm vom linken Rand und 15-24 mm vom oberen Rand.
- Abschluss der Datei
In dem Abschnitt werden die öffnenden Tags aus dem Kopf-Bereich geschlossen.
</page> </document>
Verarbeitung von XML-Strukturen
Nachdem der XML-Text in ein Memory-Objekt übertragen wurde, kann er mit der Anweisung (siehe CONZEPT 16 Hilfe) in eine XML-Struktur überführt werden. Soll lediglich das erste Vorkommen eines Begriffes und dessen Position ermittelt werden, kann auch das Memory-Objekt durchsucht und die entsprechende Textstelle ausgewertet werden. Bei komplexeren Aufgaben empfiehlt sich die Verwendung der XML-Struktur.
local { tResult : int; tMemory : handle; tXmlDoc : handle; } { tMemory # AfMemAllocate(_MemAutoSize); tMemory->spCharset # _CharsetUTF8; tResult # AfArcFileXmlTextRead(tMemory,1); // first Page if (tResult != _ErrOk) { // Error handling ... tMemory->MemFree(); return; } tXmlDoc # AfCteOpen(_CteNode, _CteChildList | _CteAttribList | _CteAttribTree); tResult # tXmlDoc->XmlLoad('',0,tMemory); tMemory->MemFree(); if (tResult != _ErrOk) { // Error handling ... tXmlDoc->AfCteCloseAll(); } ... }
Beispiel:
Die folgende Funktion gibt das Wort zurück, das an einer bestimmten Stelle auf der Seite steht. Die Position des Wortes wird in einer Konstanten in 10tel Millimeter angegeben. Es werden Funktionen definiert, die bestimmte Attribute aus einem XML-Knoten lesen (getNodeAttrUnits()), aus den Attributen l, t, r und b ein Rechteck bilden (getNodeAttrRectUnits()) und prüfen, ob ein Wort an einem vorgegebenen Punkt steht (xmlFindWdByPoint()).
define { sPointOnPage : PointMake(1900,250) // Position 2.5 cm from top, 19 cm from left } sub getNodeAttrUnits ( aXmlNode : handle; aName : alpha; ) : int local { tXmlNode : handle; } { tXmlNode # aXmlNode->CteRead(_CteAttribList | _CteFirst | _CteSearch, 0, aName); if (tXmlNode > 0) return CnvIA(tXmlNode->spValueAlpha); else return 0; } sub getNodeAttrRectUnits ( aXmlNode : handle; ) : rect local { tResult : rect; } { tResult:left # aXmlNode->getNodeAttrUnits('l'); tResult:top # aXmlNode->getNodeAttrUnits('t'); tResult:right # aXmlNode->getNodeAttrUnits('r'); tResult:bottom # aXmlNode->getNodeAttrUnits('b'); return tResult; } sub xmlFindWdByPoint ( aXmlNode : handle; aPoint : point; ) : handle local { tXmlNode : handle; tRect : rect; tResult : handle; } { for tXmlNode # aXmlNode->CteRead(_CteChildList | _CteFirst); loop tXmlNode # aXmlNode->CteRead(_CteChildList | _CteNext, tXmlNode); while (tXmlNode > 0) { if (tXmlNode->spName = 'wd') { tRect # tXmlNode->getNodeAttrRectUnits(); if (aPoint:x >= tRect:left and aPoint:x <= tRect:right and aPoint:y >= tRect:top and aPoint:y <= tRect:bottom) { return tXmlNode; } cycle; } tResult # xmlFindWdByPoint(tXmlNode,aPoint); if (tResult > 0) return tResult; } return 0; }
Für den Aufruf der Funktionen muss der XML-Text gelesen und in eine Knotenstruktur geladen werden. Anschließend wird der angegebene Punkt in seine Position in Twips umgerechnet und der Funktion xmlFindWdByPoint() übergeben. Das gesuchte Wort befindet sich in einem untergeordneten Knoten. Das Wort wird mit der Funktion getWord() ermittelt.
sub getWord ( aWdNode : handle; var aValue : alpha; ) : int; local { tHdlNode : handle; } { if (HdlInfo(aWdNode,_HdlExists) = 0) { aValue # ''; return(_ErrHdlInvalid); } tHdlNode # aWdNode->CteRead(_CteChildList | _CteFirst); // run element if (tHdlNode <= 0) { aValue # ''; return(_ErrGeneric); } tHdlNode # tHdlNode->CteRead(_CteChildList | _CteFirst); // text element if (tHdlNode <= 0) { aValue # ''; return(_ErrGeneric); } aValue # tHdlNode->spValueAlpha; return(_ErrOk); } main ( ) : logic local { tResult : int; tMemory : handle; tXmlDoc : handle; tTarget : point; tNodeTarget : handle; tTargetWord : alpha(250); } { tMemory # AfMemAllocate(_MemAutoSize); tMemory->spCharset # _CharsetUTF8; tResult # AfArcFileXmlTextRead(tMemory,1); // read XML of first Page tXmlDoc # AfCteOpen(_CteNode, _CteChildList | _CteAttribList | _CteAttribTree); tResult # tXmlDoc->XmlLoad('',0,tMemory); // convert to xml structure tMemory->MemFree(); tTarget # sPointOnPage; // convert position from 1/10 mm to twips tTarget:x # tTarget:x * 1440 / 254; tTarget:y # tTarget:y * 1440 / 254; tNodeTarget # tXmlDoc->xmlFindWdByPoint(tTarget); if (tNodeTarget = 0) { // nothing found at the given point ... } else { // get the word at that point tResult # getWord(tNodeTarget, var tTargetWord); } ... return(true); }
Neben den allgemeinen Fehlerwerten können folgende Werte zurückgegeben werden:
Konstante | Wert | Bedeutung |
_ErrOk | 0 | ok - kein Fehler aufgetreten |
_ErrHdlInvalid | -191 | Das übergeben Memory-Objekt existiert nicht. |
Für weitere CONZEPT 16-spezifische Rückgabewerte siehe die aktuelle CONZEPT 16-Hilfe.