Hver geometrisk tekstekstraktor gjetter. Den leser glyfene en side tegner, sorterer dem etter grunnlinje og horisontal posisjon, og håper det visuelle arrangementet matcher rekkefølgen et menneske ville lest. På en én-kolonne rapport er den gjetningen riktig. På en to-kolonne journalartikkel, et skjema med en sidefelt, eller en tabell hvis celler ble sendt ut kolonne for kolonne, er den feil på måter som er vanskelige å legge merke til og dyre å oppdage nedstrøms. HotPDF svarer på dette med ExtractLoadedPageStructureText, som ignorerer geometri fullstendig: den går gjennom dokumentets strukturetre i forfatterrekkefølge som definert i ISO 32000-1 §14.8.4, og setter deretter sammen sideglyfene etter sin marked-content-identifikator. For en tagget PDF er det ikke en heuristikk, det er rekkefølgen det produserende programmet erklærte
Funksjonen returnerer False når siden ikke har noe brukbart strukturetre, noe som er signalet til å falle tilbake til den geometriske ekstraktoren snarere enn å feile. Det toveisdesignet betyr mer enn algoritmen: ekte dokumentinntak ser taggede offentlige skjemaer og skanneroutput i den samme mappen, og en pipeline som bare håndterer én av dem, er ikke en pipeline
Hvorfor får geometrisk ekstraksjon leserrekkefølgen feil?
Fordi en PDF-innholdsstrøm ikke bærer noen leserrekkefølge i det hele tatt. Den er en sekvens av tegneoperatorer, og en produsent står fritt til å sende dem ut i den sekvensen som passer sin egen layoutmotor. Tekstbehandlere sender vanligvis ut i flytrekkefølge og geometrisk sortering ser fint ut. Verktøy for layout, skjemadesignere og rapportgeneratorer gjør ofte ikke det: en sidefot kan sendes ut før brødteksten, en tabell kan fylles kolonnevis, og en to-kolonne side kan flette linjer fra begge kolonner fordi komponistoren løste dem sammen
Feilmodusen er stille. En geometrisk ekstraktor rapporterer aldri en feil, den leverer bare prosa hvis setninger er flettet fra to kolonner. Alt som konsumerer den teksten, et søkeindeks, en e-faktura feltmapper, en hentingspipeline som mater en språkmodell, arver skaden uten en advarsel. HotPDF leverer også de geometriske ekstraktorene for lastede dokumenter, og de forblir det riktige verktøyet for utaggete filer; poenget med strukturrekkefølgeveien er å slutte å gjette når dokumentet allerede bærer svaret
Hva strukturetret faktisk lagrer
En tagget PDF holder en andre, parallell beskrivelse av siden. Katalogen peker på en /StructTreeRoot, hvis /K-barn danner et tre av strukturelementer: /Document, /Sect, /P, /Table, /TR, /TD, og så videre. Bladene av det treet er marked-content-referanser, heltall som navngir et spenn av sideinnholdsstrømmen. På innholdssiden åpnes de spennene med en BDC-operator som bærer en /MCID og lukkes med EMC. Hvert strukturelement bærer også en /Pg-oppføring som navngir siden det tilhører, noe som er det som gjør per-side-traversering mulig i et dokument hvis strukturetre spenner over hundrevis av sider
HotPDF traverserer det treet med et dybdetak på 128 nivåer og filtrerer på /Pg slik at bare den nåværende siden bidrar. Output av traverseringen er ikke tekst, det er en ordnet liste av MCID-verdier: forfatterrekkefølgen av marked-content-spennene på denne siden. Å sette sammen tekst er deretter et spørsmål om å spille av glyfene i den rekkefølgen
MCID-en registreres under glyfekstraksjon, ikke slås opp etterpå
Dette er implementeringsdetaljen som gjør funksjonen billig. HotPDF registrerer allerede den aktive marked-content-identifikatoren på hver glyf den trekker ut, i MCID-feltet av THPDFGlyphRecord, fordi innholdsstrømtolken vet hvilken BDC-skope som er åpen i det øyeblikket den prosesserer hver Tj- eller TJ-operator. Strukturrekkefølge-ekstraksjon trenger derfor ingen annen passering over innholdsstrømmen. Den samler MCID-sekvensen fra strukturetret, og grupperer deretter de allerede uttrukne glyfene etter MCID og sender dem ut i den sekvensen
var
Pdf: THotPDF;
PageCount, I, Untagged: Integer;
PageText, AllText: UnicodeString;
Report: TStrings; // kaller-eid diagnostikkmottaker
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
// Forfatterrekkefølge rett fra strukturetret
if Untagged > 0 then
Report.Add(Format('page %d: %d glyphs outside the structure tree',
[I, Untagged]));
end
else
// Intet brukbart strukturetre på denne siden: geometrisk fallback
Pdf.ExtractLoadedPageText(I, PageText);
AllText := AllText + PageText + #13#10;
end;
finally
Pdf.Free;
end;
end;
Utaggete glyfer telles, aldri lydløst droppet
En side kan være delvis tagget. Produsenter legger til en dekorativ linje, et sidetall eller et senstadiumsvannmerke utenfor enhver BDC-skope, og de glyfene tilhører ingen MCID. Å droppe dem ville være den ryddige implementeringen og den feilaktige, fordi det samme gapet også opptrer når en produsent tagger brødteksten men glemmer tabellen, og du ville miste tabellen uten å legge merke til det
HotPDF appender uokkuperte glyfer som en geometrisk hale etter den strukturrekkefølgeordnete teksten og rapporterer antallet deres gjennom UntaggedGlyphCount-utdataparameteren. Det tallet er et kvalitetssignal du kan handle på. En håndfull glyfer på en side på to tusen er sidemøblering og kan ignoreres. Førti prosent av siden utenfor strukturetret betyr at taggingen er dekorativ og den geometriske ekstraktoren er det ærligere svaret for den filen
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);
// Stol på strukturetret bare når det hevder det meste av siden
if (TotalGlyphs = 0) or (Untagged * 4 <= TotalGlyphs) then
begin
UsedStructure := True;
Result := True;
Exit;
end;
end;
Result := Pdf.ExtractLoadedPageText(PageIndex, AText);
end;
Hva får funksjonen til å returnere False
Tre tilfeller, og de er verdt å skille fordi bare én av dem er en defekt i dokumentet. Det første er en vanlig utagget PDF: ingen /StructTreeRoot, ingenting å gå gjennom, og False er rett og slett sannheten. Det andre er en skannet side hvis tekst kommer fra et OCR-lag som aldri ble tagget. Det tredje er det interessante: innhold som bærer BDC-operatorer med /MCID-verdier, men hvis side ikke har noen /StructParents-oppføring og hvis strukturetre aldri refererer de identifikatorene. Det markerte innholdet finnes, struktursiden gjør ikke det, og det finnes ingen rekkefølge å gjenopprette. HotPDF rapporterer False i stedet for å finne på én
Det siste tilfellet opptrer i håndredigerte filer og i output fra verktøy som sender ut markert innhold for optional-content- eller artifact-formål uten å bygge et strukturetre. Hvis du produserer taggete PDF-er selv, er den samme asymmetrien det PDF/UA-validering sjekker for, og motstykket på skriversiden er dekket i layout-DOM-en som sender ut tagget, paginert output
Hvor strukturrekkefølge betaler for seg
Tilgjengelighetsrevisjon er den opplagte: hvis du sertifiserer et dokument mot PDF/UA, er leserrekkefølgen en skjermleser vil annonsere nøyaktig strukturrekkefølgen, så å ekstrahere den er hvordan du reviderer den uten en skjermleser. Datafangst er det større kommersielle tilfellet. Taggede offentlige skjemaer, regulerte offentliggjøringer og e-fakturavedlegg bærer feltetiketter og verdier i erklært rekkefølge, og å lese dem i den rekkefølgen fjerner en hel klasse av kartleggingsfeil som geometrisk ekstraksjon skaper på flerkolonneoppsett
Den nyeste konsumenten er henting for språkmodeller. Å kutte et dokument i biter for embedding er bare så bra som tekstrekkefølgen, og en bit som fletter to kolonner produserer setninger som aldri fantes. Strukturrekkefølge-ekstraksjon er den billigste tilgjengelige fiksen for det, for for taggete dokumenter er den korrekte rekkefølgen allerede i filen og trenger bare å leses
HotPDF er en nativ VCL-komponent for Delphi og C++Builder, så strukturetre-traverseringen og glyfeavspillingen kjører begge i prosessen mot et lastet dokument uten noen ekstern renderer involvert. Fullstendige API-detaljer for lastet-dokument-ekstraksjonsfamilien står på produktsiden for HotPDF Delphi PDF component