Každý geometrický extraktor textu háda. Číta glyfy, ktoré stránka kreslí, triedi ich podľa baseline a horizontálnej pozície a dúfa, že vizuálne usporiadanie zodpovedá poradiu, v akom by čítal človek. Pri jednostĺpcovej správe je ten tip správny. Pri dvojstĺpcovom článku z časopisu, formulári s bočným panelom alebo tabuľke, ktorej bunky boli emitované stĺpec po stĺpci, je zlý spôsobmi, ktoré sa ťažko všimnú a sú drahé objaviť po prúde. HotPDF na to odpovedá ExtractLoadedPageStructureText, ktorý ignoruje geometriu úplne: prechádza strom štruktúry dokumentu v poradí autorstva, ako ho definuje ISO 32000-1 §14.8.4, a potom znovu skladá glyfy strany podľa ich marked-content identifikátora. Pre tagované PDF to nie je heuristika, je to poradie, ktoré produkujúca aplikácia deklarovala
Funkcia vracia False, keď strana nemá použiteľný strom štruktúry, čo je signál prepadnúť na geometrický extraktor, nie zlyhať. Tento dvojcestný návrh je dôležitejší než algoritmus: reálny príjem dokumentov vidí tagované vládne formuláre a výstup skenerov v tom istom priečinku a pipeline, ktorá zvláda len jeden z nich, nie je pipeline
Prečo geometrická extrakcia mylí poradie čítania?
Pretože content stream PDF nenesie žiadne poradie čítania. Je to sekvencia kresliacich operátorov a producent je slobodný emitovať ich v akejkoľvek sekvencii, ktorá sedí jeho vlastnému layout enginu. Textové procesory zvyčajne emitujú v poradí toku a geometrické triedenie vyzerá dobre. Layout nástroje, návrhári formulárov a generátory správ často nie: pätička strany sa môže emitovať pred telom, tabuľka sa môže plniť po stĺpcoch a dvojstĺpcová strana môže prelínať riadky z oboch stĺpcov, pretože skladateľ ich rozriesil spolu
Režim zlyhania je tichý. Geometrický extraktor nikdy nehlási chybu, len odovzdá späť prózu, ktorej vety sú zlepené z dvoch stĺpcov. Čokoľvek, čo ten text konzumuje — vyhľadávací index, mapovač polí e-faktúr, retrieval pipeline kŕmiaci jazykový model — dedí škodu bez varovania. HotPDF dodáva aj geometrické extraktory pre načítané dokumenty a tie zostávajú správnym nástrojom pre netagované súbory; zmysel cesty v poradí štruktúry je prestať hádať, keď dokument už odpoveď nesie
Čo strom štruktúry skutočne uchováva
Tagované PDF uchováva druhý, paralelný popis strany. Katalóg ukazuje na /StructTreeRoot, ktorej deti /K tvoria strom prvkov štruktúry: /Document, /Sect, /P, /Table, /TR, /TD a ďalšie. Listy toho stromu sú marked-content referencie, celé čísla, ktoré menujú úsek content streamu strany. Na strane obsahu sa tie úseky otvárajú operátorom BDC nesúcim /MCID a zatvárajú s EMC. Každý prvok štruktúry nesie aj položku /Pg menujúcu stranu, ku ktorej patrí, čo umožňuje prechod po stranách v dokumente, ktorej strom štruktúry sa tiahne cez stovky strán
HotPDF prechádza ten strom s hĺbkovým stropom 128 úrovní a filtruje na /Pg, takže prispieva len aktuálna strana. Výstupom prechodu nie je text, je to usporiadaný zoznam hodnôt MCID: poradie autorstva úsekov marked-content na tejto strane. Zloženie textu je potom vecou prehratia glyfov v tom poradí
MCID sa zaznamenáva počas extrakcie glyfov, nie dohľadáva sa potom
Toto je implementačný detail, ktorý robí funkciu lacnou. HotPDF už zaznamenáva aktívny marked-content identifikátor na každom glyfe, ktorý extrahuje, v poli MCID záznamu THPDFGlyphRecord, pretože interpret content streamu vie, ktorý scope BDC je otvorený v momente, keď spracováva každý operátor Tj alebo TJ. Extrakcia v poradí štruktúry preto nepotrebuje druhý prechod cez content stream. Zbiera sekvenciu MCID zo stromu štruktúry, potom roztriedi už extrahované glyfy podľa MCID a emituje ich v tej sekvencii
var
Pdf: THotPDF;
PageCount, I, Untagged: Integer;
PageText, AllText: UnicodeString;
Report: TStrings; // diagnostická zbierka vo vlastníctve volajúceho
begin
Pdf := THotPDF.Create(nil);
try
PageCount := Pdf.LoadFromFile('accessible-form.pdf');
AllText := '';
for I := 0 to PageCount - 1 do
begin
if Pdf.ExtractLoadedPageStructureText(I, PageText, Untagged) then
begin
// Poradie autorstva priamo zo stromu štruktúry
if Untagged > 0 then
Report.Add(Format('page %d: %d glyphs outside the structure tree',
[I, Untagged]));
end
else
// Žiadny použiteľný strom štruktúry na tejto strane: geometrický fallback
Pdf.ExtractLoadedPageText(I, PageText);
AllText := AllText + PageText + #13#10;
end;
finally
Pdf.Free;
end;
end;
Netagované glyfy sa počítajú, nikdy sa potichu nezahadzujú
Strana môže byť čiastočne tagovaná. Producenti pridávajú ozdobnú linku, číslo strany alebo neskorší vodoznak mimo akéhokoľvek scope BDC a tie glyfy nepatria žiadnemu MCID. Zahodiť ich by bolo uprataná implementácia a zároveň zlá, pretože rovnaká medzera sa objaví aj vtedy, keď producent taguje telo, ale zabudne tabuľku, a prídete o tabuľku bez toho, aby ste si to všimli
HotPDF pripája nevyžiadané glyfy ako geometrický chvost za textom v poradí štruktúry a hlási ich počet cez výstupný parameter UntaggedGlyphCount. To číslo je kvalitatívny signál, na ktorý možno reagovať. Hŕstka glyfov na strane dvoch tisíc je page furniture a možno ju ignorovať. Štyridsať percent strany mimo stromu štruktúry znamená, že tagovanie je ozdobné a geometrický extraktor je pre ten súbor úprimnejšia odpoveď
function ExtractPageBestEffort(Pdf: THotPDF; PageIndex: Integer;
out AText: UnicodeString; out UsedStructure: Boolean): Boolean;
var
Untagged, TotalGlyphs: Integer;
Glyphs: THPDFGlyphArray;
begin
UsedStructure := False;
if Pdf.ExtractLoadedPageStructureText(PageIndex, AText, Untagged) then
begin
TotalGlyphs := 0;
if Pdf.ExtractLoadedPageGlyphs(PageIndex, Glyphs) then
TotalGlyphs := Length(Glyphs);
// Veriť stromu štruktúry len vtedy, keď si nárokuje väčšinu strany
if (TotalGlyphs = 0) or (Untagged * 4 <= TotalGlyphs) then
begin
UsedStructure := True;
Result := True;
Exit;
end;
end;
Result := Pdf.ExtractLoadedPageText(PageIndex, AText);
end;
Čo prinúti funkciu vrátiť False
Tri prípady a stojí za to ich rozlíšiť, pretože len jeden z nich je defektom dokumentu. Prvý je obyčajné netagované PDF: žiadny /StructTreeRoot, nič na prechádzanie a False je jednoducho pravda. Druhý je naskenovaná strana, ktorej text pochádza z OCR vrstvy, ktorá nebola nikdy tagovaná. Tretí je ten zaujímavý: obsah nesúci operátory BDC s hodnotami /MCID, ale jeho strana nemá položku /StructParents a strom štruktúry tie identifikátory nikdy neodkazuje. Marked content existuje, strana štruktúry nie a nie je žiadne poradie na obnovenie. HotPDF hlási False namiesto jedného vymyslieť
Posledný prípad sa objavuje v ručne upravovaných súboroch a vo výstupe nástrojov, ktoré emitujú marked content na účely optional-content či artifact bez budovania stromu štruktúry. Ak sami produkujete tagované PDF, tá istá asymetria je to, čo kontroluje validácia PDF/UA a writer-side náprotivok pokrýva layout DOM emitujúci tagovaný, stránkovaný výstup
Kde sa poradie štruktúry vyplatí
Audit prístupnosti je zjavný: ak certifikujete dokument voči PDF/UA, poradie čítania, ktoré ohlási čítačka obrazovky, je presne poradie štruktúry, takže jeho extrakcia je spôsob, ako ho prezrieť bez čítačky obrazovky. Zber dát je väčší komerčný prípad. Tagované vládne formuláre, regulované zverejnenia a prílohy e-faktúr nesú menovky polí a hodnoty v deklarovanom poradí a ich čítanie v tom poradí odstraňuje celú triedu chýb mapovania, ktoré geometrická extrakcia vytvára na viacstĺpcových usporiadaniach
Najnovším konzumentom je retrieval pre jazykové modely. Chunkovanie dokumentu pre embedding je len také dobré, aké je poradie textu, a chunk, ktorý zlepí dva stĺpce, produkuje vety, ktoré nikdy neexistovali. Extrakcia v poradí štruktúry je najlacnejšia dostupná oprava, pretože pre tagované dokumenty je správne poradie už v súbore a len ho treba prečítať
HotPDF je natívna VCL komponenta pre Delphi a C++Builder, takže prechod stromom štruktúry aj prehrávanie glyfov bežia v procese nad načítaným dokumentom bez zapojenia externého renderera. Kompletné API detaily rodiny extrakcie načítaných dokumentov sú na produktovej stránke HotPDF Delphi PDF component