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

ฟอนต์: value object การฝัง และการสำรอง

ใน NextPDF ฟอนต์คือ value object แบบเปลี่ยนแปลงไม่ได้ FontInfo พร้อมชนิดเทคโนโลยีที่บอกเอนจินว่าต้องฝังฟอนต์นั้นอย่างไร เอนจินจะฝังฟอนต์ทุกตัวที่ใช้งาน ส่วนการอ้างอิง Base 14 แบบเดิมจะสำรองไปยังฟอนต์แทนที่ให้มาในแพ็กเกจและเข้ากันได้ทางเมตริก

Terminal window
composer require nextpdf/core:^3

FontInfo คือ value object แบบเปลี่ยนแปลงไม่ได้ที่รวบรวมข้อมูลทั้งหมดซึ่งเอนจินต้องใช้ในการฝังฟอนต์ ได้แก่ family และ style ชื่อ PostScript แฟล็กของ descriptor เมตริกที่ปรับสเกลเป็น em ขนาด 1000 หน่วย ความกว้างของอักขระ แมป glyph-to-Unicode แมปอักขระแบบไปข้างหน้า (cmap จาก Unicode ไปยังตัวระบุ glyph) ไบต์ฟอนต์ดิบ และเมื่อมีข้อมูล ก็รวมถึงแกน variation อินสแตนซ์ที่มีชื่อ ตัวเลือก variation คู่ kern และเมตริกแนวตั้ง เนื่องจากเป็น final readonly ลายเซ็นของ constructor และพร็อพเพอร์ตี public จึงถูกตรึงไว้ ฟอนต์ที่แจงแล้วจึงเป็นข้อเท็จจริงที่เสถียรและแชร์ใช้ร่วมกันได้ FontInfo::encodeText() เป็นเมท็อดเดียวที่มีพฤติกรรม โดยส่งผ่าน encoding resolver และคืนค่าเป็น EncodedGlyphRun เสมอ

FontType ระบุเทคโนโลยีที่เอนจินใช้ฝัง ได้แก่ TrueType (การเข้ารหัสแบบไบต์เดียว) TrueTypeUnicode (การเข้ารหัสตัวระบุอักขระ (CID) แบบหลายไบต์สำหรับสคริปต์ที่มี Unicode หลากหลาย) OpenType (เส้นโครงร่างแบบ Compact Font Format) Type1 (PostScript Type 1 ที่ลงทะเบียนจากคู่ Printer Font Binary (PFB) และ Adobe Font Metrics (AFM)) และ CidFont0 (ฟอนต์ CID ที่อิงกับ PostScript) ชนิดที่ตัวแจงกำหนดจะเป็นตัวกำหนดรูปแบบของ font dictionary ที่ตัวเขียนสร้างออกมา

เพื่อให้การเรนเดอร์ไม่ขึ้นกับฟอนต์ระบบที่ติดตั้งไว้ เอนจินจะฝังโปรแกรมฟอนต์ — ISO 32000-2 §9 โปรแกรม TrueType ถูกฝังผ่านรายการ font-descriptor FontFile2 และต้องมีตาราง glyf, head, hhea, hmtx, loca, และ maxp — ISO 32000-2 §9.6.5 (RAG digest ถูกตัดทอนด้วยเพดานสัญญาอนุญาต บันทึกไว้ใน _downgraded-claims-o3.md) โปรแกรม OpenType ที่มีตารางเส้นโครงร่างแบบ Compact Font Format ถูกฝังผ่าน FontFile3 — ISO 32000-2 §9.6.5 (RAG digest ถูกตัดทอน ดูได้จากบันทึกเดียวกัน) ตัวทำ subset จะสร้างชุดตารางที่จำเป็นนี้ขึ้นใหม่อย่างครบถ้วน ดังนั้น subset ที่ฝังไว้จึงยังคงเป็นโปรแกรมที่สอดคล้องตามข้อกำหนด

