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

เรนเดอร์ HTML ภาษาอาหรับแบบขวาไปซ้าย

เรนเดอร์ HTML แบบขวาไปซ้าย (RTL) ให้เป็น PDF ด้วย writeHtml() โดยกำหนดพร็อพเพอร์ตี CSS direction: rtl และลงทะเบียนฟอนต์ที่รองรับภาษาอาหรับ เอนจินจะจัดเรียงข้อความเป็นลำดับเชิงภาพตามอัลกอริทึมข้อความสองทิศทางของ Unicode (UAX #9) และขึ้นรูปอักษรอาหรับตามบริบท สูตรนี้แสดงวิธีเรนเดอร์ใบแจ้งหนี้ภาษาอาหรับขนาดเล็กแบบ RTL โดย RTL ใช้กับภาษาอาหรับ ภาษาฮีบรู ภาษาเปอร์เซีย และภาษาอูรดู ภาษาฮีบรูจะถูกจัดลำดับใหม่แต่ไม่ถูกขึ้นรูป ซึ่งถูกต้องสำหรับสคริปต์นั้น

Terminal window
composer require nextpdf/core

ต้องมีฟอนต์ TrueType หรือ OpenType ที่รองรับภาษาอาหรับด้วย แผนผังอักขระของฟอนต์ต้องครอบคลุมบล็อก Arabic Presentation Forms-B ฟอนต์ Noto Naskh Arabic และ Amiri เป็นฟอนต์แบบเปิดที่เหมาะกับงานนี้

การเรนเดอร์ RTL ต้องมีอินพุตสองอย่าง ได้แก่ พร็อพเพอร์ตี CSS direction: rtl และฟอนต์อาหรับที่ลงทะเบียนแล้ว

direction: rtl บอกให้เลย์เอาต์วางข้อความจากขวาไปซ้าย จากนั้นเอนจินจะใช้อัลกอริทึมข้อความสองทิศทางของ Unicode (UAX #9) เพื่อคำนวณลำดับเชิงภาพ เนื้อหาแบบผสมจึงถูกจัดลำดับอย่างถูกต้อง คำภาษาละติน คำภาษาอาหรับ และตัวเลขยังคงทิศทางของตัวเอง ตัวเลขที่ตามหลังข้อความภาษาอาหรับจะยังคงลำดับจากซ้ายไปขวา

ภาษาอาหรับเป็นระบบอักษรที่ตัวอักษรเชื่อมต่อกัน ตัวอักษรแต่ละตัวจึงใช้กลีฟต่างกันตามตัวอักษรข้างเคียง เอนจินจะเลือกรูปเริ่มต้น รูปกลาง รูปท้าย หรือรูปเดี่ยวสำหรับตัวอักษรแต่ละตัว และใช้ลิเกเจอร์ Lam-Alef การขึ้นรูปตามบริบทนี้ต้องใช้ฟอนต์ที่มีแผนผังอักขระครอบคลุมบล็อก Arabic Presentation Forms-B ฟอนต์ที่รองรับเฉพาะภาษาละติน รวมถึงฟอนต์มาตรฐาน 14 รายการ ไม่สามารถวาดอักษรอาหรับได้

ในตาราง แต่ละเซลล์จะถูกจัดลำดับและขึ้นรูปแยกกัน แล้วจัดแนวชิดขอบเริ่มต้น ซึ่งคือขอบขวาภายใต้ direction: rtl ค่าเชิงตรรกะของ text-align เช่น start และ end จะถูกแก้ค่าตามทิศทาง ดังนั้น start จึงแมปไปยังขอบขวาสำหรับเนื้อหา RTL

ให้กำหนดทิศทางด้วยพร็อพเพอร์ตี CSS direction แอตทริบิวต์ HTML dir ไม่แมปกับพร็อพเพอร์ตีนี้ ดู RTL — ข้อจำกัดในปัจจุบัน เพื่อดูขอบเขตการรองรับในปัจจุบัน

สัญลักษณ์ตำแหน่งบทบาท
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputเรนเดอร์ชิ้นส่วน HTML ที่ตำแหน่งเคอร์เซอร์ปัจจุบัน
FontRegistry::register(string $fontFile, string $alias = '', int $fontIndex = 0): FontInfoNextPDF\Typography\FontRegistryลงทะเบียนฟอนต์อาหรับภายใต้ชื่อแทน
DocumentFactory::create(): DocumentNextPDF\Core\DocumentFactoryสร้างเอกสารที่อ่านรีจิสทรีที่กำหนดไว้

ตัวอย่างนี้ใช้พร็อพเพอร์ตี CSS ต่อไปนี้ ได้แก่ direction, font-family, text-align ให้อ้างอิงฟอนต์ที่ลงทะเบียนไว้ใน CSS font-family ด้วยชื่อแทนในรีจิสทรีของฟอนต์

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
$fontRegistry = new FontRegistry();
$fontRegistry->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->addPage();
$doc->writeHtml(
'<div style="direction: rtl; font-family: \'ArabicFont\';">'
. '<h1>فاتورة</h1>'
. '<p>المبلغ الإجمالي 380.00</p>'
. '</div>'
);
$doc->save(__DIR__ . '/rtl-arabic.pdf');

หัวเรื่องจะเรนเดอร์จากขวาไปซ้าย และตัวเลข 380.00 จะคงลำดับจากซ้ายไปขวาภายในประโยคภาษาอาหรับ

ตัวอย่างที่ครบถ้วนในตัวเองนี้เรนเดอร์ตารางใบแจ้งหนี้ภาษาอาหรับ แต่ละเซลล์มี direction: rtl และใช้ฟอนต์อาหรับที่ลงทะเบียนแล้ว เอนจินจึงจัดลำดับและขึ้นรูปทุกบรรทัด จากนั้นจัดแนวเซลล์ชิดขอบขวา

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;
use NextPDF\Graphics\ImageRegistry;
use NextPDF\Typography\FontRegistry;
// Supply an Arabic-capable face whose cmap covers Arabic Presentation Forms-B.
// Embed only fonts you are licensed to embed.
$fontPath = __DIR__ . '/NotoNaskhArabic-Regular.ttf';
if (!is_file($fontPath)) {
fwrite(STDERR, "Arabic font not found at {$fontPath}\n");
exit(1);
}
$fontRegistry = new FontRegistry();
$fontRegistry->register($fontPath, alias: 'ArabicFont');
$documentFactory = new DocumentFactory($fontRegistry, new ImageRegistry(maxCacheBytes: 0));
$doc = $documentFactory->create();
$doc->setTitle('Arabic invoice');
$doc->addPage();
$html = <<<'HTML'
<div style="direction: rtl; font-family: 'ArabicFont'; font-size: 12pt;">
<h1>فاتورة</h1>
<table style="width: 100%; border-collapse: collapse;">
<tr>
<th style="border: 1px solid #333; padding: 6px;">الوصف</th>
<th style="border: 1px solid #333; padding: 6px;">المبلغ</th>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">خدمات استشارية</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
<tr>
<td style="border: 1px solid #333; padding: 6px;">الإجمالي</td>
<td style="border: 1px solid #333; padding: 6px;">380.00</td>
</tr>
</table>
</div>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');
$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');
echo "Wrote the Arabic invoice PDF\n";
HTML;$doc->writeHtml($html);$out = getenv('NEXTPDF_OUT');$doc->save($out !== false ? $out : __DIR__ . '/render-rtl-arabic-html.pdf');echo "Wrote the Arabic invoice PDF\n";">
  • ลงทะเบียนฟอนต์ก่อนสร้างเอกสาร Document::createStandalone() จะสร้างรีจิสทรีของตัวเองและไม่เห็นฟอนต์ที่ลงทะเบียนไว้ที่อื่น ให้สร้างผ่าน DocumentFactory เพื่อให้ตัวเขียนอ่านรีจิสทรีของคุณได้ ดังที่แสดงในทั้งสองตัวอย่าง
  • จับคู่ CSS font-family กับชื่อแทนในรีจิสทรี ชื่อที่ส่งให้ register(..., alias: 'ArabicFont') คือชื่อที่ใช้อ้างอิงใน CSS
  • ใช้ CSS direction ไม่ใช่แอตทริบิวต์ HTML dir มีเพียงพร็อพเพอร์ตี CSS เท่านั้นที่สลับเลย์เอาต์
  • ตัวเลขที่ตามหลังภาษาอาหรับจะคงลำดับจากซ้ายไปขวา ซึ่งเป็นไปตาม UAX #9 ตัวเลขแบบยุโรปที่ตามหลังตัวอักษรอาหรับจะแก้ค่าเป็นตัวเลขอาหรับและรักษาลำดับหลักตัวเลขไว้ ดังนั้น 380.00 จึงไม่ถูกสลับกลับ

การนำไปใช้ในปัจจุบันจัดลำดับและขึ้นรูปข้อความ RTL พร้อมจัดแนวเซลล์ในตารางได้ ข้อจำกัดต่อไปนี้ยังคงอยู่ และแต่ละข้อต้องอาศัยกล่องบรรทัดสำหรับการจัดรูปแบบอินไลน์รายบรรทัดในอนาคต

  • การจัดแนวแบบบล็อกและแบบอินไลน์นอกตาราง ข้อความระดับบล็อกและข้อความอินไลน์นอกเซลล์ตารางจะถูกจัดลำดับและขึ้นรูป แต่ยังเรนเดอร์จากขอบเริ่มต้น (ซ้าย) การจัดแนวข้อความที่ไม่ใช่ตารางให้ชิดขวาหรือกึ่งกลาง และการกระจายข้อความแบบ text-align: justify ยังไม่ถูกนำมาใช้ ส่วนเซลล์ตารางจัดแนวได้
  • แอตทริบิวต์ HTML dir ไม่แมปกับ direction กำหนดทิศทางด้วยพร็อพเพอร์ตี CSS direction
  • การแก้ลำดับแบบสองทิศทางทำงานต่อช่วงข้อความ อักขระที่เป็นกลางจะไม่ถูกแก้ค่าข้ามองค์ประกอบอินไลน์สองรายการ เช่น <span> ที่อยู่ติดกับ <b> ในบรรทัดเดียวกัน
  • คอลัมน์ภาษาอาหรับที่แคบวัดจากข้อความเชิงตรรกะ การตัดบรรทัดวัดจากข้อความเชิงตรรกะก่อนขึ้นรูป ดังนั้นคอลัมน์ภาษาอาหรับที่แคบมากจึงอาจตัดบรรทัดเร็วหรือช้าไปเล็กน้อย
  • ภาษาอาหรับที่ขึ้นรูปแล้วต้องการความครอบคลุม Presentation Forms-B ฟอนต์ต้องครอบคลุมบล็อก Arabic Presentation Forms-B การรองรับฟอนต์ที่พึ่งพาเฉพาะการแทนที่ด้วย OpenType GSUB และเส้นทางการขึ้นรูปแบบ HarfBuzz ยังเป็นงานในอนาคต ฟอนต์ที่ไม่ใช่ภาษาอาหรับไม่สามารถวาดภาษาอาหรับได้

ต้นทุนการเรนเดอร์เพิ่มขึ้นเชิงเส้นตามจำนวนกลีฟ การจัดลำดับแบบสองทิศทางและการขึ้นรูปตามบริบททำงานรายบรรทัด และเพิ่มตัวคูณคงที่เล็กน้อยเมื่อเทียบกับข้อความแบบซ้ายไปขวา งบประมาณของสูตรนี้คือ wall_ms: 1500, peak_mb: 64

ตรวจสอบความยาวของสตริงที่ผู้ใช้ป้อนเพื่อให้ขนาดเอาต์พุตยังอยู่ในขอบเขต เอนจินจะเรนเดอร์ข้อความ ไม่ตีความข้อความ และไม่รันสคริปต์ใด หากโหลดฟอนต์ผ่านแหล่ง @font-face แบบรีโมต นโยบายทรัพยากรภายนอกที่ปลอดภัยจะควบคุมการดึงข้อมูล ควรใช้ไฟล์ฟอนต์ในเครื่องเพื่อให้เอาต์พุตคาดการณ์ได้

ข้อความข้อกำหนดข้อreference_id
ลำดับเชิงภาพเกิดจากการกลับลำดับช่วงอักขระจากระดับสูงสุดลงมาจนถึงระดับคี่ต่ำสุดUnicode UAX #9§3.3.6 Rule L2 (uax9#3.3.6.p13)814977a77019d728dc562a612098a82dc260f6844f5998eca5fe7a3baf3394af
ตัวเลขแบบยุโรปที่ตามหลังตัวอักษรอาหรับจะแก้ค่าเป็นตัวเลขอาหรับ ดังนั้นหลักตัวเลขจึงคงลำดับจากซ้ายไปขวาUnicode UAX #9§3.3.4 Rule W2 (uax9#3.3.4.p9)5747405357772797d62b3f4ba79328557fa0c4273a1dd5ffa8d996f24c78e120

การขึ้นรูปภาษาอาหรับตามบริบท (รูปเริ่มต้น รูปกลาง รูปท้าย และรูปเดี่ยว รวมถึงลิเกเจอร์ Lam-Alef) เป็นความสามารถของเอนจินที่ผ่านการตรวจสอบและครอบคลุมด้วยชุดทดสอบ ไม่ใช่การอ้างความสอดคล้องแยกต่างหาก โดยต้องใช้ฟอนต์ที่มีแผนผังอักขระครอบคลุมบล็อก Arabic Presentation Forms-B

ไม่เกี่ยวข้อง