ข้ามไปยังเนื้อหา
getnextpdf.com

รูปภาพ ตาราง และรายการ

ข้อความเพียงอย่างเดียวมักไม่เพียงพอต่อการทำเอกสารให้สมบูรณ์ ในบทแนะนำนี้คุณจะเพิ่มองค์ประกอบพื้นฐานที่ใช้ทุกวันสามอย่าง ได้แก่ รูปภาพ ตาราง และรายการแบบมีจุดนำ คุณจะเขียนสคริปต์ขนาดเล็กสองชุด และแต่ละชุดจะสร้างไฟล์ PDF (Portable Document Format) จริงที่คุณเปิดได้ทันที

  • 01-image.php — PDF หนึ่งหน้าที่มีหัวเรื่องและรูปภาพสี่เหลี่ยมจัตุรัสสีเหลืองอำพัน วางไว้ ณ ตำแหน่งที่แน่นอนบนหน้า
  • 02-table-and-lists.php — PDF หนึ่งหน้าที่มีตารางหนังสือขนาดเล็กและรายการแบบมีจุดนำอยู่ด้านล่าง

สคริปต์ทั้งสองเป็นโปรแกรมที่สมบูรณ์ ใช้โฟลเดอร์โปรเจกต์จากบทแนะนำแรกต่อไป และบันทึกแต่ละสคริปต์ไว้ข้าง composer.json

สคริปต์นี้พกรูปภาพของตัวเองมาด้วย รูปภาพ PNG (Portable Network Graphics) ขนาดเล็กเพียง 8 x 8 พิกเซลฝังตัวอยู่ภายในสคริปต์ในรูปของสตริง Base64 โดย Base64 คือการเขียนข้อมูลไบนารีให้อยู่ในรูปข้อความล้วน จึงวางไว้ในซอร์สโค้ดได้ ในโปรเจกต์จริงคุณจะข้ามส่วนนี้ไป เพราะไฟล์รูปภาพของคุณมีอยู่บนดิสก์อยู่แล้ว

บันทึกไฟล์นี้เป็น 01-image.php แล้วรันด้วย 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";

คุณจะเห็น Wrote out/image.pdf บนหน้าจอ เปิด out/image.pdf แล้วคุณจะพบหัวเรื่อง ข้อความหนึ่งบรรทัด และสี่เหลี่ยมจัตุรัสสีเหลืองอำพัน

  • สคริปต์จะถอดรหัสสตริง Base64 กลับเป็นไบต์ของรูปภาพก่อน แล้วเขียนลงใน out/amber-square.png ซึ่งเป็นเพียงเทคนิคเพื่อให้บทแนะนำนี้อยู่ในไฟล์เดียวเท่านั้น บทเรียนที่แท้จริงเริ่มต้นที่การเรียก image() ซึ่งอ่านไฟล์ PNG หรือ JPEG (Joint Photographic Experts Group) ที่มีอยู่แล้วด้วยวิธีเดียวกัน
  • @mkdir(__DIR__ . '/out') สร้างโฟลเดอร์เอาต์พุต เครื่องหมาย @ จะซ่อนคำเตือนที่ไม่เป็นอันตรายซึ่งจะเกิดขึ้นเมื่อมีโฟลเดอร์นั้นอยู่แล้ว เพื่อให้สคริปต์รันซ้ำได้สองครั้งติดต่อกัน
  • image() รับพาธของไฟล์พร้อมตำแหน่งและขนาดที่พิมพ์ออกมา ตำแหน่งและขนาดวัดเป็นพอยต์ โดย 72 พอยต์เท่ากับหนึ่งนิ้ว จุดกำเนิดของหน้าอยู่ที่มุมบนซ้าย ดังนั้น y: 160 จึงหมายถึง 160 พอยต์ลงมาจากด้านบน
  • พิกเซลและพอยต์เป็นคนละสิ่งกัน รูปภาพมีขนาดเพียง 8 x 8 พิกเซล แต่ width: 96, height: 96 จะพิมพ์ออกมาเป็นสี่เหลี่ยมจัตุรัสกว้างหนึ่งนิ้วกับอีกหนึ่งในสาม คุณเป็นผู้เลือกขนาดที่พิมพ์ ไม่ใช่จำนวนพิกเซล
  • image() วางรูปภาพ ณ ตำแหน่งที่คุณระบุไว้อย่างแม่นยำ โดยจะไม่ขยับตำแหน่งการเขียนที่ cell() ใช้ การเขียนข้อความก่อนแล้วจึงวางรูปภาพช่วยไม่ให้ทั้งสองสิ่งซ้อนทับกัน
  • NextPDF อ่านรูปภาพจากไฟล์ในเครื่องเท่านั้น ไม่เคยอ่านจากที่อยู่บนเว็บ และจะตรวจสอบว่าไฟล์เป็นรูปภาพจริงที่รองรับก่อนฝังลงไป การตรวจสอบนี้ช่วยคุ้มครองคุณเมื่อชื่อไฟล์มาจากผู้ใช้

