Przejdź do głównej zawartości
getnextpdf.com

Obrazy, tabele i listy

Z samego tekstu rzadko powstaje gotowy dokument. W tym samouczku dodasz trzy codzienne elementy składowe: obraz, tabelę oraz listę wypunktowaną. Napiszesz dwa niewielkie skrypty, a każdy z nich tworzy prawdziwy plik PDF (Portable Document Format), który można od razu otworzyć.

  • 01-image.php — jednostronicowy plik PDF z nagłówkiem oraz bursztynowym kwadratowym obrazem umieszczonym w dokładnym miejscu na stronie.
  • 02-table-and-lists.php — jednostronicowy plik PDF z niewielką tabelą książek oraz listą wypunktowaną pod nią.

Oba skrypty to kompletne programy. Korzystaj dalej z folderu projektu z pierwszego samouczka i zapisz każdy skrypt obok composer.json.

Ten skrypt zawiera własny obraz. Maleńki obraz PNG (Portable Network Graphics) o wymiarach 8 x 8 pikseli podróżuje wewnątrz skryptu jako ciąg Base64. Base64 to tekstowy zapis danych binarnych, dzięki czemu mogą one znaleźć się w kodzie źródłowym. W prawdziwym projekcie ten fragment można pominąć, ponieważ plik obrazu już istnieje na dysku.

Zapisz to jako 01-image.php i uruchom poleceniem php 01-image.php:

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// A tiny 8 x 8 pixel amber PNG, stored as text inside this script.
// In a real project the image file already exists on disk, so you
// would skip this block and point image() at your own file.
$pngBase64 = 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAEUlEQVR42mP4Oo8bK2IYWhIAq6BngWh/dt4AAAAASUVORK5CYII=';
@mkdir(__DIR__ . '/out');
$pngPath = __DIR__ . '/out/amber-square.png';
$pngBytes = base64_decode($pngBase64, true);
if ($pngBytes === false) {
fwrite(STDERR, "The embedded image data is damaged.\n");
exit(1);
}
file_put_contents($pngPath, $pngBytes);
$document = Document::createStandalone();
$document->setTitle('Tutorial: images');
$document->addPage();
$document->setFont('helvetica', 'B', 20);
$document->cell(0, 26, 'A picture inside a PDF', newLine: true);
$document->setFont('helvetica', '', 12);
$document->cell(0, 18, 'The amber square below comes from a tiny PNG file.', newLine: true);
// Place the image 72 points (one inch) from the left edge and
// 160 points down from the top, printed as a 96 x 96 point square.
$document->image($pngPath, x: 72, y: 160, width: 96, height: 96);
$document->save(__DIR__ . '/out/image.pdf');
echo "Wrote out/image.pdf\n";

Na ekranie powinien pojawić się komunikat Wrote out/image.pdf. Otwórz out/image.pdf, a znajdziesz w nim nagłówek, jeden wiersz tekstu oraz bursztynowy kwadrat.

  • Skrypt najpierw dekoduje ciąg Base64 z powrotem na bajty obrazu i zapisuje je do out/amber-square.png. To tylko sztuczka na potrzeby samodzielnego samouczka. Właściwa lekcja zaczyna się przy wywołaniu image(), które w ten sam sposób odczytuje dowolny istniejący plik PNG lub JPEG (Joint Photographic Experts Group).
  • @mkdir(__DIR__ . '/out') tworzy folder wyjściowy. Znak @ ukrywa nieszkodliwe ostrzeżenie, które pojawiłoby się, gdy folder już istnieje, dzięki czemu skrypt można uruchomić dwa razy z rzędu.
  • image() przyjmuje ścieżkę pliku oraz pozycję i rozmiar wydruku. Pozycje i rozmiary mierzone są w punktach, a 72 punkty odpowiadają jednemu calowi. Punkt początkowy strony znajduje się w lewym górnym rogu, więc y: 160 oznacza 160 punktów w dół od góry.
  • Piksele i punkty to różne rzeczy. Obraz ma zaledwie 8 x 8 pikseli, ale width: 96, height: 96 drukuje go jako kwadrat o boku jednego i jednej trzeciej cala. To Ty wybierasz rozmiar wydruku; nie decyduje o nim liczba pikseli.
  • image() umieszcza obraz w dokładnie wskazanym miejscu. Nie przesuwa pozycji pisania, z której korzysta cell(). Napisanie najpierw tekstu, a dopiero potem umieszczenie obrazów, zapobiega ich kolizji.
  • NextPDF odczytuje obraz wyłącznie z pliku lokalnego, nigdy z adresu internetowego. Przed osadzeniem sprawdza, czy plik jest prawdziwym, obsługiwanym obrazem. To zabezpieczenie chroni Cię, gdy nazwy plików pochodzą od użytkowników.