การสำรองครอบคลุมกรณี Base 14 แบบเดิม Base14SubstituteFonts จะแมปคีย์ Base 14 ที่ปรับเป็นรูปแบบมาตรฐานแล้ว — helvetica, helveticab, times, courier, และคีย์ที่เหลือ — ไปยังไฟล์ Liberation Fonts ที่ให้มาในแพ็กเกจ Liberation Sans, Serif, และ Mono เข้ากันได้ทางเมตริกกับ Helvetica หรือ Arial, Times Roman, และ Courier แต่ละตัวเป็นหน้าตัวอักษร TrueType ที่ฝังได้ จึงเรนเดอร์ชุดอักขระละตินของ WinAnsiEncoding (Windows-1252) ได้ครบถ้วนตามที่การอ้างอิงฟอนต์มาตรฐาน 14 ตัวกำหนด — อักษรละตินที่มีเครื่องหมายกำกับเสียง เครื่องหมายยูโร และเครื่องหมายวรรคตอนเชิงการพิมพ์ทั่วไป (ISO 32000-2 Annex D.2) Symbol และ ZapfDingbats ไม่มีฟอนต์แทนที่เข้ากันได้ทางเมตริกและอนุญาตให้ใช้ได้อย่างเสรี ดังนั้น NextPDF จึงจงใจไม่แทนที่ฟอนต์เหล่านี้ เอกสารที่ต้องใช้ฟอนต์ใดฟอนต์หนึ่งต้องลงทะเบียนฟอนต์ที่ฝังได้ ตัว resolver ไม่มี side effect โดยตอบเพียงว่าคีย์แมปไปยังไฟล์ใดเท่านั้น ผู้เรียกยังคงรับผิดชอบการลงทะเบียนกับ registry พร้อมรักษาความหมายของการล็อกและไปป์ไลน์การวอร์มอัปไว้

ชนิดประเภทสมาชิกหลักความเสถียรตั้งแต่
FontInfofinal readonly class$family, $style, $type, $unitsPerEm, $widths, $unicodeMap, $cmapForward, $fileData, $variationAxes, $kernPairs, getKey(), encodeText()เสถียร1.0.0
FontTypeenum (string)TrueType, TrueTypeUnicode, OpenType, Type1, CidFont0เสถียร1.0.0
Base14SubstituteFontsfinal class (ภายใน)คีย์ Base 14 ที่ทำให้เป็นรูปแบบมาตรฐานไปยังพาธไฟล์ Liberation ที่ให้มาในแพ็กเกจเสถียร2.7.0
ShaperFactoryfinal classdefault(), create(), wouldUseRealShaper()เสถียร3.2.0
ShapingResultfinal readonly class$glyphRuns, $originalText, $script, $direction, $shaperImplเสถียร3.2.0

Base14SubstituteFonts เป็น @internal: ใช้ภายในเฟรมเวิร์กเท่านั้น และไม่มีการรับประกันความเข้ากันได้ย้อนหลังสำหรับส่วนติดต่อของคลาสนี้

examples/35-cjk-cmap-demo.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Typography\FontRegistry;
use NextPDF\Typography\FontType;
$registry = new FontRegistry();
$font = $registry->register('/path/to/NotoSansTC-Regular.ttf', alias: 'NotoSansTC');
// FontInfo is the immutable parsed fact about the face.
echo $font->family, ' / ', $font->type->value, "\n"; // e.g. "Noto Sans TC / TrueTypeUnicode"
assert($font->type === FontType::TrueTypeUnicode);

ตัวแจงจะเติมค่าให้ FontInfo และกำหนด FontType หน้าตัวอักษร TrueType ที่มีแมปอักขระแบบ Unicode จะกลายเป็น TrueTypeUnicode ซึ่งตัวเขียนจะสร้างออกมาเป็นฟอนต์เชิงประกอบ Type 0

