Технічна стаття

Експорт листів Excel у PDF в Delphi без використання Office

Щоб експортувати лист Excel у PDF з Delphi або C++Builder без встановленого Office, викличте метод SaveAsPDF для листа або книги HotXLS. HotXLS — це нативний VCL-компонент Excel, і його функція експорту в PDF рендерить заповнений діапазон листа у самостійний файл PDF 1.4, відображаючи ширину стовпців Excel та відображуваний текст комірок на сторінках формату A4 з автоматичним розбиттям на сторінки. У цьому процесі не беруть участі ні Excel, ні драйвер принтера, ні будь-які зовнішні DLL.

HotXLS розглядає PDF як формат представлення даних (аналогічно до своїх шляхів експорту в CSV, TSV та HTML), а не як графічний рушій з точністю до пікселя. Експорт відтворює табличний вміст та макет: значення в сітці, пропорції стовпців та межі комірок. Таке розуміння є важливим для правильних очікувань, і в цій статті детально описано можливості та обмеження цього підходу.

Як конвертувати Excel у PDF в Delphi без Office?

Найкоротший шлях — це один виклик. Клас TXLSWorksheet надає методи SaveAsPDF(FileName) та SaveAsPDF(Stream), а TXLSWorkbook містить такі самі два перевантажені методи, які перенаправляють запит на активний лист. Кожен метод повертає значення типу Integer (1 у разі успіху та -1 у разі збою), тому ви можете обробити результат без використання блоків обробки винятків.

uses
  lxHandle;

var
  Book: TXLSWorkbook;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('sales-june.xlsx');
    // Render the active sheet's used range straight to report.pdf.
    if Book.SaveAsPDF('report.pdf') = 1 then
      Writeln('PDF written');
  finally
    Book.Free;
  end;
end;

При виклику SaveAsPDF для робочого листа HotXLS експортує його заповнений діапазон (UsedRange) — тобто прямокутник, що охоплює всі заповнені комірки. Перевантажений метод книги є просто зручною обгорткою, що перенаправляє виклик на активний лист, тому для експорту багатолистового звіту потрібно або обійти в циклі необхідні листи, або вибрати активний лист перед викликом. Глобального режиму експорту всієї книги в один файл за один прохід немає: кожен виклик рендерить один конкретний лист або діапазон.

Як HotXLS перетворює заповнений діапазон на сторінки PDF?

HotXLS обходить заповнений діапазон комірка за коміркою та розбиває його на сторінки. Геометрія стовпців береться безпосередньо з Excel: ширина кожного стовпця конвертується з одиниць Excel у друкарські пункти з мінімальним порогом, щоб стовпець не зникав повністю. Якщо сумарна ширина стовпців перевищує ширину сторінки, HotXLS пропорційно масштабує їх; якщо вони поміщаються на сторінці, вони зберігають свою оригінальну ширину без розтягування на весь лист.

Рядки послідовно розташовуються на сторінці, і коли наступний рядок виходить за межі нижнього поля, HotXLS створює нову сторінку, завдяки чому великий лист на тисячу рядків автоматично розбивається без вашої участі. Кожна комірка виводить своє форматоване значення (FormattedText), тобто рядок, отриманий після застосування формату комірки. Наприклад, дати та грошові значення відображаються точно так само, як і на листі, зберігаючи роздільники тисяч та символи валют. Текст, який виходить за межі стовпця, обрізається по межі комірки, а не перекриває сусідні комірки.

Керування орієнтацією, полями та розміром шрифту

Для глибшого налаштування макета керуйте експортером безпосередньо. Клас TXLSPDFExport лежить в основі стандартних методів і має три основні властивості: орієнтація сторінки Orientation (xlsPdfPortrait або xlsPdfLandscape, за замовчуванням книжкова), поля Margin (у пунктах, за замовчуванням 40) та розмір шрифту FontSize (у пунктах, за замовчуванням 9). Встановіть їх перед викликом SaveAsPDF, і вони будуть застосовані до всього документа.

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;  // fit wide sheets on the page
      Exporter.Margin := 28;                     // tighter page margin, in points
      Exporter.FontSize := 8;                    // denser rows
      Exporter.SaveAsPDF(Book.ActiveSheet, 'ledger.pdf');
    finally
      Exporter.Free;
    end;
  finally
    Book.Free;
  end;
