Delphi компоненты чтения pdf. Добавляем в программу просмотр PDF с помощью ActiveX

Возможности компонента, заявленные разработчиками:

  • Поддержка векторной и растровой графики в PDF-документах
  • Защита PDF-документов паролем
  • Поддержки AcroForms/PDF-форм
  • Водяные знаки
  • Генерация PDF документов с внутренними и внешними ссылками, веб-ссылками и закладками
  • Полная поддержка Unicode
  • Поддержка различных шрифтов, форматирование текста, расположение текста в несколько столбцов
  • Поддержка TCanvas
  • Встроенный архиватор для сжатия текстовой и графической информации в документе
  • Преобразование TIFF в PDF

В качестве примера, я решил собрать демонстрационное приложение, идущее в комплекте вместе с компонентом THotPDF . Приложение довольно простенькое — генерирует PDF-ку с двумя ссылками и простым текстом. Код тоже простой и понятный:

procedure TForm1. HelloWorldButtonClick (Sender: TObject ) ; begin HPDF. BeginDoc ; HPDF. CurrentPage . PrintHyperlink (20 , 35 , "Website: " + MainEdit. Text , MainEdit. Text ) ; HPDF. CurrentPage . SetFont ( "Times New Roman" , , 16 ) ; HPDF. CurrentPage . SetRGBHyperlinkColor (clRed) ; HPDF. CurrentPage . PrintHyperlink (20 , 50 , "Order page: " + BuyEdit. Text , BuyEdit. Text ) ; HPDF. CurrentPage . SetFont ( "Times New Roman" , , 14 ) ; HPDF. CurrentPage . TextOut (20 , 75 , 0 , "Click the link to navigate" ) ; HPDF. EndDoc ; end ;

Даже не вдаваясь в тонкости работы компонента можно понять, что и как происходит в этом демонстрационном примере. Запускаем, смотрим на внешний вид сгенерированного документа:

Вот эти два синих прямоугольника в документе — ссылки на две страниц…а простого текста «Click the link to navigate» вообще не наблюдается нигде. Хотя, надо отдать должное, при клике по прямоугольнику ссылка действительно открывается. В общем, то ли разработчики поторопились заявить поддержку Delphi вплоть до XE3, то ли это так интересно работает trial-версия, но после запуска этого демонстрационного примера у меня как-то отпало желание использовать THotPDF даже за бесплатно. Двигаемся далее.

4. PDF Creator Pilot

Стоимость: от 450$ без исходников до 9950$ (!!!) с исходниками
5-XE4
http://www.colorpilot.com/pdflibrary.html#download

Библиотека стоимостью почти как Delphi XE3 Professional…Ну да ладно, посмотрим, что представляет из себя эта библиотечка.

Возможности, заявленные разработчиками:

  • Расширенный набор методов и свойств для легкого создания PDF;
  • Чтение и слияние существующих PDF-документов;
  • Добавление и удаление страниц PDF-документа;
  • Поддержка юникода;
  • Создание водяных знаков для каждой страницы;
  • Добавление эскизов для PDF-документа;
  • Использование и встраивание шрифтов (TrueType, OpenType, Type1 и т.д.);
  • Создание интерактивных PDF-документов, используя JavaScript и гиперссылки;
  • Поддержка интерактивных элементов AcroForm: текстовые поля ввода, кнопки, радио-кнопки, выпадающие списки, флажки;
  • шифрование и защита паролем созданных PDF-документов;
  • Создания и управление содержанием документа;
  • Доступ к HDC для рисования на PDF-страницах с помощью WinAPI функций.
  • Использование изображений в различных форматах (JPEG, TIFF, PNG, BMP, GIF);
  • Создание и использование аннотаций;
  • Создание PDF-документов на диске или в памяти;
  • Извлечения текста из PDF документов;

В общем, довольно внушительный список возможностей. Посмотрим как некоторые из этих возможностей работают на практике. Скачиваем демонстрационную версию, устанавливаем.

После установки запускаем Delphi (в моем случае — это Delphi XE3) и переходим в меню:

Component — Import Component — Import Type Library

В списке ищем библиотеку

Импортируем, создаем новый проект и подключаем в uses модуль PDFCreatorPilotLib_TLB.

