Delphi сохранить excel как pdf
Когда задача стоит “Сохранить из Delphi или Lazarus в Excel” у разработчика просто огромный выбор - частично он описан в статье “Как записать в XLS Biff8 из Delphi”, там же я вкратце расписал, почему это плохой выбор. А что же тогда хорошо? А хорошо - сохранять в новый (ну, относительно новый) XML XLSX.
"XML является технологией, разработанной для управления структурированными данными и отображения этих данных в виде удобочитаемого текстового файла. Язык XML соответствует отраслевым стандартам и может быть обработан многими базами данных и приложениями. С помощью XML многие разработчики могут создавать собственные настроенные теги, структуры данных и схемы. В целом XML существенно облегчает определение, передачу, проверку и интерпретацию данных в различных базах данных, приложениях и организациях. "
Но Microsoft не был бы собой, если бы, традиционно не попытался сделать “свой собственный XML - c блэкджеком и ячейками!”. А потому у Excel на самом деле есть не один а целых два(!) XML-стандарта для хранения Excel-файлов: более ранний и более правильный.
Как я уже неоднократно указывал, FastReport позволяет сохранять из Delphi и Lazarus ваши документы, отчёты информацию в великое множество форматов. Сделать сам отчёт - легче лёгкого, можно посмотреть в прошлых статьях - единственное, опять остановлюсь-отмечу - следите за выравниванием ваших объектов, чтобы результирующие табличные форматы получались красивыми качественными! Так вот - для Excel XML у нас два разных(!) фильтра экспорта. Вот, полюбуйтесь!
Видим окно предварительного просмотра и кнопку “сохранить”
“Эй, уважаемый, а мне, простому программисту чем пользоваться?!” - спросите вы и будете совершенно правы. Короткий ответ - 2007 XML, более поздний. А ниже я расскажу, почему.
Понятно, что программист никогда не делает “потому, что захотелось” - хочется чего-либо пользователю. В чём же разница в этих двух форматах с точки зрения пользователя, жаждущего получить таблицу Excel из приложения? Со стороны пользователя разница примерно как между rft без картинок и полноценным файлом MS Word, и первый в реальной жизни почти не встречается. В простом XML нет, ни стилей ни картинок. Просто таблица в XML. Но в момент, когда его придумывали, и выбора-то особо не было - это был огромный шаг вперёд для MS Excel. А вот Microsoft Excel 2007 XML может хранить картинки , там есть стили и тд. Это контейнер OOML.
Углубиться в тему XML используемого с 2007 и далее можно тут - там целый мир!
А мы просто сравним два варианта сохранения в XML и XLSX XML и решим, какой использовать рациональнее и в каких случаях.
Экспорт в XML - более простой. Экспортируются только текстовые объекты. Изображения, графики, карты, штрихкоды, форматирование TfrxRichView, HTML-тэги и фоновое изображение в результирующий Excel XML не попадут.
Настройки экспорта – большее визуальное соответствие с начальным вариантом (WYSIWYG), разрыв страницы, и continuous - непрерывный документ с пропуском промежуточных заголовков и подвалов страниц.
Как будет выглядеть результат: без разделения, разделение на листы с использованием страниц отчёта, Use print on parent - каждой странице TfrxReportPage в шаблоне отчёта соответствует лист книги (при условии, что TfrxReportPage.PrintOnParent = False) или же поделить на части с задаваемым количеством строк.
Открыть после экспорта – результирующий файл будет открыт сразу же после экспорта программой Microsoft Excel (Ну или что у пользователя в системе ассоциировано с файлами расширения XLSX для их открытия).
Сравним получившиеся XLSX и Excel XML
Первый скриншот - это результат сохранения в формате XLSX и как мы видим, данный формат не поддерживает данные сложнее обычного текста. А вот второй скриншот показывает нам все возможности формата XML, т.е. полную поддержку штрихкодов, картинок. Если говорить про вес файлов, то результат ожидаемый: XLSX 48,0 КБ, XML 40,0 КБ.
Разберёмся подробнее почему XLSX весит больше XML. За основу взяли вот этих прекрасных рыбок. Данный документ содержит много текста, табличные данные и 30 фотографий. Для большей наглядности сравним ещё и нестареющий Excel 97, о котором мы говорили в другой статье.
Excel 97 - Формат двоичных файлов, бинарник (biff8), про сжатие тут не слышали и потому вес файла столь велик. В отличии от более позднего XML, формат 97 года поддерживает все виды изображений.
Excel table (XML) - Ранняя версия XLSX, где данные хранятся как простые одиночные монолитные XML-файлы, что делает их довольно большими, по сравнению с OOXML и устаревшими двоичными форматами Microsoft Office. Но на скриншоте вес минимален - возмутился бы каждый! Ответ прост, данный вес указан за документ, где отображаться будет только текст. А теперь представьте, если бы тут всё-таки была поддержка картинок, да он бы занимал кучу места, ведь о сжатии на этом моменте всё ещё никто не знает. Кроме того, встроенные элементы, такие как изображения, хранятся в виде двоичных закодированных блоков, но недоступны для отображения.
Excel 2007 XLSX (XML) - Microsoft взяли лучшее от прошлых форматов и внедрили сжатие файлов. Размер документа приблизительно на 50-75 процентов меньше, чем в предыдущих версиях.
Ограниченные возможности и возможные ограничения формата XLSX Excel 2007
Количество столбцов увеличилось с 256 до 16 384, количество строк в листе возросло с 65 536 до 1 048 576. Ускорены вычисления в больших листах, содержащих множество формул, благодаря поддержке Office Excel 2007 нескольких процессоров и многопоточных наборов микросхем.
← →voronkov ( 2002-07-08 12:21 ) [0]
Задача такая - надо открыть в фоновом режиме Excel, напихать туда чего-то и сохранить в заранее известном файле. Все это делается, кроме записи. При вызове метода Save все время выскакивает диалог записи файла, мне он совершенно не нужен. Подскажите пожалуйста работающий пример функции SaveAs объекта Excel.
← →troits ( 2002-07-08 12:44 ) [1]
Работающего примера нет, но попробуй вызвать метод
SaveAs(Filename: OleVariant; .
у WorkBook - а. (Например Application.ActiveWorkBook.SaveAs. )
Мне кажется, что проблем быть не должно.
voronkov ( 2002-07-08 13:14 ) [2]
Я вызываю этот метод, но в нем куча параметров. Некоторые я проставил, но что-то не подходит, хотя все компилируется. Я не могу найти на все эти параметры описания, поэтому выскакивает ошибка, что-то типа "invalid index" или что-то подобное. Вот вся эта ботва из файла excel97.pas :
procedure SaveAs(const Filename: WideString; FileFormat: OleVariant; Password: OleVariant;
WriteResPassword: OleVariant; ReadOnlyRecommended: OleVariant;
CreateBackup: OleVariant; AddToMru: OleVariant; TextCodepage: OleVariant;
TextVisualLayout: OleVariant; lcid: Integer); safecall;
Что такое, например TextCodepage? Я потому и прошу работающий пример, потому что кто-то уже наверняка на эти грабли наступал. Но неужели все открывают Excel, а потом заставляют юзверя руками все это сохранять, нелогично как-то, особенно если это отчет формируется в пакете и куда-то отсылается, как в моем случае.
← →USAtyj ( 2002-07-08 13:29 ) [3]
У меня код такой работает:
.
if FileExists(FileName) then // если такой файл уже есть - удаляем, иначе сохранить не получится.
DeleteFile(PChar(FileName));
Excel.ActiveWorkBook.SaveAs(FileName);
Excel.ActiveWorkBook.Close(SaveChanges := True);
Excel:=UnAssigned;
.
А то, что ты написал - это, кажется, в Word так сохранять надо.
TTCustomDelphiMaster ( 2002-07-08 13:33 ) [4]
А я так сохраняю файл
Workbook.SaveCopyAs(dir+destname30);
voronkov ( 2002-07-08 16:38 ) [5]
Да, господа. Типа все хорошо, но только на словах. Попробовал как сказал USAtyj, но все та же песня, компилятор говорит, что не хватает параметров, все параметры я перечислил выше, никакие они не word-овские.
Если делать как у TTCustomDelphiMaster, то там тоже не хватает одного параметра, а именно lcid. Я ставлю 0, все компилируется, но выдетает Access violation. Я создаю файл из шаблона, может это на что-то влияет. Блин, как у вас все это работает, может тут тайна какая-то, может можно как-то компилятор убедить компилировать без параметров?
voronkov ( 2002-07-08 16:48 ) [6]
Господа, я тут одурел от жары. Я пытался записывать после того как уже освободил все объекты.
Запись работает только со всеми параметрами, все записывается, но некоторые параметы нужны. Всем большое спасибо.
знаю что произвести конвертацию из doc и xls в pdf можно как минимум тремя способами
1) использовать printout на виртуальный принтер создающий pdf
2) с использованием компонент FastReport
3) с использованием библиотеки adobepdfmakerx.dll
первый способ вполне не сложный и я знаю как реализовать. но не совсем удобно устанавливать дополнительное по для создания пдф к тому же принтер сам по себе работает немного тормознуто
где переменная fileformat типа olevariant может принимать значения:
Шестнадцатеричная Символьное обозначение Смысл
$00000000 wdformatdocument Документ word
$00000004 wdformatdostext Простой текст
$00000006 wdformatrtf Файл rtf
и кстати. огромное спасибо Anatoly Podgoretsky за перевод книги IndyInDepth
мне как раз счс нужно много информации по работе с почтой в инди причем не на примере MailClient от разработчиков. вообще столько всего есть на сайте. запрятали от поисковиков =)
мне как раз нужно качество и главное. скорость создания
а можно поподробнее.
>salexn (27.06.08 17:47) [32]
мне если честно также все меньше и меньше верится в это. в принципе из тех трех способов сработал только принтаут
примеров конечно много нашел и узнал основы работы с OpenOffice
но так и не могу добраться до экспорта в pdf.
uses ComObj, Variants, sysutils;
type
TOOoWriter = class(TObject)
private
fOpenOffice : Variant;
fDocument : Variant;
fConnected : boolean;
fDocumentOpened : boolean;
fDesktop : Variant;
fHTMLSrc : boolean;
function MakePropertyValue(PropName:string; PropValue:variant):variant;
public
Constructor Create;
destructor Destroy; override;
function Connect : boolean;
procedure Disconnect;
function OpenDocument(Filename:string):boolean;
procedure SaveToPDF(FileName:string);
procedure CloseDocument;
end;
procedure TOOoWriter.CloseDocument;
begin
if fDocumentOpened then
begin
fDocument.Close(false);
fDocumentOpened := false;
fDocument := Unassigned;
fDesktop.Terminate;
fDesktop := UnAssigned;
end;
end;
function TOOoWriter.Connect: boolean;
begin
if VarIsEmpty(fOpenOffice) then
fOpenOffice := CreateOleObject("com.sun.star.ServiceManager");
fConnected := not (VarIsEmpty(fOpenOffice) or VarIsNull(fOpenOffice));
Result := fConnected;
end;
constructor TOOoWriter.Create;
begin
inherited;
CoInitialize(nil);
end;
destructor TOOoWriter.Destroy;
begin
CoUninitialize;
inherited;
end;
procedure TOOoWriter.Disconnect;
begin
if fDocumentOpened then
CloseDocument;
fConnected := false;
fOpenOffice := Unassigned;
end;
function TOOoWriter.MakePropertyValue(PropName: string;
PropValue: variant): variant;
var
Struct: variant;
begin
Struct := fOpenOffice.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
Struct.Name := PropName;
Struct.Value := PropValue;
Result := Struct;
end;
function TOOoWriter.OpenDocument(Filename: string): boolean;
var
wProperties : Variant;
wViewSettings : Variant;
wController : Variant;
begin
if not fConnected then
abort;
wProperties := VarArrayCreate([0, 0], varVariant);
//wProperties[0] := MakePropertyValue("Hidden", True);
wProperties[0] := MakePropertyValue("Hidden", "MS Word 97");
fDocument := fDesktop.loadComponentFromURL("file:///"+ StringReplace(FileName, "\", "/", [rfIgnoreCase, rfReplaceAll]) , "_blank", 0, wProperties);
fDocumentOpened := not (VarIsEmpty(fDocument) or VarIsNull(fDocument));
fHTMLSrc := pos(".htm", lowercase(extractfileext(Filename))) > 0;
if fDocumentOpened and fHTMLSrc then
begin
wController := fDocument.Getcurrentcontroller;
if not (VarIsEmpty(wController) or VarIsNull(wController)) then
begin
wViewSettings := wController.getviewsettings;
if not (VarIsEmpty(wViewSettings) or VarIsNull(wViewSettings)) then
wViewSettings.ShowOnlineLayout := false;
end;
wViewSettings := Unassigned;
wController := Unassigned;
end;
result := fDocumentOpened;
end;
procedure TOOoWriter.SaveToPDF(FileName: string);
var
wProperties: variant;
begin
if not (fConnected and fDocumentOpened) then
abort;
wProperties := VarArrayCreate([0, 3], varVariant);
if fHTMLSrc then
wProperties[0] := MakePropertyValue("FilterName", "writer_web_pdf_Export")
else
wProperties[0] := MakePropertyValue("FilterName", "writer_pdf_Export");
wProperties[1] := MakePropertyValue("CompressionMode", "1");
wProperties[2] := MakePropertyValue("Pages", "All");
wProperties[3] := MakePropertyValue("Overwrite", TRUE);
fDocument.StoreToURL("file:///"+ StringReplace(FileName, "\", "/", [rfIgnoreCase, rfReplaceAll]), wProperties);
end;
и вот код который использует модуль
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,ComObj,ActiveX;
type
TForm6 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
< Private declarations >
public
procedure MakePDF(InFileName, OutFileName:string);
< Public declarations >
end;
var
Form6: TForm6;
uses StripStringUnit1, OpenOfficePDF;
procedure TForm6.Button1Click(Sender: TObject);
var
inFilename,OutFilename : string;
begin
inFilename := "E:\Programming\work\Sources\other\crazy_mailer\coding\pdf\db\OpenOffice\Test2.d oc";
OutFilename :="E:\Programming\work\Sources\other\crazy_mailer\coding\pdf\db\OpenOffice\test2 .pdf";
MakePDF(infilename,OutFilename);
end;
procedure TForm6.MakePDF(InFileName, OutFileName:string);
var
wWriter : TOOoWriter;
begin
try
wWriter := TOOoWriter.Create;
try
if wWriter.Connect then
try
if wWriter.OpenDocument(InFileName) then
try
wWriter.SaveToPDF(OutFileName);
finally
wWriter.CloseDocument;
end;
finally
wWriter.Disconnect;
end;
finally
wWriter.free;
end;
except
on e:exception do
begin
Showmessage(e.message);
end;
end;
end;
end.
на выходе получается пдф-файл. но при открытии в акробате он пишет что файл поврежден если открыть пдф-файл в Writer то файл открывается
но мне нужно чтобы он открывался в акробате без проблем
А я и не знаю. Задачи такой никогда не стояло, а "просто так" делать у меня тупо времени нет. Но наверняка как-то можно.
Создаём новое VCL приложение в Delphi
Добавляем с вкладки "FastReport" на форму компоненты TfrxReport, TfrxPDFExport и TButton.
Делаем двойной клик на TfrxReport, входим в FR Designer. Создаём новый отчёт (File - > New report). Добавляем TfrxMemoView c текстом "Test text" на MasterData1
Устанавливаем MasterData1.RowCount = 200 (Чтобы повторить строку 200 раз и сформировать отчёт на 3-4 страницы, поскольку наш пример не использует датасет), выходим из дизайнера и прописываем и прописываем обработчик OnClick для Button1:
В принципе, этого кода нам уже достаточно для полноценной работы, формирования отчёта и экспорта в PDF. Теперь в "design time" делаете документ любой сложности (можете подключить любые источники данных и взять информацию оттуда) - таблицы, списки, иллюстрации, карты, QR-коды - для этого просто не забываем в проект предварительно добавить соответствующие компоненты (а иначе их в "run time" просто не будет), композитные и многостраничные документы, с якорями, встроенными ссылками и оглавлением - да пожалуйста! И любого размера - одностраничную квитанцию, стостраничный каталог, годовой отчёт о передвижениях персонала всех работников завода на тысячи страниц.
Да, не забываем положить компонент экспорта PDF в наш проект! Запускаем и нажимаем на единственную кнопку на форме. Видим окно предварительного просмотра и кнопку экспорта в PDF
Вперёд - сохраняем из нашего Delphi-приложения в PDF!
Да и "не архивный" PDF тоже имеет несколько версий (и вы можете выбрать, в какую сохранять)
Служебная информация, которая также пойдёт в PDF-файл: Название, автор, тема, ключевые слова (вы можете выкладывать PDF в веб, они отлично индексируются), средство создания PDF, производитель документа.
Безопасность - защита паролем документа от открытия (используется RC4). Возможность установить запрет на печать документа, изменение документа, копирование текста или графики, добавление или изменение текстовых заметок.
Настройка просмотрщика PDF в момент открытия документа: Скрыть панель инструментов, скрыть меню, скрыть окно пользовательского интерфейса, распахнуть окно просмотра, центрировать окно, растянуть под размер печати. Обычно при экспорте я использую параметры, выставленные разработчиками по умолчанию, но в этот раз пробежался по всем параметрам. Итак, если нам или нашим пользователям не нужно всё это богатство визуальное, то можно сразу
О, это вечная тема - сделать таблицу Эксель из Delphi.
Таблицы Excel – сегодня один из мировых стандартов. А для программ, даже простых, частое требование – это вывод данных в виде таблиц и перенос отчёта в таблицу. Сразу отмечу, что XLS формат уже устаревший, это внутренний формат Microsoft Excel под названием Biff8 (целый мир со своими взаимосвязями между, с первого взгляда, никак не связанными сущностями, ячейками, бесконечными вкладками и страницами с участками файла, записанного в хардкорном бинарном формате), тем не менее - есть компании, заказчики, у которых именно такое требование. Таких заказчиков хорошо бы сразу палкой по голове бить предупредить, что для реальных больших данных этот формат НЕ ГОДИТСЯ - сами полюбуйтесь :
"Excel has limits on the amount of data a cell can hold: for Excel BIFF 8 files, that limit is 32,767 characters, so (in theory) 200+ characters should not be an issue. However, for longer strings, this data is maintained in the BIFF file across several blocks with continuation records, For BIFF 5 files (Excel 95) the limit is 2084 bytes per block; in BIFF 8 files (Excel 97 and above) the limit is 8228 bytes. Records that are longer than these limits must be split up into CONTINUE blocks."
- там и число столбцов, и строк, и данных в них - ограничены. Лучше уж что-то новое использовать. В другой статье я расскажу, как сохранять из Delphi в XLSX XML (куда как более приятные форматы - хотя тоже Excel).
Но если уж захотелось странного, и недостатки формата вас не испугали, то пойдём пугаться дальше тут есть несколько возможностей:
- Вывод таблицы XLS прямо сразу из StringGrid через вызовы OLE / OLE-container - у этого способа есть несколько неприятных моментов - вам всенепременно нужен установленный Microsoft Excel на компьютере (мы же не пираты какие - обязательно купить лицензию надо!), разрядность системы, установленного пакета MS Office и вашей скомпилированной программы должны совпадать (вы даже не представляете, сколько незабываемых часов отладки может сам доставить, например, 32-битный офис на 64-битной системе!), ваша табличка должна быть небольшой (на больших данных OLE, работая непосредственно в оперативной памяти, сразу упадёт с громким треском, потянув за собою и Excel и вашу программку), и даже для этой маленькой программки у вас должно быть достаточно времени. Процесс передачи серийных данных через OLE медитативен и не терпит суеты. Запрос “delphi ole excel container save file” скрасит вам не один вечер.
- Окей, предположим, хочется делать всё по-взрослому - и отправлять в XLS большие объемы данных. Тогда приходят на помощь всевозможные библиотеки для записи сразу в XLS - например, TXLSFile. Есть и у этого подхода некоторые недостатки. Например - изображения, картинки, штрихкоды в ячейки поместить, да те же рамки-обрамления ячеек - не то чтобы невозможно, но будут результатом некоторых, скажем так, усилий.
- Или TMS FlexCel. Вы можете сделать отчёт в TMS FlexCel с картинкаи и совсем без программирования. Если же вы хотите сделать это из кода, у них есть инструмент для его генерации! *
- Так а что же делать? Выход, как обычно в этом блоге, есть - и это FastReport VCL! Во-первых, спокойно, используя максимум визуальных прелестей, делаете документ, отчёт (называйте, как хотите - хоть каталог для своих дилеров - и это не шутка, люди и не такое делают), потом экспортируйте готовый результат, как он есть - в Excel! Да, используйте рекомендации по подготовке отчёта - делайте его сразу ТАБЛИЧНЫМ, “аккуратненько, под линеечку” - FastReport, понятно, постарается наложенные друг на друга объекты вписать в таблицу - но так из пары объектов может получиться до 9(!) ячеек - вам же самим не понравится такой результат!
Записываем XLS из Delphi c помощью FastReport
Итак, ваш документ содержит большие таблицы, многоуровневые списки, иллюстрации, карты, штрих-коды и вы думаете, как бы это перенести в Excel?
Не буду тут повторно останавливаться на создании отчёта - бросили на форму проекта TfrxReport, TfrxBIFFExport и TButton, прописали на кнопку вызов
- строим отчёт и запускаем окно предпросмотра того, что получилось.
Видим окно предварительного просмотра и кнопку “сохранить”
И, в принципе, как будет выглядеть результат: разбивать на страницы, оставив в изначальном виде, расположить всё на одной странице или же поделить на части с задаваемым количеством строк.
Открыть после экспорта – результирующий файл будет открыт сразу же после экспорта программой Microsoft Excel.
Служебная информация, которая также пойдёт в Excel-файл: название, автор, ключевые слова, версия документа, приложения, категория, менеджер и комментарий к файлу.
Безопасность — защита паролем документа (дополнительно можно указать подтверждение).
Если задать непустую строку пароля, то сгенерированный файл будет защищён паролем. Пароль пишется только символами Юникода и должен быть короче 256 символов.
Опции – настройка документа на большее визуальное соответствие с первоначальном вариантом (WYSIWYG), экспорт в таблицу картинок-изображений, отображения границ ячеек, выставлять размер страницы, удаление пустых строк (для экономии места в этом конкретном формате очень важная опция), экспорт формул.
Если не нужно столь подробно выставлять параметры, то можно оставить всё по умолчанию.
Отправка из Delphi / Lazarus в Excel(Biff8) из кода
Какие побочные эффекты у такого варианта создания Excel-листов из Delphi? Прежде всего, это на порядок быстрее и надёжнее, чем запись в XLS Biff8 через OLE-container (можете сами сравнить), да и возможности пошире (если, конечно, не нужно просто тупо выгнать StringGrid 100х100 в Excel, который гарантированно стоит на машинке без возможности обновлений), оно платформонезависимое (Linux-приложения, сделанные в Lazarus спокойно будут генерить XLS - и потом открыть в каком-нибудь Open Office / Libre Office), форматирование, свойства текста, цвета, картинки, штрих-коды, карты, графические примитивы из отчёта в результирующую Excel-таблицу будут сохранены (но учтите, Libre Office отказался показывать картинки, только MS Excel).
Вот так выгядит документ с иллюстрациями (рыбки) в Biff8 XLS. Каждая картинка в собственной ячейке.
Отчёт с картами после сохранения в формат Excel XLS (biff8). Некоторые ячейки были объединены.
Но и ограничения есть - вызваны самим выбранным форматом! На количество выгоняемых на одном листе Excel строк и столбцов - вот вам прямо кусок из кода:
Иначе бы оно при открытии сам MS Excel вываливался с ошибкой и не открывал бы таблицу. Формат, напомню, не развивается и уже давно морально устарел. Радует, что Microsoft не стоял на месте и (несколько позже, конечно, чем Fast Reports) понял таки преимущества XML в качестве базы для организации формата хранения. И о том, как сохранить из Delphi/Lazarus в Excel XML расскажем в следующей статье.
Читайте также: