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

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.

Многоезичен Hello World PDF, създаден от компонента 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 Component за Delphi и C++Builder