PDFlibPas konverterer PDF-innhold til to redigerbare formater uten Office-automatisering. ExportPageMarkdown og ExportDocumentMarkdown returnerer semantisk Markdown med utledede overskrifter, nummererte og punktlister og pipe-tabeller, mens SaveDOCXToFile og SaveDOCXToStream skriver en WordprocessingML-pakke som inneholder avsnitt, overskrifter, native listenummerering, oppdagede tabeller, skriftformatering, sideskift og posisjonerte PNG-bilder
Begge kjører fullstendig i Pascal, på en server, uten at Word er installert og uten COM. Denne begrensningen er grunnen til at funksjonen finnes i et PDF-bibliotek fremfor i et skrivebordsverktøy
Hvorfor er «PDF til Word» reelt vanskelig?
Fordi en PDF-side ikke inneholder avsnitt. Den inneholder tekstvisningsoperatorer som plasserer sekvenser av glyffer på koordinater, i den rekkefølgen produsenten skrev dem ut, uten noen forpliktelse til å angi at to sekvenser hører til samme setning, langt mindre samme listepunkt. Formatet ble designet for å beskrive en trykt side nøyaktig, og det lykkes med det ved å kaste bort strukturen som produserte siden
Så enhver konverterer må rekonstruere det generatoren kastet bort. Linjegruppering kommer fra vertikal avstand og grunnlinjejustering. Avsnittsgrenser kommer fra endringer i avstand og innrykk. En overskrift er en linje der skriften er større eller tyngre enn brødteksten, og som skiller seg fra det som følger. En liste er en rekke avsnitt som begynner med et punkttegn eller et nummermønster. En tabell er et rutenett av tekstblokker der kantene stemmer overens på tvers av rader og kolonner. Alt dette er slutninger, og en slutning gir et godt resultat på dokumenter som følger vanlige typografiske konvensjoner, og et middelmådig resultat på dokumenter som ikke gjør det
Taggede PDF-er er unntaket, og et stort et. Når dokumentet bærer et strukturtre, registreres rollene for avsnitt, overskrift, liste og tabell i stedet for å gjettes, og det er derfor tilgjengelighetsarbeidet beskrevet i strukturen for tagget PDF-tilgjengelighet lønner seg også for konverteringskvaliteten. Hvis du styrer produsenten, er tagging av utdataene dine det enkelttiltaket med størst gjennomslagskraft du kan gjøre for alle som senere skal konvertere den
Markdown-eksport, én side om gangen
Markdown-veien er den du bør velge når målet er en tekstpipeline: et dokumentasjonsnettsted, en søkeindeks, et hentekorpus for en assistent. Alternativene er en bitmaske: PDF_MARKDOWN_INCLUDE_PAGE_MARKERS, PDF_MARKDOWN_DETECT_HEADINGS, PDF_MARKDOWN_PRESERVE_STYLES, der PDF_MARKDOWN_DEFAULT kombinerer alle tre
var
Pdf: TPDFlib;
Md: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.LoadFromFile('handbook.pdf', '');
// Én side, som en streng
Md := Pdf.ExportPageMarkdown(1, PDF_MARKDOWN_DEFAULT);
// Et sideintervall, strømmet til disk som UTF-8 uten BOM
Pdf.SaveMarkdownToFile('1-40',
PDF_MARKDOWN_DETECT_HEADINGS or PDF_MARKDOWN_PRESERVE_STYLES,
'handbook.md');
finally
Pdf.Free;
end;
end;
Sidemarkører gjør seg fortjent i hentearbeid. En tekstbit som bærer med seg siden den kom fra, kan siteres presist, og en leser som følger sitatet, havner der påstanden faktisk står. Slå dem av når Markdown-en er beregnet på menneskelig lesing, der sidegrenser fra kildens layout bare er støy
Strømmeinngangene betyr noe for store dokumenter. SaveMarkdownToStream og SaveMarkdownToFile skriver UTF-8 én side om gangen og bufrer ikke hele utdataen, slik at en manual på 900 sider ikke først blir en 900-siders streng i minnet. Fraværet av en byte-rekkefølge-markør (BOM) er også bevisst: en BOM på en Markdown-fil forvirrer et overraskende antall statiske nettstedsgeneratorer og diff-verktøy
DOCX uten Office på maskinen
DOCX-skriveren produserer selve pakken: ZIP-oppføringer skrevet som rå Deflate med CRC-sjekker, WordprocessingML-delene og relasjonene som binder dem sammen. Ingenting kaller inn i Word, noe som betyr at konverteringen kjører på en hodeløs server, inne i en tjenestekonto, i en container, på alle stedene der Office-automatisering enten er ulisensiert, ustabil eller forbudt
var
Pdf: TPDFlib;
Target: TFileStream;
begin
Pdf := TPDFlib.Create;
Target := TFileStream.Create('handbook.docx', fmCreate);
try
Pdf.LoadFromFile('handbook.pdf', '');
Pdf.SaveDOCXToStream('1-40',
PDF_DOCX_INCLUDE_IMAGES or PDF_DOCX_DETECT_HEADINGS or
PDF_DOCX_PRESERVE_STYLES or PDF_DOCX_PRESERVE_PAGE_BREAKS,
Target);
finally
Target.Free;
Pdf.Free;
end;
end;
Bildedata skrives etter hvert som hver side prosesseres fremfor å samles og legges til på slutten, slik at toppminnebruken følger én side fremfor hele dokumentet. Eksplisitt siderekkefølge bevares, og den valgte PDF-siden gjenopprettes etterpå, noe som betyr noe når eksporten er ett trinn inne i en lengre jobb som hadde en side valgt av andre grunner
Hva får du igjen for deterministisk pakking?
Byte-for-byte-reproduserbarhet. To konverteringer av samme inndata med samme alternativer produserer samme pakke, noe som betyr at du kan hashe utdataen for å oppdage endringer, diffe to bygg av et generert dokument, og cache aggressivt uten å bekymre deg for at identisk inndata produserte et annet artefakt
Office-automatisering kan ikke love det. Den bygger inn tidsstempler, revisjonsidentifikatorer og maskinavhengige metadata, slik at samme dokument konvertert to ganger blir forskjellig på måter som umuliggjør hashing. Det samme resonnementet ligger bak de deterministiske filidentifikatorene omtalt i deterministiske PDF-ID-er for reproduserbare bygg: når utdataen er reproduserbar, blir verifisering en sammenligning i stedet for en inspeksjon
Hvor utdataen er god, og hvor den ikke er det
Vær ærlig med brukerne dine om dette, for konverteringskvaliteten varierer mer med inndataen enn med konverteren. Taggede PDF-er og rent genererte forretningsdokumenter, fakturaer, rapporter, kontrakter, konverterer godt: overskrifter havner som overskrifter, tabeller overlever, lister nummereres riktig på nytt i Word. Akademiske to-spalte-layouter konverterer akseptabelt hvis spaltegeometrien er regelmessig. Tabeller som strekker seg over sideskift, settes sammen igjen ved slutning og deles noen ganger opp. Sterkt designet markedsføringsmateriell, der tekst er plassert for visuell effekt fremfor i leserekkefølge, konverterer dårlig, og ingen mengde slutning retter opp i det
Skannede dokumenter er et helt eget tilfelle. En side som er ett stort bilde, inneholder ingen tekstobjekter, så det er ingenting å eksportere før det finnes et tekstlag; OCR-veien som produserer et slikt lag, er en forutsetning, ikke et valg. Før du kjører en stor batch, bør du ta stikkprøver av et dusin representative filer og se på utdataen, og vurdere å telle opp sideelementer først, som beskrevet i tekstsøk og opptelling av sideelementer, for å se hva sidene faktisk inneholder
For assistent- og hentepipeliner er Markdown-veien vanligvis det bedre målet: overskrifter blir bitgrenser, tabeller forblir lesbare som pipe-tabeller, og sidemarkører gir hver bit en siterbar plassering. For menneskelig redigering er DOCX svaret, fordi det brukeren vil ha, ikke er teksten, men muligheten til å endre den
PDFlibPas er et PDF-bibliotek for Delphi, C++Builder og Lazarus med matchende DLL- og ActiveX-grensesnitt, så de samme eksportkallene er tilgjengelige fra C#, C++ eller skriptverter. Full dokumentasjon og en prøvebygg finnes på PDFlibPas sin side for Delphi PDF-bibliotek