Теперь можем протестировать работу библиотеки на каком-нибудь живом примере. Вначале попробуем сгенерировать документ с простым текстом:

procedure TForm1. Button1Click (Sender: TObject ) ; var fnt: integer ; begin { initialization } PDF : = TPDFDocument4. Create (nil ) ; PDF. SetLicenseData ("demo" , "demo" ) ; fnt : = pdf. AddFont ("Verdana" , false , false , false , false , fcANSI) ; PDF. UseFont (fnt, 14 ) ; PDF. ShowTextAt (20 , 40 , "HELLO, PDF!" ) ; { save } PDF. SaveToFile ("HelloPDF.pdf" , true ) ; PDF. Destroy ; end ;

Запускаем приложение и смотрим на созданный PDF-документ:

Теперь попробуем записать русский текст в файл:

procedure TForm1. Button1Click (Sender: TObject ) ; begin { initialization } {...} PDF. ShowTextAt (20 , 40 , "Привет, PDF!" ) ; { save } {...} end ;


Может где-то в свойствах класса надо что-то настроить, вызвать какой-нибудь метод, который включит-таки поддержку юникода, НО за такие бабки хотелось бы получить библиотеку, которая заработает сразу «из коробки» без всяких заморочек с настройками и подкрутками…Кстати, метод для вставки ссылки (AddHyperLink) тоже не сработал — документ остался девственно чист несмотря на то, что ссылка якобы вставилась. Но, надо отдать должное, попытка вставить в новый документ уже ранее созданную PDF-ку — сработал на ура — документ вставился на новую страничку как надо, без косяков.

5. PDFtoolkit VCL v4.0.1.293

Стоимость: от 349$ без исходников до 499$ с исходниками
Поддерживаемые версии Delphi: 6-XE4
Страница загрузки trial-версии: http://www.gnostice.com/PDFtoolkit_VCL.asp?show=downloads

Про эту библиотеку компонентов от Gnostice имеется довольно много положительных отзывов в Сети.

