Technický článek

Export listů Excelu do PDF v Delphi bez Office

Chcete-li exportovat list Excelu do PDF z Delphi nebo C++Builderu bez nainstalovaného Office, zavolejte `SaveAsPDF` na listu nebo sešitu HotXLS. HotXLS je nativní komponenta Excelu pro VCL a její export z listu do PDF převádí použitý rozsah listu (UsedRange) do samostatného souboru PDF 1.4, přičemž mapuje šířky sloupců Excelu a zobrazovaný text buněk na stránky A4 s automatickým stránkováním na více stránek. Na vykreslování se nepodílí žádná kopie Excelu, žádný ovladač tiskárny ani žádná externí DLL

HotXLS přistupuje k PDF jako k formátu pro prezentaci dat, což je sourozenec jeho cest pro export do CSV, TSV a HTML, spíše než jako k pixelově přesnému vykreslovacímu enginu. Export reprodukuje tabulkový obsah a rozvržení: hodnoty, které vidíte v mřížce, proporce sloupců a mřížku kolem buněk. Toto vymezení je důležité, protože předem nastavuje upřímné očekávání, a zbytek tohoto článku je o tom, kde přesně tato hranice leží

Jak převést Excel do PDF v Delphi bez Office?

Nejkratší cestou je jediné volání. `TXLSWorksheet` vystavuje `SaveAsPDF(FileName)` a `SaveAsPDF(Stream)`, a `TXLSWorkbook` vystavuje stejná dvě přetížení, která se předávají aktivnímu listu. Každá z nich vrací `Integer`, 1 při úspěchu a -1 při selhání, takže se můžete rozhodnout podle výsledku bez nutnosti obalovat volání vlastním ošetřením výjimek

uses
  lxHandle;

var
  Book: TXLSWorkbook;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('sales-june.xlsx');
    // Vykreslit použitý rozsah aktivního listu přímo do report.pdf.
    if Book.SaveAsPDF('report.pdf') = 1 then
      Writeln('PDF written');
  finally
    Book.Free;
  end;
end;

Když zavoláte `SaveAsPDF` na listu, HotXLS exportuje jeho `UsedRange`, což je ohraničující rámeček každé vyplněné buňky. Přetížení sešitu je pohodlná metoda, která deleguje práci na aktivní list, takže report s více listy buď prochází listy, které potřebuje, nebo před voláním vybere aktivní list. Neexistuje žádný režim celého sešitu, který by v jednom průchodu spojil všechny karty za sebou: každé volání vykreslí jeden list nebo jeden rozsah

Jak HotXLS převádí použitý rozsah na stránky PDF?

HotXLS prochází použitý rozsah buňku po buňce a rozvrhuje jej jako stránkovanou mřížku. Geometrie sloupců pochází přímo z Excelu: šířka každého sloupce se převede z jednotky šířky Excelu na typografické body s minimálním prahem, aby se žádný sloupec nesrazil na minimum. Když jsou sloupce dohromady širší než použitelná stránka, HotXLS je rovnoměrně zmenší, aby se vešly; pokud se již vejdou, ponechá je v jejich přirozené šířce, místo aby je roztahovalo přes celý list

Řádky pak plynou dolů po stránce, dokud by další nepřekročil spodní okraj, v tomto bodě HotXLS otevře novou stránku a pokračuje, takže list s tisícem řádků se stránkuje sám bez vašeho přičinění o konce stránek. Každá buňka tiskne svůj `FormattedText`, což je zobrazovaný řetězec vytvořený po aplikaci formátu čísla, takže datum se zobrazuje jako datum, které list ukazuje, a buňka s měnou si zachovává své oddělovače tisíců a symbol. Text, který přetéká ze svého sloupce, se ořízne na šířku buňky, místo aby přetékal k sousedovi

Ovládání orientace, okrajů a velikosti písma

Pro cokoli nadrámec výchozího rozvržení ovládejte exportér přímo. `TXLSPDFExport` je třída stojící za jednořádkovými pomocníky a publikuje tři vlastnosti: `Orientation` (`xlsPdfPortrait` nebo `xlsPdfLandscape`, na výšku ve výchozím nastavení), `Margin` (body, výchozí 40) a `FontSize` (body, výchozí 9). Nastavte je před voláním `SaveAsPDF` a převezme je celý dokument

uses
  lxHandle, lxPDF;

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('wide-ledger.xlsx');
    Exporter := TXLSPDFExport.Create;
    try
      Exporter.Orientation := xlsPdfLandscape;  // vejít široké listy na stránku
      Exporter.Margin := 28;                     // těsnější okraj stránky, v bodech
      Exporter.FontSize := 8;                    // hustší řádky
      Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