examples/font/base14-fallback.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Typography\Base14SubstituteFonts;
use NextPDF\Typography\FontRegistry;
final readonly class Base14EmbeddingResolver
{
public function __construct(private FontRegistry $registry) {}
/**
* Register an embeddable substitute for a legacy Base 14 key so the
* output document embeds every font (PDF/A-4 and PDF/UA-2 require it).
*/
public function ensureEmbeddable(string $base14Key): void
{
$path = Base14SubstituteFonts::resolve($base14Key);
if ($path === null) {
// Symbol / ZapfDingbats have no permissive substitute — the
// caller must supply its own embeddable font.
throw new \RuntimeException("No bundled substitute for {$base14Key}");
}
if (!$this->registry->has($base14Key)) {
$this->registry->register($path, alias: $base14Key);
}
}
}

ตัว resolver ไม่มี side effect การลงทะเบียนยังคงต้องทำอย่างชัดแจ้ง ดังนั้นสัญญาด้านการล็อกและการวอร์มอัปของ registry จึงยังคงถูกต้อง Symbol และ ZapfDingbats ถูกออกแบบให้คืนค่าโดยไม่มีพาธ

  • Symbol และ ZapfDingbats จงใจไม่ถูกแทนที่ ผลลัพธ์ null สำหรับคีย์เหล่านี้เป็นพฤติกรรมที่ระบุไว้ในเอกสาร ไม่ใช่บั๊กจากฟอนต์หาย
  • FontInfo เป็น final readonly ให้ถือว่าฟอนต์ที่แจงแล้วเป็นค่า อย่าคาดหวังว่าจะแก้ไขความกว้างหรือเมตริกเดิมได้ ให้ลงทะเบียนใหม่หากแหล่งที่มาเปลี่ยนแปลง
  • ฟอนต์ Type 1 ต้องใช้ทั้งเส้นโครงร่าง PFB และเมตริก AFM FontRegistry::registerType1() รับคู่นี้ ส่วนการค้นพบอัตโนมัติจะอนุมานพาธ AFM จากพาธ PFB ด้วยนามสกุลไฟล์
  • FontType::TrueType และ FontType::TrueTypeUnicode ระบุความแตกต่างระหว่างแบบไบต์เดียวกับแบบหลายไบต์ ตัว encoding resolver ใช้แมปอักขระแบบไปข้างหน้าที่เติมค่าไว้ ไม่ใช่ชื่อ family ดังนั้นหน้าตัวอักษร TrueType แบบ Unicode จึงถูกส่งไปยังเส้นทาง Identity-H โดยอัตโนมัติ
  • แกน variation ของฟอนต์และอินสแตนซ์ที่มีชื่อจะถูกแจงเข้าไปใน FontInfo เมื่อมีข้อมูล แต่ตัวอย่างภาษาจีน ญี่ปุ่น และเกาหลี (CJK) ที่ใช้งานจริงจงใจใช้หน้าตัวอักษรแบบ static เพื่อให้ FontInfo ที่แจงได้มีผลลัพธ์แน่นอน

registry จัดสรร FontInfo หนึ่งครั้งต่อหนึ่งฟอนต์ต่อหนึ่งโปรเซส แล้วแชร์ใช้ผ่านการอ้างอิง ไบต์ฟอนต์ดิบเป็นตัวกำหนดต้นทุนหน่วยความจำเป็นหลัก ให้วอร์มเฉพาะฟอนต์ที่ worker ต้องใช้ และติดตาม memoryUsage() ตัว resolver ฟอนต์แทน Base 14 ค้นหาแมปด้วยเวลาคงที่โดยไม่มี input/output (I/O) จนกว่าผู้เรียกจะลงทะเบียนไฟล์ที่ resolve แล้ว performance_budget ที่ 1500 ms wall และ 64 MB peak ครอบคลุมการวอร์มอัปชุดฟอนต์ทั่วไปพร้อมการเรนเดอร์ จนกว่าตัวทำ subset จะทำงาน ปริมาณหน่วยความจำของแต่ละฟอนต์จะเพิ่มตามขนาดไฟล์ฟอนต์ ไม่ใช่จำนวน glyph