По возможностям PDFtoolkit практически 1 в 1 соответствует PDF Creator Pilot, т.е. умеет «склеивать» PDF-ки, распознавать текст, вставлять ссылки, проводить поиск в документах и т.д. Но, в отличие от PDF Creator Pilot, PDFtoolkit if gtPDFDocument1. IsLoaded then begin gtPDFDocument1. TextOut ( "Привет, Мир!" , IntToStr (gtPDFDocument1. PageCount ) , //диапазон страниц в который будет вставлен текст gtPDFDocument1. GetPageSize (gtPDFDocument1. PageCount , muPixels) . Width / 2 , //вставляем текст в центр страницы gtPDFDocument1. GetPagesize (gtPDFDocument1. PageCount , muPixels) . Height / 2 ) ; {сохраняем документ} gtPDFDocument1. SaveToFile ("modified_doc.pdf" ) ; end ; finally gtPDFDocument1. Free end ;

Конечно, применительно к моей задаче PDFtoolkit оказывается практически бесполезным, т.к. меня интересует именно создание с нуля PDF-ки, но для тех, кто пишет собственный вьювер PDF-ок, думаю, эта библиотека должна подойти более чем.

Итак, что имеем в итоге. Есть 5 различных решений для создания и работы с PDF-документами в Delphi. Каждое решение имеет как свои достоинства (бесплатность, «навороченность»), так и недостатки (конская стоимость, проблемы с юникодом и т.д.). Применительно к моей задаче надо всеми решениями придётся «работать напильником». С другой стороны, в Сети есть куча платных и бесплатных сервисов для генерации PDF, но, памятуя о том, что такие сервисы имеют свойство вдруг брать и умирать, то как-то не тянет с ними связываться. Есть, конечно, ещё одно решение — самописное и не совсем в тему Delphi, но об этом как-нибудь в следующий раз, а пока пойду подумаю что же делать с клиентом для DelphiFeeds


До встречи в онлайне!


дата публикации 23-09-2005 07:00 Очерк по поводу создания PDF-файлов

В последнее время на просторах интернета обнаружилось очень много PDF converter"ов, reader"ов и write"ов. И подавляющее большинство из них предлагается за деньги. Сама программа от 10$ до 300$. А уж исходный код за гораздо большие деньги цена начинается от 200$ а в одном месте (заинтересовавшись этим полазил по инету) аж за 900 евро.

Данная проблемма меня заинтересовала в плане программирования и вот результаты довожу до вашего сведения. (Данные результаты получены мною при изучении внутренностей PDF файла, когда открываешь его в total commander через F3)

Обычный PDF файл состоит из четырех частей :=

Что такое такое

? Это обычное упоминание о версии PDF specification. Которое присутствует в первой строке PDF файла. Например "%PDF-1.3" В седьмой версии акробата которая вышла где то в начале лета этого года, этот номер "%PDF-1.7", но это не версия продукта, это версия именно спецификации. Второй строкой PDF идет небольшая аброкадабра (видимо предназначена для дальнейшего использования) " %вгПУ"

Все с первой частью PDF разобрались.

Что из себя представляет вторая часть которая называется ?

Ответ очень простой: это последовательность объектов, описание которых как и хедера представлены в текстовом виде.

Каждый объект это текстовой фрагмент с порядковым номером в имени например "4 0 obj"

  • 4 это порядковый номер объекта
  • 0 это номер (ре)генерации файла то есть когда файл обновляется (редактируется) то данный номер увеличивается
  • obj это кодовое слово означающее что в теле документа нам встретился объект

Все объекты делятся на косвенные и прямые. Все косвенные, и их большинство, после слова obj имеют в своем теле делиметер "<<", означающее начало данных объекта. И в конце данных закрывающий делиметер ">>" и кодовое слово endobj

Прямые объекты не должны иметь в своем теле открывающих и закрывающих делиметеров "<<", ">>" Все косвенные объекты доступны через cross-reference table . В ней представлены ссылки в виде смещения от начала файла до начала объекта (Данные (строки) в объекте разделяются #13#10 либо #13 )

Тип "самого главного" объекта в теле PDF файла носит гордое имя "/Catalog"

4 0 obj << /Type /Catalog /Pages 2 0 R /OpenAction [ 5 0 R /XYZ null 364 1 ] /PageMode /UseNone >> endobj

На самом деле в теле минимального PDF файла типа "Hello world" должно быть 3 "главных" объекта. Давайте я их перечислю по типам:

  • "/Catalog" содержит в себе ссылку: на дерево страниц (/Pages )
  • "/Pages" содержит в себе ссылку на группу страниц документа (Например 2 0 obj > endobj)
  • "/Page" содержит в себе ссылку на объекты относящиеся к конкретной странице. (Например 3 0 obj > /Rotate 0 >>)
И несколько "второстепенных"

Разберем объект страница:

  • /Rotate поле показывающее на сколько градусов изображение страницы должно быть повернуто при отображение в программе
  • /MediaBox и /CropBox поля описывающие размер страницы
  • /Parent ссылка на родительский объект "/Pages"
  • /Resources это поле описывает какой фонт должен быть использован при отображении страницы (фонт это отдельный объект) и установку ProcSet эта установка показывает какое содержимое потока данных данной страницы (тоже может быть определен как объект, а не как поле)
  • /Contents Самое интересное поле в объекте "страница", дает ссылку на объект содержимого данной страницы, причем: если это поле отсутствует в объекте "страница" значит страница пустая
Содержимое страницы:
Объект "stream" 4 0 obj > stream BT /F12 9 Tf 10 782 TD 0 -12.5 TD (Max Fokin) Tj 0 -12.5 TD (mnb) Tj 0 -12.5 TD () Tj 0 -12.5 TD (Max Privet) Tj 0 -12.5 TD (1) Tj 0 -12.5 TD (1) Tj 0 -12.5 TD (2) Tj 0 -12.5 TD (3) Tj 0 -12.5 TD (45) Tj ET endstream endobj /Length 305 это поле показыввающее сколько байт от слова stream до слова endstream

Самый простой вариант - это некодированный и несжатый поток данных в объекте stream . Он ограничивается операторами BT и ET

BT Begins a Text Object - характеризует начало текста ET Ends a Text Object. - характеризует конец текста /F12 9 Tf

  • /F12 это кодовое имя объекта который характеризует фонт используемый на данной странице
  • 9 это размер фонта
  • Tf это оператор который характеризует что данная строка в объекте steam есть установка фонта и размера
10 782 TD это цифры откуда начинается данная строка (отсчет производиться от левого верхнего угла) Tj это оператор перевода на новую строку Ну а в круглых скобках наш текст

Кодированный поток я сдесь не объясняю. Он основан на алгоритмах RC4, RC5, MD5.

Что такое объект Font 12 0 obj >

  • /Type /Font Естественно название типа
  • /Subtype /Type1 название подтипа
  • /Name /F7 F7 это кодовое имя

PDF поддерживает несколько видов фонтов. Они перечисленны ниже

  • Type 1, including subsets and Multiple Master "snapshots"
  • Type 3
  • TrueType, including subsets
  • Type 0
Честно говоря, я не разбирался с Type 3, TrueType, including subsets, Type 0 ничего по ним сказать не могу
А Type 1 - это следующие фонты Courier Courier-Bold Courier-BoldOblique Courier-Oblique Helvetica Helvetica-Bold Helvetica-BoldOblique Helvetica-Oblique Times-Roman Times-Bold Times-Italic Times-BoldItalic Symbol ZapfDingbats

20 0 obj > endobj Это объект с названиями кодовых имен для фонтов первого типа. По этому кодовому имени можно легко получить сам объект фонт . 6 0 obj >

ВСЕ: то есть минимальное Состоит из следующих объектов: "catalog" , "pages", "page", "Resources" (опиционально может присутствовать, как поле в объекте страница), нетипизированный объект "stream" , группа объектов "font"

Что такое ? На самом деле это обычная текстовая таблица, она начинается со слова xref и своем теле имеет ссылки на все косвенные объекты в документе. Вот пример xref 0 27 0000000021 65535 f 0000000016 00000 n 0000000105 00000 n 0000000169 00000 n 0000000356 00000 n 0000000713 00000 n 0000000892 00000 n 0000001006 00000 n 0000001125 00000 n 0000001247 00000 n 0000001373 00000 n 0000001486 00000 n 0000001604 00000 n 0000001725 00000 n 0000001850 00000 n 0000001967 00000 n 0000002084 00000 n 0000002203 00000 n 0000002326 00000 n 0000002439 00000 n 0000002558 00000 n 0000000024 00001 f 0000002751 00000 n 0000002831 00000 n 0000000000 00001 f 0000002915 00000 n 0000002955 00000 n 0 27 Эти цифры обозначают следующее:

  • 0 - первый object number в таблице
  • 27 - количество элементов таблицы

Первый элемент таблицы всегда иммет вид "XXXXXXXXXX 65535 f " где X это цифра, а 65535 это значение по умолчанию для первого элемента в таблице. Символ "f" обозначает "free ", то есть объект не используется

Разберем элемент данной таблицы.

  • Первые 10 цифр - это смещение от начала файла до начала объекта.
  • 0000000016 означает что через 16 байт от начала файла Вас встретит первое упоминание об объекте то есть, например, 4 0 obj

Вторые пять цифр - это номер генерации файла. Если файл только что создан, то они всегда нули. Если файл модифицируется, то это число увеличивается на единицу. То есть, 0000000024 00001 f

Канонический, только что созданный PDF файл, имеет только одну таблицу. Но, если файл редактируется, то таких таблиц может быть очень много.

Взаимосвязь таблиц осуществляется при помощи последнего элемента и кодового слова startxref

Канонический, только что созданный PDF файл, имеет только одну таблицу, после таблицы идет элемент trailer А после трайлера идет кодовое слово startxref , указывающее на смещение от начала файла до начала таблицы, вот пример. trailer > startxref 173 %%EOF Это значит, что через 173 байта от начала документа, будет присутствовать кодовое слово xref . Но, если файл был отредактирован, то последний в файле трайлер будет иметь вид: xref 0 3 0000000000 65535 f 0000003609 00000 n 0000003832 00000 n trailer <7a15ab3ed3999575ff2f3034104a82c1>] >> startxref 173 %%EOF Но, если мы обратимся к таблице, куда указывает ссылка startxref 173 , то мы найдем следующую таблицу, а за ней трайлер, который будет иметь поле /Prev 3896 3 16 0000000016 00000 n 0000000664 00000 n 0000000936 00000 n 0000001106 00000 n 0000001133 00000 n 0000001250 00000 n 0000001395 00000 n 0000001811 00000 n 0000001992 00000 n 0000002180 00000 n 0000002360 00000 n 0000002760 00000 n 0000003438 00000 n 0000003516 00000 n 0000000776 00000 n 0000000916 00000 n trailer <7a15ab3ed3999575ff2f3034104a82c1>] >> startxref 567 %%EOF