end;

TXLSPDFExport також приймає діапазон замість усього листа через метод SaveAsPDF(Range: IXLSRange; ...). Це дозволяє експортувати окремий підсумковий блок без зайвих обчислювальних стовпців. Цей метод із перевантаженням діапазону використовується і самим класом листа всередині програми, тому макет, масштабування та пагінація працюватимуть однаково.

var
  Book: TXLSWorkbook;
  Exporter: TXLSPDFExport;
  Summary: IXLSRange;
begin
  Book := TXLSWorkbook.Create;
  try
    Book.Open('quarter.xlsx');
    // Export only the summary block, not the scratch columns beside it.
    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;

Чому HotXLS не вбудовує шрифти: компроміс Helvetica та WinAnsi

HotXLS записує текст, використовуючи вбудований у PDF шрифт Helvetica та кодування WinAnsiEncoding. Це свідомий вибір для уникнення залежностей, але він має одне обмеження. Оскільки Helvetica є одним із 14 стандартних шрифтів, які підтримує кожен переглядач PDF, експортер взагалі не вбудовує файли шрифтів: завдяки цьому файл залишається дуже малим та відкривається всюди без додаткового ліцензування. Але платою за це є обмежений набір символів, які можна відобразити.

Кодування WinAnsiEncoding охоплює набір Windows-1252, тому латиниця, розділові знаки та символи західноєвропейських мов відображаються коректно. Також HotXLS відображає деякі друкарські символи (фігурні лапки, тире та знак євро) у відповідні позиції CP1252. Символи поза цим діапазоном — кирилиця, ієрогліфи, грецькі або арабські літери — на сторінці будуть замінені на знаки запитання. Якщо ваші листи містять нелатинський текст, цей експортер не підійде, і в такому разі потрібен повноцінний PDF-рендерер.

Межі можливостей експорту листа в PDF

HotXLS рендерить лише вміст та структуру, а не повне візуальне оформлення листа. Заливка комірок, індивідуальні стилі меж, шрифти та кольори кожної комірки, діаграми та вбудовані зображення не підтримуються експортером. Ви отримуєте лише текстову сітку з однаковими лініями меж. Це аналогічно до роботи експортерів у HTML та RTF, і цього цілком достатньо для звітів або передачі даних, де важливі саме цифри, а не оформлення.

Якщо вам потрібен стилізований документ відповідно до бренду, зазвичай спочатку формують дані у шаблоні таблиці, що детально описано у статті про генерацію звітів на основі шаблонів. Оскільки цей процес не використовує COM або запущений екземпляр Excel, він повністю вписується в модель автоматизації без використання MS Office: це чистий код на Pascal, який можна запускати на сервері без графічної оболонки.

Самостійний PDF байт-в-байт

HotXLS формує структуру файлу PDF вручную та розраховує таблицю перехресних посилань (cross-reference) на основі точних байтових зміщень. Саме тому результат відкривається в будь-кому переглядачі. При серіалізації кожного об'єкта HotXLS записує його початкове зміщення перед додаванням байтів, а потім зміщує поточну позицію на записану довжину. Це забезпечує точне позиціонування таблиці xref на об'єктах, а мітка startxref точно вказує на її початок. Якщо зміщення будуть зсунуті хоча б на один байт, переглядач відхилить весь файл, тому точний розрахунок зміщень є критично важливим для роботи експортера.

Це правило має один важливий наслідок. Вузол сторінок (Pages) записується першим як об'єкт 1, но його список дочірніх сторінок стає відомим лише після завершення обробки всього документа. Тому HotXLS спочатку резервує для нього місце, а потім вписує фінальний список сторінок та їх кількість безпосередньо перед розрахунком зміщень. Після вимірювання байтів об'єкта для таблиці xref будь-які зміни заборонені: зміна навіть одного байта змістить усі наступні адреси та пошкодить таблицю. Такий жорсткий порядок дозволяє створювати повністю сумісний файл стандарту PDF 1.4 без сторонніх бібліотек.

Методи SaveAsPDF та клас TXLSPDFExport постачаються у складі компонента HotXLS Delphi Excel Component разом із експортерами в CSV, HTML та RTF, а також повним API для роботи з листами в Delphi та C++Builder.