Artykuł techniczny

Hello World w Delphi HotPDF: Twój pierwszy program PDF

Każda biblioteka PDF ma swój program "hello world", a w przypadku HotPDF warto się przy nim zatrzymać na dłużej, ponieważ najmniejszy program, który cokolwiek robi, wymusza dwie decyzje, które będziesz powtarzać w każdym kolejnym dokumencie: jaką czcionkę ustawić i w jakim miejscu na stronie umieścić tekst. Wykonaj poprawnie te dwa kroki, a reszta API będzie tylko wariacjami na ten sam temat. Oto całość: program konsolowy, który zapisuje pojedynczą stronę, witając czytelnika w niemal kilkunastu językach:

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.

Multilingual Hello World PDF produced by the HotPDF component in Delphi

To cały przykład. THotPDF.Create(nil) w połączeniu z blokiem try/finally ... Free to zwykły wzorzec zarządzania właścicielami w Delphi, a generowanie PDF nic tu nie zmienia. Na uwagę zasługuje czterostopniowy rdzeń wewnątrz: ustawienie właściwości, BeginDoc, rysowanie, EndDoc. Ta kolejność jest niezmienna

Ustaw właściwości dokumentu przed BeginDoc

BeginDoc to moment, w którym HotPDF zatwierdza strukturę dokumentu, dlatego wszystko, co wpływa na cały plik, musi zostać ustawione przed tym krokiem. Compression := cmFlateDecode włącza kompresję FlateDecode dla strumieni treści, co decyduje o tym, czy plik będzie miał kompaktowy rozmiar, czy niepotrzebnie rozdęty. Opcja FontEmbedding := True pakuje czcionkę użytą do rysowania do pliku, dzięki czemu wygląda ona tak samo na maszynie, na której nigdy nie zainstalowano Arial Unicode MS, jak na twojej. Jeśli przypiszesz którąś z tych opcji po BeginDoc, operacja ta zostanie po cichu zignorowana dla obecnie tworzonego dokumentu, a ty nie otrzymasz żadnego ostrzeżenia o błędzie

SetFont, potem TextOut, i zwracaj uwagę na środek układu współrzędnych

Dwie kwestie związane z wywołaniami rysowania zaskakują każdego przy tworzeniu pierwszej strony. Pierwszą jest kolejność: SetFont musi zostać uruchomione przed każdym wywołaniem TextOut, które od niej zależy, i musi być powtarzane po każdym AddPage, ponieważ bieżąca czcionka nie jest przenoszona na nową stronę. Drugą rzeczą jest układ współrzędnych. Metoda TextOut dokonuje pomiarów od lewego dolnego rogu strony, a nie od górnego lewego rogu, przy czym wartość Y rośnie w górę, mierzona w punktach (1/72 cala). Z tego powodu kolejne wiersze wędrują tu w dół od wartości 760, przy czym każdy z nich znajduje się 30 punktów poniżej poprzedniego. Każdy, kto przechodzi od grafiki ekranowej, zakłada odwrotną logikę i często pisze pierwszy wiersz prosto poza dolną krawędź

Jedna czcionka, wiele skryptów

Powodem, dla którego pojedyncze wywołanie SetFont może obsługiwać pismo łacińskie, cyrylicę, pismo japońskie i chińskie na tej samej stronie, jest sam krój czcionki: Arial Unicode MS pakuje glify dla niemal każdego alfabetu w jednym pliku. Czwarty argument SetFont to zestaw znaków (character set) dla systemu Windows, a przekazanie DEFAULT_CHARSET pozwala systemowi dobierać glify dla każdego ciągu znaków, zamiast przypinać wszystko do jednej przestarzałej strony kodowej. Z tą wygodą wiążą się jednak dwie pułapki. Czcionka musi być zainstalowana na komputerze generującym plik PDF, ponieważ HotPDF osadza to, do czego system operacyjny przypisze określoną nazwę; jeśli brakuje czcionki Arial Unicode MS, Windows po cichu ją podmieni, a tekst CJK może wyświetlić się jako puste prostokąty. Ponadto, czcionka ta nie obsługuje jednakowo wszystkich pism: w przypadku języków zapisywanych od prawej do lewej, takich jak arabski i hebrajski, lub dowolnego innego języka wymagającego złożonego kształtowania znaków, należy sięgnąć po dedykowaną czcionkę wczytywaną za pomocą RegisterUnicodeTTF oraz metod obsługujących tekst od prawej do lewej, co stanowi osobny temat

Po uruchomieniu tego kodu otrzymasz plik HelloWorld.pdf w katalogu roboczym: jedną stronę, kilka linii wielojęzycznego tekstu, skompresowaną zawartość z osadzoną czcionką. Kolejnymi naturalnymi krokami będzie zmiana rozmiaru, stylu czy kąta nachylenia tekstu, a także świadome umiejscowienie wielu jego fragmentów na stronie, co zostało omówione w przykładzie użycia funkcji TextOut. Jeśli chcesz rysować linie, prostokąty i obrazy, a nie tylko umieszczać na stronie sam tekst, wystarczy skorzystać z tego samego obiektu strony do wywoływania odpowiednich metod

Metody TextOut, SetFont oraz metody dotyczące samego dokumentu pokazane w tym przykładzie, wchodzą w skład komponentu HotPDF dla środowisk programistycznych Delphi i C++Builder