Данное поле /Prev 3896 указывает нам на предыдущую таблицу, а ссылка startxref 567 указывает на следующую таблицу и так практически до бесконечности, пока в очередном поле startxref мы не увидим 0 . Это значит, мы прочитали все таблицы.

В данном очерке, конечно, не хватает исходного кода. Вот и он: представлены два модуля основной "PDFDocument " и вспомогательный "PDFBaseFonts "

К материалу прилагаются файлы:

  • Исходный код модулей PDFDocument.pas и PDFBaseFonts.pas (16 K) обновление от 9/23/2005 7:02:00 AM

Обсуждение материала [ 31-07-2006 06:33 ] 7 сообщений

В этой статье, рассмотрим, как создавать свои pdf -документы, а в следующей статье рассмотрим, как можно просматривать pdf -документы в своих проектах, а также печатать содержимое, перемещаться по документу и так далее.

Для этого нам понадобятся компоненты с вкладки Rave . Давайте же установим, необходимые нам, для работы компоненты, а это:

  • TRvNDRWriter
  • TRvRenderPdf
  • TButton

Компонент TRvNDRWriter предназначен для записи в pdf -файл информацию (текстовую, графическую), через поток.

Компонент TRvRenderPdf предназначен для создания, отрисовки информации (текстовой, графической и так далее). Ну и по нажатию на кнопку, мы будем что-то заносить в наш pdf -файл.

