PDFium Component otkriva tablice na PDF stranici i vraća ih kao mrežu ćelija s rasponima redaka i stupaca, recima zaglavlja i vrijednošću pouzdanosti, putem ExtractTables za jednu stranicu i ExtractDocumentTables za cijeli dokument. Svaka se tablica jednim pozivom pretvara u CSV ili JSON, a tablice koje se nastavljaju preko prijeloma stranice mogu se povezati u lanac nastavka
PDF nema objekt tablice. Tablica u PDF-u skup je tekstualnih nizova pozicioniranih tako da ih čovjek čita kao mrežu, ponekad s nacrtanim linijama oko njih, a često bez njih. Obnavljanje mreže znači rekonstrukciju namjere koju datoteka nikada nije zabilježila, zbog čega svaki alat za izvlačenje proizvodi malo drugačije rezultate i zbog čega je alat koji vam govori svoju pouzdanost korisniji od onoga koji to ne čini
Dva načina otkrivanja za dvije vrste tablica
Otkrivanje pomoću crta koristi nacrtane linije. Svaki segment iscrtane putanje transformira se u koordinate stranice putem matrice objekta stranice, horizontalne i vertikalne linije presijecaju se, a presjeci tvore povezane komponente. Svaka komponenta postaje vlastita sortirana mreža X i Y pozicija, što sprječava da se dvije zasebne tablice na istoj stranici spoje u jednu besmislenu mrežu
Otkrivanje razmacima obrađuje tablice nacrtane poravnanjem umjesto linijama. Okviri riječi grupiraju se u vizualne retke, praznine unutar retka dijele ga na kandidatske stupce, a tablica se prihvaća samo kada barem MinRows redaka ponavlja barem MinColumns lijevo poravnatih sidra unutar AlignmentTolerance. Faktor razmaka između redaka prema zadanim postavkama iznosi 3, što pokriva otprilike razmak bazne linije od 30 točaka tipičan za tekst od 12 točaka, a da pritom ne dopusti da se jedan redak koji sadrži nekoliko tekstualnih nizova prerušava u tablicu
uses
PDFium;
var
Pdf: TPdf;
Options: TPdfTableExtractionOptions;
Tables: TPdfTables;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'annual-report.pdf';
Pdf.LoadDocument;
Pdf.PageNumber := 12; // 1-based
Options := TPdfTableExtractionOptions.Default;
Options.DetectRuledTables := True;
Options.DetectWhitespaceTables := True;
Options.MinConfidence := 0.6; // default is 0.5
Options.HeaderRowCount := 1;
Tables := Pdf.ExtractTables(Options);
for I := 0 to High(Tables) do
Writeln(Format('table %d: %dx%d cells, confidence %.2f, mode %d',
[I, Tables[I].RowCount, Tables[I].ColumnCount,
Tables[I].Confidence, Ord(Tables[I].DetectionMode)]));
if Length(Tables) > 0 then
SaveText('page12-table0.csv', Tables[0].ToCsv);
finally
Pdf.Free;
end;
end;
Kako se obnavljaju spojene ćelije?
Ovo je dio koji naivni alati za izvlačenje krivo obavljaju. Spojena ćelija ne može se identificirati samo iz globalne mreže, jer je mreža izvedena iz svih linija na stranici, a spojenom području jednostavno nedostaje unutarnja linija koja bi je odvajala
Ovdje korišteno pravilo lokalno je: dvije susjedne osnovne ćelije spajaju se kada nijedna granična linija ne pokriva interval između njih. Union-find ih spaja, rezultirajuće pravokutne komponente postaju vrijednosti RowSpan i ColumnSpan, a tekst se pridjeljuje osnovnoj ćeliji prema svojoj središnjoj točki i zatim slijedi tu ćeliju do njezina korijena spajanja. Ovakav pristup također drži trošak linearnim u riječima plus ćelijama, umjesto kvadratnog skeniranja koje se dobiva testiranjem svake riječi prema svakoj ćeliji
Praktičan je učinak da financijska tablica sa spojenim zaglavljem "Total" koje obuhvaća tri stupca izlazi s jednom ćelijom raspona tri, umjesto jedne popunjene ćelije i dvije tajanstveno prazne
Nastavak preko stranica
Duge se tablice lome preko stranica, a tretiranje fragmenta svake stranice kao neovisne tablice prisiljava pozivatelja da ih spaja. ExtractDocumentTables ih umjesto toga može povezati, ali samo pod strogim uvjetima: fragment mora biti najniža tablica na ranijoj stranici, sljedeći mora biti najviša tablica na sljedećoj stranici, brojevi stranica moraju biti susjedni, a granice stupaca moraju se podudarati
Sva četiri uvjeta zajedno sprječavaju očitu pogrešku, a to je ulančavanje svake tablice od četiri stupca u dokumentu u jednu izmišljenu mega-tablicu jer slučajno dijele broj stupaca. Kada uvjeti vrijede, tablice dijele identifikator grupe nastavka i nose metapodatke nastavka; kada ne vrijede, dobivate zasebne tablice i sami možete odlučiti
Izvlačenje na razini dokumenta dijeli proračune MaxCells i MaxTables preko stranica umjesto da ih resetira po stranici, a aktivnu stranicu vraća u bloku finally, pa izvlačenje pokrenuto u pregledniku ostavlja korisnika gledajući stranicu na kojoj je bio
Izvoz bez oštećivanja podataka
Oba su izvoznika namjerna oko izlaznog označavanja (escaping). CSV uvijek stavlja polja pod navodnike i udvostručuje unutarnje navodnike, čime se izbjegava klasičan neuspjeh gdje ćelija koja sadrži zarez tiho postane dva stupca. Za spojene ćelije, sadržaj se emitira samo na gornjem lijevom sidru, pa ciklus CSV-a ne duplicira zaglavlje raspona preko stupaca koje pokriva
JSON čuva Unicode umjesto da ga izlazno označava u ASCII, izlazno označava kontrolne znakove, i uključuje metapodatke koji su potrošaču potrebni za procjenu kvalitete: način otkrivanja, pouzdanost, granice, vrijednosti raspona, oznake zaglavlja i podatke o nastavku. Ako izvučene tablice šaljete u nizvodni sustav, dajte prednost JSON-u, jer vam redak CSV-a ne može reći da je tablica iz koje potječe ocijenjena pouzdanošću od 0,51:
// Izvlačenje na razini cijelog dokumenta, zadržavajući samo tablice vrijedne povjerenja
Tables := Pdf.ExtractDocumentTables(Options);
for I := 0 to High(Tables) do
begin
if Tables[I].Confidence < 0.75 then
begin
Log(Format('page %d table needs review (%.2f)',
[Tables[I].PageNumber, Tables[I].Confidence]));
Continue;
end;
if Tables[I].ContinuationGroup > 0 then
AppendToGroup(Tables[I].ContinuationGroup, Tables[I].ToJson)
else
EmitStandalone(Tables[I].ToJson);
end;
Fino podešavanje i znati kada stati
Tri postavke bitnije su od ostalih. MinConfidence je vrata kvalitete, a 0,5 je namjerno popustljivo; povećajte ga za automatizirani unos i smanjite za sučelje pregleda gdje čovjek potvrđuje svaki rezultat. MinColumnGap odlučuje što se broji kao granica stupca u razmačnom načinu, a čvrsto postavljene tablice u gustim izvještajima možda ga trebaju smanjiti sa zadanih 12 točaka. MaxRowGapFactor odlučuje kada okomita udaljenost završava tablicu, što je bitno za tablice s povremenim praznim recima
Budite iskreni o ograničenjima. Tablice s crtama izvlače se pouzdano. Uredno poravnate razmačne tablice izvlače se dobro. Tablice s rotiranim tekstom, ugniježđene tablice, ili ćelije čiji se sadržaj prelama u ono što izgleda kao drugi redak, trebat će pregled bez obzira kako su parametri postavljeni. Za njih model strukturiranog teksta daje vam sirovi materijal za izgradnju čitača specifičnog za domenu, opisan u članku blokovi strukturiranog teksta i redoslijed čitanja
Jedno korisno uparivanje: kada skenirani dokument nema uopće tekst, otkrivanje tablica nema s čime raditi dok ne postoji tekstualni sloj. Najprije ga dodajte, kako je opisano u članku dodavanje pretraživog tekstualnog sloja skeniranim PDF-ovima, a zatim izvucite. Okviri riječi koje vraća pružatelj OCR-a upravo su ulaz koji otkrivanje razmacima treba
Izvlačenje tablica, strukturirani tekst i preslaganje (reflow) svi čitaju iz istog modela stranice u Delphiju, C++Builderu i Lazarusu; potpuni API opisan je na stranici PDFium Component za Delphi