ตารางและรายการเป็นเนื้อหาที่มีโครงสร้าง วิธีอธิบายโครงสร้างที่เร็วที่สุดคือ HTML (Hypertext Markup Language) ซึ่งเป็นมาร์กอัปแบบเดียวกับที่หน้าเว็บใช้ NextPDF เรนเดอร์ชุด HTML ที่รองรับลงบนหน้า PDF ได้โดยตรง โดยไม่มีเบราว์เซอร์เข้ามาเกี่ยวข้อง

บันทึกไฟล์นี้เป็น 02-table-and-lists.php แล้วรันด้วย 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";

คุณจะเห็น Wrote out/table-and-lists.pdf ไฟล์ PDF จะมีหัวเรื่อง ตารางสามคอลัมน์ที่มีแถวหัวตารางสีเข้ม และรายการแบบมีจุดนำ

  • สคริปต์ผสมรูปแบบการเขียนทั้งสองแบบไว้ในหน้าเดียว cell() พิมพ์หัวเรื่องขนาดใหญ่ ณ ตำแหน่งการเขียนปัจจุบัน จากนั้น writeHtml() จะจัดวางตารางและรายการให้ไหลลงมาด้านล่างบนหน้าเดียวกัน
  • ln(8) เพิ่มช่องว่างแนวตั้งเล็กน้อยสูงแปดพอยต์ระหว่างหัวเรื่องกับเนื้อหา HTML หากไม่มีช่องว่างนี้ ทั้งสองส่วนจะติดกันแน่น
  • ตารางใช้มาร์กอัปตารางทั่วไป ได้แก่ <thead> สำหรับแถวหัวตาราง <tbody> สำหรับแถวข้อมูล <th> สำหรับเซลล์หัวตาราง และ <td> สำหรับเซลล์ข้อมูล border="1" วาดเส้นตาราง และ cellpadding="6" เพิ่มพื้นที่ว่างภายในทุกเซลล์
  • ความกว้างของคอลัมน์เป็นเปอร์เซ็นต์ เช่น width: 50% โดยจะแบ่งสัดส่วนจากความกว้างเต็มของตาราง เลย์เอาต์จึงคงอยู่ได้แม้ขนาดหน้าจะเปลี่ยน สูตรการจัดวางตาราง HTMLครอบคลุมหัวตาราง ท้ายตาราง และการกำหนดขนาดคอลัมน์อย่างละเอียด
  • แอตทริบิวต์ style ใช้การประกาศ CSS (Cascading Style Sheets) ซึ่งเป็นภาษาสำหรับจัดรูปแบบของเว็บ สี การจัดแนว และความกว้างทำงานได้ตามที่แสดงไว้ตรงนี้ ก่อนจะพึ่งพาพร็อพเพอร์ตี้อื่น ให้ตรวจสอบเมทริกซ์การรองรับ CSSก่อน
  • รายการแบบมีจุดนำเป็นเพียง <ul> ที่มี <li> หนึ่งรายการต่อหนึ่งข้อ NextPDF วาดเครื่องหมายจุดนำและการเยื้องระยะให้คุณเอง
  • ข้อผิดพลาดที่ระบุ ImageProcessingException หมายความว่าไม่สามารถอ่านหรือถอดรหัสไฟล์รูปภาพได้ ให้ตรวจสอบพาธ และตรวจสอบว่าไฟล์เป็นรูปแบบที่รองรับ เช่น PNG หรือ JPEG
  • ข้อผิดพลาดที่ระบุ PageLayoutException หมายความว่าตำแหน่งหรือขนาดถูกปฏิเสธ ความกว้างและความสูงต้องมากกว่าศูนย์ และพาธต้องชี้ไปยังไฟล์ในเครื่อง ไม่ใช่ที่อยู่บนเว็บ
  • ข้อผิดพลาดทั้งสองอธิบายไว้ในเอกสารอ้างอิงข้อผิดพลาดของเอนจิน
  • หากตารางเรนเดอร์ออกมาผิดปกติ ให้ตรวจสอบมาร์กอัปก่อน ทุกแถว <tr> และทุกเซลล์ <td> ต้องมีแท็กปิด
  • สำหรับปัญหาอื่น ๆ ให้เริ่มที่คู่มือการแก้ปัญหา

ตอนนี้หน้าเอกสารของคุณสามารถมีรูปภาพ ตาราง และรายการได้แล้ว ในบทแนะนำถัดไปคุณจะปล่อยให้เอกสารขยายเกินหนึ่งหน้าและจัดให้เป็นระเบียบด้วยหัวกระดาษ ท้ายกระดาษ และเลขหน้า สำหรับการเจาะลึกหัวข้อในวันนี้ สูตรการฝังรูปภาพในเอกสารครอบคลุมรูปแบบของรูปภาพและกฎการกำหนดขนาด