PDFiumPas grąžina puslapio tekstą kaip struktūrą, ne kaip eilutę. GetStructuredText sukuria TPdfStructuredTextPage, turintį blokus, kiekvienas turintis eilutes, kiekviena turinti stilizuotus fragmentus, su puslapio erdvės ribomis kiekviename lygmenyje ir išsaugotais originalaus simbolio indeksais, todėl bet kurį fragmentą galima susieti atgal su pagrindiniu teksto puslapiu
Plokščio teksto išgavimas, nuo kurio pradeda dauguma kodo, vis dar egzistuoja ir vis dar teisingas savo paskirčiai. Jis nustoja pakankamai tinkamas tą akimirką, kai reikia žinoti, kurie žodžiai buvo antraštė, kurie priklausė kairiajam stulpeliui, arba kur puslapyje iš tikrųjų yra atitikmuo
Kodėl plokščia eilutė yra neteisinga išvestis daugumai užduočių?
Todėl, kad klausimai, kuriuos žmonės užduoda išgautam tekstui, beveik niekada nėra „kokie simboliai yra šiame puslapyje". Jie yra „koks yra pavadinimas", „ar tai lentelė", „ar ši pastraipa priklauso 4 skyriui", „kur nubrėžti paryškinimą". Viena eilutė neatsako nė į vieną iš jų, ir kiekvienas atsakymas, kurį atkuriate iš jos, yra euristika, kurią dabar turite jūs pats
Dviejų stulpelių maketai tai iliustruoja konkrečiai. Išgaukite dviejų stulpelių straipsnį kaip eilutę, ir, priklausomai nuo to, kaip generatorius parašė turinio srautą, galite gauti pirmą stulpelį, po jo antrą, arba galite gauti pirmo stulpelio pirmą eilutę, antro stulpelio pirmą eilutę, pirmo stulpelio antrą eilutę, ir taip toliau žemyn puslapiu. Abu atvejai gaunami iš atitinkančio PDF. Nė vienas neteisingas formato lygmeniu, nes PDF aprašo ženklus puslapyje, ne dokumento kontūrą. Blokais grįstas modelis leidžia išgavikliui priimti tvarkos sprendimą aiškiai ir pasakyti, kurį sprendimą jis priėmė
Turinio tvarka ar fizinis maketas?
TPdfStructuredTextOptions.ReadingOrder pasirenka tarp roContentOrder ir roPhysicalLayout, o teisingas atsakymas priklauso nuo to, kuo pasitikite labiau – generatoriumi ar geometrija
Turinio tvarka grąžina tekstą tokia seka, kokia jį piešia turinio srautas. Tai greita, ir dokumentams, sugeneruotiems tvarkingo generatoriaus, paprastai numatytoji skaitymo tvarka. Fizinis maketas ignoruoja srauto seką ir atkuria tvarką iš to, kur simboliai iš tikrųjų yra, sugrupuodamas juos į eilutes, o tada į stulpelius. Tai yra tai, ko norite nuskaitytiems ir per OCR apdorotiems puslapiams, įrankių, išvedančių tekstą šrifto, ne skaitymo tvarka, rezultatams, ir bet kam, kur vizualinis rezultatas yra vienintelis dalykas, kuriuo galite pasikliauti
uses
PDFium;
var
Pdf: TPdf;
Options: TPdfStructuredTextOptions;
Page: TPdfStructuredTextPage;
B, L: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'article.pdf';
Pdf.LoadDocument;
Pdf.PageNumber := 1; // pradedant nuo 1
Options := TPdfStructuredTextOptions.Default;
Options.ReadingOrder := roPhysicalLayout;
Options.IncludeFontInfo := True;
Options.IncludeSemantics := True;
Options.MaxCharacters := 200000; // griežtai uždaras biudžetas
Page := Pdf.GetStructuredText(Options);
for B := 0 to High(Page.Blocks) do
begin
if Page.Blocks[B].Kind = cfHeading then
Emit(Format('H%d: %s',
[Page.Blocks[B].HeadingLevel, Page.Blocks[B].Text]))
else
for L := 0 to High(Page.Blocks[B].Lines) do
Emit(Page.Blocks[B].Lines[L].Text);
end;
finally
Pdf.Free;
end;
end;
Ką prideda žymėjimas, ko negali geometrija?
Ketinimą. Kai IncludeSemantics įjungta, blokai iš žymėto PDF nešioja Kind, gautą iš struktūros medžio, todėl antraštė yra antraštė, nes generatorius taip pasakė, ne todėl, kad jos šriftas buvo didesnis nei vidutinis. Rūšys apima formas, kurios svarbios pakartotiniam naudojimui: cfParagraph, cfHeading su HeadingLevel, cfListItem, cfTableCell, cfCaption, cfFigure ir nežymėtas atsarginis variantas cfPlain
Source laukas užrašo, iš kur kilo kiekviena klasifikacija, rosStructure struktūros medžiui ir rosHeuristic sprendimui, o tai yra laukas, kurį verta registruoti sprendžiant, kiek pasitikėti išgavimo konvejeriu per dokumentų rinkinį. Paveikslai yra specialus atvejis, kurį verta žinoti: cfFigure blokui tekstas kilęs iš alternatyvaus aprašymo, ne iš jokių glifų, nes paveikslas neturi savų simbolių. Nesutampantis alternatyvus tekstas vis tiek pateikiamas, o ne praleidžiamas, ir būtent tai leidžia prieinamumo auditui matyti, kad aprašymas egzistuoja, net kai puslapyje nieko nepiešiama. Pats žymėjimo modelis aprašytas straipsnyje apie PDF/UA struktūros medžio validaciją
Fragmentai neša stilių ir kilmę
Kiekvienas TPdfStructuredTextSpan turi savo tekstą, puslapio erdvės ribas, FontName, FontSize, FontWeight ir Angle, taip pat SourceStartIndex ir SourceCharacterCount. Fragmentai lūžta ten, kur keičiasi stilius, todėl sakinys su trimis pusjuodžiais žodžiais tampa trimis fragmentais, ir pabrėžimo atkūrimas HTML ar Markdown formate tampa savybių skaitymo, ne spėjimo iš šrifto vardų, klausimu
Du šaltinio indeksų laukai yra tie, kurie paverčia išgavimą funkcija, ne ataskaita. Jie nurodo atgal į puslapio simbolių seką, o tai reiškia, kad blokas, kurį suradote paieškoje, gali būti paverstas simbolių lygmens pažymėjimo geometrija ar paryškinimo stačiakampiu be antro, kitaip surikiuoto teksto pravedimo; mechanika aprašyta straipsnyje apie vizualų teksto eilutės pažymėjimą su simbolių langeliais. Angle laukas svarbesnis, nei atrodo: pasuktas tekstas antspaude ar vandens ženkle patenka į tą pačią koordinačių erdvę kaip pagrindinis tekstas, ir konvejeris, ignoruojantis kampą, mielai sulies įstrižą „DRAFT" į pastraipos vidurį
Biudžetas ir du kokybės skaitikliai
MaxCharacters yra griežtai uždaras biudžetas, ne apkarpymo nustatymas: puslapis, jį viršijantis, sustoja, o ne tyliai grąžina turinio dalį. Nepatikimame priėmimo kelyje tai ir yra elgesys, kurio norite, nes puslapis su milijonu simbolių yra arba mašinos sugeneruota pabaisa, arba bandymas paversti jūsų išgaviklį lėčiausia sistemos dalimi
Du grąžinto puslapio skaitikliai tiesiogiai aprašo išgavimo kokybę. UnmappedCharacterCount skaičiuoja simbolius be tinkamo Unicode susiejimo, o tai klasikinis simptomas įterpto poaibio šrifto be /ToUnicode CMap; toks tekstas atvaizduojamas puikiai ir išgaunamas kaip niekas naudingas. GeometryFailureCount skaičiuoja simbolius, kurių ribojantis stačiakampis negalėjo būti nustatytas, o tai pablogina fizinio maketo rikiavimą. Registruokite abu. Dokumentų rinkinys, kuriame tie skaičiai nuolat artimi nuliui, gali būti indeksuojamas su pasitikėjimu, o tas, kuriame jie ne, praneša, kad kai kuriems jūsų konvejerio generatoriams reikia dėmesio, prieš pasitikint bet kokiu tolesniu rezultatu
var
Page: TPdfStructuredTextPage;
B, S, L: Integer;
Emphasised: Boolean;
begin
Page := Pdf.GetStructuredText(Options);
if Page.UnmappedCharacterCount > 0 then
Log(Format('page %d: %d characters without a Unicode mapping',
[Page.PageNumber, Page.UnmappedCharacterCount]));
if Page.GeometryFailureCount > 0 then
Log(Format('page %d: %d characters without geometry',
[Page.PageNumber, Page.GeometryFailureCount]));
for B := 0 to High(Page.Blocks) do
for L := 0 to High(Page.Blocks[B].Lines) do
for S := 0 to High(Page.Blocks[B].Lines[L].Spans) do
begin
Emphasised := Page.Blocks[B].Lines[L].Spans[S].FontWeight >= 600;
AppendRun(Page.Blocks[B].Lines[L].Spans[S].Text, Emphasised,
Page.Blocks[B].Lines[L].Spans[S].SourceStartIndex);
end;
end;
Našumas realiuose puslapiuose
Fizinio maketo išgavimas yra brangesnis režimas, o realizacija sukurta puslapiams, kurie iš tikrųjų dideli: simbolių rikiavimas vyksta O(n log n), ne pakartotiniu skenavimu, eilučių ir fragmentų buferiai auga geometriškai vietoj perskirstymo kiekvienam simboliui, Unicode tekstas kuriamas buferiuose, ne eilučių sujungimu, o šrifto paieškos gretimiems teksto objektams kešuojamos. Šis derinys ir palaiko tankų 5000 simbolių puslapį nuspėjamą, o ne kvadratinį
Puslapių skaičiumi sunkiam darbui vis tiek verta rinktis pigesnį režimą, kur galite. Naudokite roContentOrder su įjungta semantika žymėtiems dokumentams, kuriais pasitikite, ir palikite roPhysicalLayout nuskaitytai bei senai medžiagai, kur geometrija yra vienintelis signalas. Jei jums reikia tik paprastos eilutės, paprastesnis API, aprašytas straipsnyje apie teksto išgavimą iš PDF dokumentų, išlieka greitesnis kelias, o kai reikia susieti tekstą su žymėto turinio identifikatoriais, BDC ir MCID žymėto turinio skaitymas ir rašymas apima tą sluoksnį
Blokų modelis taip pat švariai atitinka tai, ko nori gavybos konvejeriai: antraštė su savo pastraipomis yra gabalas su pavadinimu, o ribos leidžia citatai nurodyti vietą puslapyje, ne visą dokumentą. PDFiumPas yra Delphi ir Lazarus komponentas aplink PDFium variklį, dokumentuotas su pavyzdžiais PDFium Delphi komponento puslapyje