Из теории много писать ничего не будем, а сразу перейдем к программированию, но необходимо еще сперва создать обычный пустой pdf -файл и положить его в корень с программой. Дальше на событие OnClick нашей кнопки мы напишем следующий код:

procedure TForm1. Button1Click (Sender: TObject ) ; var Streams: TMemoryStream; begin Streams: = TMemoryStream. create ; RvNDrWriter1. Stream : = Streams; RvNDRWriter1. Execute ; RvRenderPdf1. PrintRender (Streams, "test.pdf" ) ; ShellExecute(Handle, nil , "test.pdf" , "" , "" , SW_SHOW) ; FreeAndNil (Streams) ; end ;

Создаем поток, в котором и будем отрисовывовать всю информацию, затем запускаем отрисовку, указываем файл, в который будет производиться отрисовка данных и в конце уничтожаем поток.

Все теперь, нам необходимо событие, которое возникает при отрисовке данных, в нем мы и будем выводить всю нашу информацию. Выделяем компонент TRvNDRWriter и переходим список событий данного компонента, после чего, находим событие OnPrint и в данной событие пишем следующий код:

procedure TForm1. Print (Sender: TObject ) ; begin bmp: = TBitmap. Create ; bmp. LoadFromFile ("test.bmp" ) ; with RvNDRWriter1 do begin SetFont("Arial" , 16) ; FontColor: = clGreen; Print("Test Text" ) ; PrintHeader("Begin PDF File" , pjCenter) ; PrintFooter("End PDF File" , pjCenter) ; LineTo(10, 10) ; PrintBitmap(1, 1, 1, 1, bmp) ; end ; FreeAndNil (bmp) ; end ;

Ну, сперва, мы загружаем картинку *.bmp , естественно переменная bmp , у нас объект класса TBitmap . Загружаем мы для того, чтобы потом ее отрисовать в нашем pdf -документе.

А дальше, я думаю все понятно, процедура PrintHeader - выводит надпись в заголовок документа (страницы), процедура PrintFooter - выводит надпись в конец документа (страницы). Процедура PrintBitmap - выводит изображение в документ, процедура SetFont - устанавливает шрифт документа, процедура FontColor - устанавливает цвет шрифта документа.

Существует два основных способа организовать в программе просмотр документов в формате PDF.

  • Использование технологии ActiveX;
  • Использование специальных компонентов.