FontInfo นั้นไม่ทำงานเอง เป็นข้อมูลที่แจงแล้วซึ่งไม่มีพฤติกรรมใดนอกเหนือจากการแปลงแบบบริสุทธิ์ encodeText() พื้นผิวการโจมตีอยู่ที่ต้นทางระหว่างการแจง เมื่อไบต์ฟอนต์ใด ๆ เข้าถึงตัวแจง TrueType หรือ Type 1 ตัวแจงจะตรวจสอบขอบเขตของออฟเซ็ตไบนารีทุกตัว และปฏิเสธ stream wrapper รวมถึงไบต์ null ในพาธ ก่อนการลงทะเบียน อินพุตฟอนต์ที่ไม่น่าเชื่อถือต้องผ่านนโยบายทรัพยากรภายนอกที่จำกัดขนาดและจำนวน glyph ฟอนต์แทน Liberation ที่ให้มาในแพ็กเกจเป็นสินทรัพย์ที่เชื่อถือได้ซึ่งจัดส่งมาพร้อมกับแพ็กเกจ ดังนั้นเส้นทางการสำรองจึงไม่นำอินพุตที่ไม่น่าเชื่อถือใหม่เข้ามา

ข้อกล่าวอ้างมาตรฐานข้อกำหนดหลักฐาน
ฟอนต์ทุกตัวที่เอกสารใช้ถูกฝังไว้ เพื่อให้เอกสารเรนเดอร์ได้โดยไม่ต้องพึ่งพาฟอนต์ระบบISO 32000-2§9
โปรแกรม TrueType ถูกฝังผ่าน FontFile2 โดยมี glyf, head, hhea, hmtx, loca, maxp เป็นตารางISO 32000-2§9.6.5RAG digest ถูกตัดทอนด้วยเพดานสัญญาอนุญาต prefix 7b26f37996239b2a ดู _downgraded-claims-o3.md
โปรแกรม OpenType (CFF) ถูกฝังผ่าน FontFile3 เท่านั้นISO 32000-2§9.6.5RAG digest ถูกตัดทอนด้วยเพดานสัญญาอนุญาต prefix 801549ee00623baf ดู _downgraded-claims-o3.md

ข้อกำหนดแรกถูกตรึงด้วย digest และยืนยันโดย B1 ข้อกำหนด FontFile2 และ FontFile3 เป็นการถอดความ RAG digest ฉบับเต็มสำหรับข้อกำหนดเหล่านั้นไม่ได้ถูกส่งกลับ (การตัดทอนด้วยเพดานสัญญาอนุญาต) ดังนั้นหลักฐานจึงได้รับการยืนยันเพิ่มเติมโดย FontSubsetter (ซึ่งสร้างชุด glyf/head/hhea/hmtx/loca/maxp ขึ้นใหม่อย่างครบถ้วน) และ enum FontType NextPDF ไม่ทำซ้ำข้อความเชิงบรรทัดฐาน ในซอร์ส Base14SubstituteFonts อ้างอิง ISO 32000-2 §9.6.2.2 (การจัดการฟอนต์ Type 1 มาตรฐาน) ISO 14289-2:2024 §8.4.5.5.1 (การฝังฟอนต์ PDF/UA-2) และ ISO 19005-4:2020 §6.3.5 (การฝังฟอนต์ PDF/A-4) หน้าการเข้าถึงและความสอดคล้องมีรายละเอียดความสอดคล้องของโปรไฟล์ฉบับเต็ม

แพ็กการอนุญาตใช้สิทธิ์ฟอนต์เชิงพาณิชย์และบริการทำ subset แบบไดนามิกสร้างขึ้นบน FontInfo ของ Core และ registry โมดูลฟอนต์ Core ฝังฟอนต์ ทำ subset และสำรองได้โดยไม่ต้องมีไลเซนส์ การละเว้นลิงก์ conversion เป็นไปโดยเจตนา