`TXLSPDFExport` také přijímá rozsah namísto celého listu prostřednictvím `SaveAsPDF(Range: IXLSRange; ...)`, což je způsob, jakým exportujete souhrnný blok z listu, který obsahuje také pomocné výpočty. Toto přetížení rozsahu je stejné, o které se interně opírá pomocník listu, takže rozvržení, měřítko a stránkování se chovají identicky, ať už mu předáte celý použitý rozsah nebo ručně vybraný výběr

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
  Summary: IXLSRange;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    // Exportovat pouze souhrnný blok, nikoli pomocné sloupce vedle něj.
    Summary := Book.Sheets[1].Range['A1', 'F20'];
    Exporter := TXLSPDFExport.Create;
    try
      Exporter.SaveAsPDF(Summary, 'summary.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

Proč HotXLS neintegruje žádné písmo: kompromis Helvetica a WinAnsi

HotXLS zapisuje text s vestavěným písmem Helvetica v PDF a kódováním `WinAnsiEncoding`, což je záměrná volba s nulovými závislostmi, avšak s jedním skutečným limitem. Vzhledem k tomu, že Helvetica je jedním ze standardních 14 písem, které již každý vyhovující prohlížeč PDF nese, exportér neintegruje vůbec žádný soubor písma: soubor zůstává malý a otevírá se kdekoli, bez nutnosti licencovat nebo dodávat cokoli dalšího. Cenou za tuto volbu je znaková sada, kterou může stránka zobrazit

`WinAnsiEncoding` pokrývá sadu Windows-1252, takže latinský text, běžná interpunkce a obvyklá západoevropská diakritika se vykreslují správně, a HotXLS skládá hrstku typografických znaků, kudrnaté uvozovky, en a em pomlčky a znak eura do jejich CP1252 pozic. Znaky mimo tento rozsah, jako jsou znaky CJK, cyrilice, řečtina a arabština, se na stránce zhroutí do otazníku. Pokud vaše listy obsahují nelatinský text, je tento exportér nesprávným nástrojem a pro danou práci se hodí plnohodnotný vykreslovač PDF se stylováním

Kde export z listu do PDF končí

HotXLS vykresluje obsah a strukturu, nikoli plný vizuální styl listu. Výplně buněk, styly ohraničení na jednotlivých hranách, písma a barvy pro jednotlivé buňky, grafy a vložené obrázky stojí mimo to, co exportér kreslí; to, co dostanete, je textová mřížka s jednotnými čarami mřížky. To je stejný kontrakt, který dodržují exportéry do HTML a RTF, a je to ten správný pro report nebo předání dat, kde význam nesou čísla a nikoli motiv

Pokud je cílem stylizovaný dokument v souladu s firemní identitou, obvyklým vzorem je nejprve sestavit čísla v šabloně tabulky, což podrobně pokrývá pracovní postup generování reportů řízených šablonami. A protože se nic z toho nedotýká COM ani běžící instance Excelu, pipeline zapadá do stejného automatizačního modelu bez Office, který HotXLS používá všude: čistý Pascal, nasaditelný na headless serveru, bez nutnosti licencovat interop nebo se o něj starat

Samostatné PDF, bajt po bajtu

HotXLS sestavuje strukturu souboru PDF ručně a počítá jeho křížovou tabulku (cross-reference table) z přesných bajtových offsetů, což je důvod, proč se výstup otevírá v každém prohlížeči. Při serializaci každého objektu zaznamená HotXLS počáteční offset tohoto objektu před připojením jeho bajtů a poté posune průběžnou pozici o délku, kterou právě zapsal, takže tabulka `xref` přistane přesně na každém objektu a `startxref` označuje, kde tato tabulka začíná. Prohlížeč, který najde tyto offsety posunuté byť jen o jediný bajt, celý soubor odmítne, což činí z vlastnoručně spočítaného offsetu nosný kontrakt exportéru

Tento kontrakt nese jeden přísný důsledek, který stojí za to znát. Uzel Pages se zapisuje jako první jako objekt 1, ale jeho seznam dceřiných stránek není znám, dokud nejsou emitovány všechny stránky, takže jej HotXLS rezervuje jako zástupný symbol a před spuštěním průchodu offsetů do něj doplní konečné dceřiné stránky a počet, nikdy ne poté. Jakmile jsou bajty objektu změřeny pro `xref`, jsou zmrazeny: změna jediného bajtu by posunula každý následující offset a tabulku poškodila. Je to malá disciplína, která přináší standardům vyhovující PDF 1.4 bez jakékoli knihovny pod ním

Metody `SaveAsPDF` a třída `TXLSPDFExport` zde ukázané se dodávají s komponentou HotXLS Delphi Excel Component, spolu s exportéry do CSV, HTML a RTF a kompletním listovým API pro Delphi a C++Builder