Tabele i listy to treść strukturalna. Najszybszym sposobem opisania struktury jest HTML (Hypertext Markup Language), ten sam język znaczników, którego używają strony internetowe. NextPDF renderuje obsługiwany zestaw HTML bezpośrednio na stronie PDF. Nie bierze w tym udziału żadna przeglądarka.

Zapisz to jako 02-table-and-lists.php i uruchom poleceniem php 02-table-and-lists.php:

<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();
$document->setTitle('Tutorial: tables and lists');
$document->addPage();
$document->setFont('helvetica', 'B', 20);
$document->cell(0, 26, 'A reading list, two ways', newLine: true);
$document->ln(8);
$html = <<<'HTML'
<h2>The books as a table</h2>
<table border="1" cellpadding="6" style="width: 100%;">
<thead>
<tr style="background-color: #1E3A8A; color: #FFFFFF;">
<th style="width: 50%;">Title</th>
<th style="width: 20%; text-align: center;">Year</th>
<th style="width: 30%; text-align: right;">Pages</th>
</tr>
</thead>
<tbody>
<tr>
<td>The Paper Office</td>
<td style="text-align: center;">2019</td>
<td style="text-align: right;">312</td>
</tr>
<tr style="background-color: #F8FAFC;">
<td>Ink and Pixels</td>
<td style="text-align: center;">2023</td>
<td style="text-align: right;">208</td>
</tr>
</tbody>
</table>
<h2>Why these two books</h2>
<ul>
<li>Short chapters that fit into a lunch break</li>
<li>Worked examples on every page</li>
<li>No jargon without an explanation</li>
</ul>
HTML;
$document->writeHtml($html);
$document->save(__DIR__ . '/out/table-and-lists.pdf');
echo "Wrote out/table-and-lists.pdf\n";

Powinien pojawić się komunikat Wrote out/table-and-lists.pdf. Plik PDF zawiera nagłówek, trójkolumnową tabelę z ciemnym wierszem nagłówka oraz listę wypunktowaną.

  • Skrypt łączy oba style pisania na jednej stronie. cell() drukuje duży nagłówek w bieżącej pozycji pisania. Następnie writeHtml() układa tabelę i listę niżej na stronie, pod nim.
  • ln(8) dodaje niewielki odstęp w pionie, o wysokości ośmiu punktów, między nagłówkiem a treścią HTML. Bez niego oba elementy przylegałyby ciasno do siebie.
  • Tabela korzysta ze zwykłych znaczników tabeli: <thead> dla wiersza nagłówka, <tbody> dla wierszy danych, <th> dla komórek nagłówka oraz <td> dla komórek danych. border="1" rysuje linie siatki, a cellpadding="6" dodaje odstęp wewnątrz każdej komórki.
  • Szerokości kolumn podane są w procentach, na przykład width: 50%. Dzielą one pełną szerokość tabeli, dzięki czemu układ przetrwa zmianę rozmiaru strony. Przepis Rozmieszczanie tabeli HTML szczegółowo omawia nagłówki, stopki oraz dobór szerokości kolumn.
  • Atrybuty style korzystają z deklaracji CSS (Cascading Style Sheets), języka stylizacji stron internetowych. Kolory, wyrównanie i szerokości działają tak, jak pokazano tutaj. Zanim oprzesz się na innych właściwościach, sprawdź macierz obsługi CSS.
  • Lista wypunktowana to po prostu <ul> z jednym <li> na każdy element. NextPDF rysuje za Ciebie znaki wypunktowania oraz wcięcie.
  • Błąd wskazujący ImageProcessingException oznacza, że nie udało się odczytać lub zdekodować pliku obrazu. Sprawdź ścieżkę oraz to, czy plik ma obsługiwany format, taki jak PNG lub JPEG.
  • Błąd wskazujący PageLayoutException oznacza, że odrzucono pozycję lub rozmiar. Szerokość i wysokość muszą być większe od zera, a ścieżka musi wskazywać na plik lokalny, nie na adres internetowy.
  • Oba błędy opisano w dokumentacji błędów silnika.
  • Jeśli tabela renderuje się dziwnie, sprawdź najpierw znaczniki. Każdy wiersz <tr> oraz każda komórka <td> wymaga znacznika zamykającego.
  • W pozostałych przypadkach zacznij od przewodnika rozwiązywania problemów.

Twoje strony mogą teraz zawierać obrazy, tabele i listy. W następnym samouczku pozwolisz dokumentowi rozrosnąć się poza jedną stronę i utrzymasz porządek za pomocą nagłówków, stopek oraz numerów stron. Aby głębiej zapoznać się z dzisiejszymi tematami, przepis Osadzanie obrazów w dokumencie omawia formaty obrazów oraz reguły doboru rozmiaru.