Техническая статья

Delphi HotPDF Hello World: ваша первая программа для создания PDF

У каждой библиотеки PDF есть свой "hello world", и на варианте от HotPDF стоит остановиться подробнее, поскольку даже самая маленькая программа, которая что-либо делает, заставляет принять два решения, которые вы будете повторять в каждом документе впоследствии: какой шрифт установить и где на странице будет располагаться текст. Сделайте эти две вещи правильно, и остальная часть API покажется лишь вариациями на эту тему. Вот весь пример — консольная программа, которая записывает одну страницу, приветствуя читателя почти на десятке языков:

program HelloWorld;

{$APPTYPE CONSOLE}

uses
  Winapi.Windows,   // for DEFAULT_CHARSET; on pre-XE2 Delphi use plain Windows
  HPDFDoc;          // HotPDF main unit

procedure CreateHelloWorld(const FileName: string);
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.FileName := FileName;
    Pdf.Compression := cmFlateDecode;   // shrink the content streams
    Pdf.FontEmbedding := True;          // embed the face so it renders anywhere
    Pdf.BeginDoc;

    // One face covering many scripts. The 4th argument is the Windows charset;
    // DEFAULT_CHARSET lets the system pick glyphs per string.
    Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 14, DEFAULT_CHARSET);

    // TextOut measures from the BOTTOM-LEFT corner, in points, Y growing upward.
    Pdf.CurrentPage.TextOut(72, 760, 0, 'Hello, Delphi PDF world!');     // English
    Pdf.CurrentPage.TextOut(72, 730, 0, 'Hola, mundo Delphi PDF!');      // Spanish
    Pdf.CurrentPage.TextOut(72, 700, 0, 'Hallo, Delphi PDF Welt!');      // German
    Pdf.CurrentPage.TextOut(72, 670, 0, 'Bonjour, monde PDF Delphi!');   // French
    Pdf.CurrentPage.TextOut(72, 640, 0, 'Ciao, mondo Delphi PDF!');      // Italian
    Pdf.CurrentPage.TextOut(72, 610, 0, 'Olá, mundo Delphi PDF!');       // Portuguese
    Pdf.CurrentPage.TextOut(72, 580, 0, 'Здравствуйте, Delphi PDF мир!'); // Russian
    Pdf.CurrentPage.TextOut(72, 550, 0, 'こんにちは、Delphi PDFの世界!');    // Japanese
    Pdf.CurrentPage.TextOut(72, 520, 0, 'Merhaba, Delphi PDF dünyası!');  // Turkish
    Pdf.CurrentPage.TextOut(72, 490, 0, '你好,Delphi PDF世界');           // Chinese
    Pdf.CurrentPage.TextOut(72, 460, 0, '여보세요, Delphi PDF 세계!');      // Korean

    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

begin
  CreateHelloWorld('HelloWorld.pdf');
  Writeln('Wrote HelloWorld.pdf');
end.

Многоязычный PDF-файл Hello World, созданный с помощью компонента HotPDF в Delphi

Это весь пример. THotPDF.Create(nil) в паре с try/finally ... Free является обычным шаблоном владения Delphi, и PDF не меняет его. Внимания заслуживает четырехэтапная основа внутри: установка свойств, BeginDoc, рисование, EndDoc. Порядок не взаимозаменяем

Установите свойства документа перед BeginDoc

BeginDoc — это момент, когда HotPDF фиксирует структуру документа, поэтому все, что влияет на файл в целом, должно быть установлено до этого. Compression := cmFlateDecode включает FlateDecode для потоков содержимого, что определяет разницу между компактным файлом и излишне раздутым. FontEmbedding := True упаковывает шрифт, которым вы рисуете, в файл, поэтому он выглядит одинаково на машине, на которой никогда не был установлен Arial Unicode MS, и на вашей. Назначение любого из этих свойств после BeginDoc ничего не изменит в уже создаваемом документе, причем без вывода ошибок, предупреждающих вас об этом

SetFont, затем TextOut, и следите за началом координат

Две вещи в вызовах рисования смущают всех на их первой странице. Первая — это порядок: SetFont должен запускаться перед любым TextOut, который от него зависит, и его нужно повторять после каждого AddPage, потому что текущий шрифт не сохраняется после разрыва страницы. Вторая — это система координат. TextOut измеряется от нижнего левого угла страницы, а не от верхнего левого, при этом Y увеличивается по мере продвижения вверх, в пунктах (1/72 дюйма). Вот почему строки здесь опускаются вниз с 760, каждая на 30 пунктов ниже предыдущей. Любой, кто сталкивался с экранной графикой, предполагает обратное и пишет первую строку прямо за нижним краем

Один шрифт, много алфавитов

Причина, по которой один SetFont может поддерживать латиницу, кириллицу, японский и китайский языки на одной странице, заключается в самом шрифте: Arial Unicode MS объединяет глифы почти для всех алфавитов в один файл. Четвертый аргумент для SetFont — это набор символов Windows, и передача DEFAULT_CHARSET позволяет системе выбирать глифы для каждой строки вместо привязки всего к одной устаревшей кодовой странице. С этим удобством связаны два предостережения. Шрифт должен присутствовать на компьютере, создающем PDF, потому что HotPDF встраивает то, во что ОС преобразует имя; если Arial Unicode MS отсутствует, Windows незаметно подменяет его на заменитель, и ваш CJK текст может выйти в виде пустых квадратов. И он не одинаково покрывает каждый алфавит: для письма справа налево, такого как арабский и иврит, или чего-либо, что требует сложного формирования, вам понадобится специальный шрифт, загружаемый с помощью RegisterUnicodeTTF, и вызовы текста справа налево, что является отдельной темой

Запустите это, и вы получите HelloWorld.pdf в рабочем каталоге: одна страница, несколько строк многоязычного текста, сжатый, со встроенным шрифтом. Очевидными следующими шагами будут задание размера, стиля и поворота для этого текста, а также намеренное размещение более одного блока, что рассматривается в примере использования TextOut. Когда вы хотите рисовать линии, рамки и изображения, а не только текст, этот же объект страницы содержит и эти вызовы

Показанные здесь вызовы TextOut, SetFont и документа являются частью компонента HotPDF для Delphi и C++Builder