PDFlibPas konverterer PDF-indhold til to redigerbare formater uden Office-automatisering. ExportPageMarkdown og ExportDocumentMarkdown returnerer semantisk Markdown med udledte overskrifter, nummererede og ikke-nummererede lister og pipe-tabeller, mens SaveDOCXToFile og SaveDOCXToStream skriver en WordprocessingML-pakke, der indeholder afsnit, overskrifter, native listenummerering, registrerede tabeller, skrifttypeformatering, sideskift og placerede PNG-billeder
Begge kører udelukkende i Pascal, på en server, uden installeret Word og uden COM. Den begrænsning er grunden til, at funktionen findes i et PDF-bibliotek frem for i et desktopværktøj
Hvorfor er "PDF til Word" reelt svært?
Fordi en PDF-side ikke indeholder afsnit. Den indeholder tekstvisningsoperatorer, der placerer forløb af glyffer ved koordinater, i den rækkefølge producenten udsendte dem, uden nogen forpligtelse til at angive, at to forløb hører til samme sætning, endsige samme listepunkt. Formatet blev designet til at beskrive en trykt side nøjagtigt, og det lykkes med det ved at kassere den struktur, der frembragte siden
Så hver konverter må genopbygge det, generatoren smed væk. Linjegruppering kommer fra lodret afstand og grundlinjejustering. Afsnitsgrænser kommer fra ændringer i afstand og indrykning. En overskrift er en linje, hvis skrifttype er større eller tungere end brødteksten, og som står adskilt fra det, der følger. En liste er en række af afsnit, der begynder med et punkttegn eller et talmønster. En tabel er et gitter af tekstblokke, hvis kanter linjer op på tværs af rækker og kolonner. Hver eneste af disse er en slutning, og en slutning giver et godt resultat på dokumenter, der følger almindelige typografiske konventioner, og et middelmådigt et på dokumenter, der ikke gør
Taggede PDF'er er undtagelsen, og en stor en. Når dokumentet bærer et strukturtræ, registreres afsnits-, overskrifts-, liste- og tabelroller frem for at blive gættet, hvilket er grunden til, at tilgængelighedsarbejdet beskrevet i tagget PDF-tilgængelighedsstruktur også betaler sig i konverteringskvalitet. Hvis du kontrollerer producenten, er tagging af dit output den enkeltstående mest effektive ting, du kan gøre for alle, der senere skal konvertere det
Markdown-eksport, én side ad gangen
Markdown-stien er den, man griber til, når destinationen er en tekstpipeline: et dokumentationssite, et søgeindeks, et hentningskorpus til en assistent. Indstillinger er en bitmaske: PDF_MARKDOWN_INCLUDE_PAGE_MARKERS, PDF_MARKDOWN_DETECT_HEADINGS, PDF_MARKDOWN_PRESERVE_STYLES, hvor 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 sideinterval, streamet til disk som UTF-8 uden BOM
Pdf.SaveMarkdownToFile('1-40',
PDF_MARKDOWN_DETECT_HEADINGS or PDF_MARKDOWN_PRESERVE_STYLES,
'handbook.md');
finally
Pdf.Free;
end;
end;
Sidemarkører tjener deres værd i hentningsarbejde. Et tekststykke, der bærer den side, det stammer fra, kan citeres præcist, og en læser, der følger citatet, lander, hvor påstanden faktisk er. Slå dem fra, når Markdown'en er bestemt til menneskelig læsning, hvor sidegrænser fra kildens layout er støj
Streaming-indgangspunkterne betyder noget for store dokumenter. SaveMarkdownToStream og SaveMarkdownToFile skriver UTF-8 én side ad gangen og bufrer ikke det komplette output, så en 900-siders manual ikke først bliver en 900-siders streng i hukommelsen. Fraværet af et byte-order mark er også bevidst: en BOM i en Markdown-fil forvirrer et overraskende antal statiske site-generatorer og diff-værktøjer
DOCX uden Office på maskinen
DOCX-skriveren producerer selve pakken: ZIP-poster skrevet som rå Deflate med CRC-tjek, WordprocessingML-delene og de relationer, der binder dem sammen. Intet kalder ind i Word, hvilket betyder, at konverteringen kører på en headless server, inde i en servicekonto, i en container, alle de steder, hvor Office-automatisering enten er ulicenseret, 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;
Billeddata skrives, efterhånden som hver side behandles, i stedet for at blive samlet og tilføjet til sidst, så spidsforbruget af hukommelse følger én side frem for hele dokumentet. Eksplicit siderækkefølge bevares, og den valgte PDF-side gendannes bagefter, hvilket betyder noget, når eksporten er ét trin i et længere job, der havde en side valgt af andre grunde
Hvad giver deterministisk pakning dig?
Byte-for-byte-reproducerbarhed. To konverteringer af samme input med samme indstillinger producerer samme pakke, hvilket betyder, at du kan hashe outputtet for at opdage ændringer, diffe to builds af et genereret dokument og cache aggressivt uden at bekymre dig om, at et identisk input producerede et andet artefakt
Office-automatisering kan ikke love det. Den indlejrer tidsstempler, revisions-id'er og maskinafhængige metadata, så det samme dokument konverteret to gange adskiller sig på måder, der ødelægger hashing. Den samme tankegang driver de deterministiske fil-id'er, der diskuteres i deterministiske PDF-id'er for reproducerbare builds: når output er reproducerbart, bliver verifikation en sammenligning i stedet for en inspektion
Hvor outputtet er godt, og hvor det ikke er
Vær ærlig over for dine brugere om dette, fordi konverteringskvaliteten varierer mere med inputtet end med konverteren. Taggede PDF'er og rent genererede forretningsdokumenter, fakturaer, rapporter, kontrakter, konverterer godt: overskrifter lander som overskrifter, tabeller overlever, lister nummereres korrekt om i Word. To-spalters akademiske layouts konverterer acceptabelt, hvis spaltegeometrien er regelmæssig. Tabeller, der spænder over sideskift, genopbygges ved slutning og bliver nogle gange delt. Stærkt designet marketingmateriale, hvor tekst er placeret for visuel effekt frem for i læserækkefølge, konverterer dårligt, og ingen mængde slutning retter det
Scannede dokumenter er et helt separat tilfælde. En side, der er ét stort billede, indeholder ingen tekstobjekter, så der er intet at eksportere, før et tekstlag findes; OCR-stien, der producerer et, er en forudsætning, ikke en mulighed. Før du kører en stor batch, så tag stikprøver af et dusin repræsentative filer, og se på outputtet, og overvej at opremse sideelementer først, som beskrevet i tekstsøgning og opremsning af sideelementer, for at se, hvad siderne faktisk indeholder
For assistent- og hentningspipelines er Markdown-stien normalt det bedre mål: overskrifter bliver til chunk-grænser, tabeller forbliver læsbare som pipe-tabeller, og sidemarkører giver hver chunk en citerbar placering. Til manuel redigering er DOCX svaret, fordi det, brugeren vil have, ikke er teksten, men muligheden for at ændre den
PDFlibPas er et Delphi-, C++Builder- og Lazarus-PDF-bibliotek med matchende DLL- og ActiveX-grænseflader, så de samme eksportkald er tilgængelige fra C#, C++ eller scriptværter. Fuld dokumentation og en trial-build findes på PDFlibPas' produktside for Delphi PDF-biblioteket