Компоненты для работы с PDF есть не во всех выпусках Delphi и чаще всего их нужно искать и устанавливать дополнительно. В тоже время, для использования ActiveX необходимо всего лишь наличие на компьютере пользователя соответствующего программного обеспечения. В данном случае Adobe Acrobat Reader (бесплатная) или Adobe Acrobat.

Работу с ActiveX можно условно разделить на два этапа.

  • Импорт библиотеки типов или компонентов;
  • Собственно, использование импортированных средств в приложении.
Импорт компонентов ActiveX

Для импорта компонентов используется команда «Component» – «Import Component» в главном меню Delphi. Сам процесс импорта реализован в виде мастера.

На первой странице мастера выбираем «Import ActiveX Control».

После этого необходимо решить, как поступить с импортируемыми компонентами. Так как планируется их использование в виде компонентов Delphi, выбираем «Install to New Package».

Теперь остаётся только указать имя вновь создаваемого пакета.

После нажатия на кнопку «Finish», компоненты ActiveX для просмотра PDF будут импортированы в Delphi.

Просмотр PDF в приложении

Для создания просмотра PDFфайлов в приложении средствами ActiveX необходим компонент TAcroPDF. Процесс его импорта подробно описан выше.

В качестве примера создадим следующее приложение. Поместим на форму компоненты TAcroPDF, TOpenDialog и TButton как показано на скриншоте ниже.

При нажатии на кнопку вызываем диалог открытия файла для выбора файла PDF для просмотра.

Для этого примера нам будут необходимы следующие компоненты, которые находятся во вкладке Rave. И так, приступим к установке нужных нам компонентов, а именно:

  • TRvNDRWriter
  • TRvRenderPdf
  • TButton

Предлагаю немного остановиться на этих компонентах и понять для чего они служат. Кстати о них я вычил информацию из пару книг которые приобрел progbook.ru . Поэтому если хотите приобрести достойные книги по Delphi, то милости прошу в данный магазин.

Итак, первым у нас идет компонент TRvNDRWriter. Этот компонент необходим нам для записи в pdf-файл информации, не важно какой, текстовой или графической, через поток.

Procedure TForm1.Button1Click(Sender: TObject); var Streams:TMemoryStream; begin Streams:=TMemoryStream.create; RvNDrWriter1.Stream:=Streams; RvNDRWriter1.Execute; RvRenderPdf1.PrintRender(Streams, "test.pdf"); ShellExecute(Handle, nil, "test.pdf", "", "", SW_SHOW); FreeAndNil(Streams); end;

Следующий компонент это TRvRenderPdf. Он необходим нам для создания, а точнее для отрисовки информации, будь то текстовая или графическая. Соответственно после нажатия кнопки, мы запишем нужную нам информацию в наш pdf-файл.

Но не будем сильно разглагольствовать, а перейдем сразу к интересующей нас теме, а именно к программированию:)

Для начала нам необходимо создать обычный пустой pdf-файл и разместить его в корневой папке нашей программы.

Собственно данным кодом мы создаем поток, где будем отрисовывовать нужную нам информацию, после чего запускаем отрисовку, указываем наш конечный pdf-файл, в который будет производиться отрисовка данных и в конце закрываем поток.

После выполнения данного когда, нам необходимо событие, которое возникает при прорисовке данных, в этом событии мы будем выводить нужную нам информацию.

Разберем код. Для начала я загружаю картинку *.bmp, создаем переменную bmp, и объект класса TBitmap. Загружаю я ее для того, чтобы потом рисовать в нашем pdf-файле.

Я думаю дальше особо описывать не стоит все понятно и так, процедура PrintHeader - добавляет надпись в заголовок документа, процедура PrintFooter - добавляет надпись в конец документа. Процедура PrintBitmap - добавляет изображение в документ, процедура SetFont - задает необходимый шрифт документа, процедура FontColor - задает нужный цвет шрифта документа.

Все последующие графические функции и процедуры, точно такие же, как и при выводе графической информации на Canvas других компонентов.

Функцию NewPage я использую для создания нового листа в документе. Все что будет добавлено после нее на вывод информации, будет выводиться на новом листе документа.

Важно , что бы все модули: RpRender, RpRenderPDF, RpDefine, RpBase, RpFiler, RpRave, RpCon были подключены к проекту!