Typography: registry phông chữ, subsetting, CMap, mã hóa, BiDi
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Module typography biến một tệp phông chữ và một chuỗi Unicode thành các byte mà luồng nội dung của Portable Document Format (PDF) cần. Module này đảm nhiệm việc phân tích phông chữ, duy trì registry theo vòng đời tiến trình, tạo tập con glyph, phát CMap ToUnicode, cung cấp các chiến lược mã hóa theo cmap và bộ máy hai chiều Unicode.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/core:^3Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”FontRegistry lưu phông chữ trong suốt vòng đời của một tiến trình và hiện thực FontRegistryInterface. Nó phân tích một tệp TrueType, OpenType, TrueType Collection (TTC) hoặc Type 1 (Printer Font Binary (PFB) và Adobe Font Metrics (AFM)) đúng một lần, rồi trả về một FontInfo bất biến. Hãy dùng nó cho các worker chạy lâu dài: nạp sẵn bộ phông chữ khi khởi động, rồi gọi lock(). Sau đó, registry từ chối mọi thay đổi, trong khi các lượt tra cứu vẫn tiếp tục phục vụ lưu lượng. Nó chỉ chứa dữ liệu PHP thuần: siêu dữ liệu đã phân tích và các byte phông chữ thô. Một nhóm worker có thể dùng chung một instance. registerFromBinary() nhận các byte phông chữ thô, là cơ chế mà cầu nối @font-face của HyperText Markup Language (HTML) dùng cho một phông chữ được tải về từ nguồn ở xa hoặc từ một data URI.
Bộ máy nhúng và tạo tập con cho mọi phông chữ được dùng. Chương trình phông chữ được nhúng kèm trong PDF, nên tài liệu hiển thị nhất quán trên mọi trình xem và không phụ thuộc vào các phông chữ hệ thống đã cài đặt — ISO 32000-2 §9. Một tập con chỉ mang theo những glyph mà tài liệu tham chiếu đến; điều này đặc biệt quan trọng với nội dung tiếng Trung, tiếng Nhật và tiếng Hàn (CJK) hoặc nội dung giàu Unicode — ISO 32000-2 §9. FontSubsetter phân tích thư mục bảng gốc, trích xuất cmap, giải quyết các phụ thuộc glyph hợp thành dưới dạng bao đóng bắc cầu, rồi dựng lại các bảng head, hhea, maxp, cmap, loca, glyf và hmtx. Nó giữ nguyên cách đánh số định danh glyph gốc và lấp số không vào các vị trí không dùng đến, nhờ vậy một CIDToGIDMap kiểu /Identity vẫn hợp lệ. Nó trả về nguyên vẹn phông chữ gốc khi tập con chỉ tiết kiệm được dưới mười phần trăm, để tránh làm những việc không đáng công. CffSubsetter thực hiện cùng thao tác đó cho các phông chữ OpenType có chứa bảng đường nét Compact Font Format.
Việc phát văn bản đi qua ba lần chuyển đổi: điểm mã Unicode, mã ký tự trong luồng nội dung, và định danh glyph bên trong phông chữ. Module giữ đường đi đó tường minh. FontInfo::encodeText() là facade; FontEncodingStrategyResolver điều phối theo từng phông chữ. Một phông chữ TrueType hoặc OpenType được nhúng có cmap Unicode sẽ được định tuyến tới TrueTypeCmapStrategy, nơi phát ra một luồng hex Identity-H hai byte. Đó là dạng mà một phông chữ Type 0 với CMap Identity-H và một hậu duệ CIDFontType2 yêu cầu (ISO 32000-2 §9.7.4; phần tóm tắt khối retrieval-augmented generation (RAG) tương ứng được trả về dưới dạng cắt cụt do giới hạn giấy phép, được ghi lại trong _downgraded-claims-o3.md). Mọi phông chữ khác — các phông chữ chuẩn Base 14, Type 1 PFB và AFM — đều được định tuyến tới Base14EncodingStrategy, nơi phát ra một chuỗi literal WinAnsi một byte. Luồng đó bao phủ toàn bộ kho ký tự của WinAnsiEncoding (Windows code page 1252) — Latinh có dấu, ký hiệu Euro và các dấu chấm câu kiểu chữ thông dụng. Các điểm mã nằm ngoài kho này bị loại khỏi luồng đơn byte và sẽ dùng cơ chế dự phòng phông chữ theo từng cụm khi một phông chữ có khả năng bao phủ được đăng ký (ISO 32000-2 Annex D.2). Resolver bao phủ toàn bộ không gian giá trị của FontInfo; không có đường đi nào trả về null. ToUnicodeCMapBuilder dựng tài nguyên /ToUnicode để trình đọc có thể khôi phục Unicode gốc từ một phông chữ Identity-H. Nó áp dụng cách gộp bfrange tham lam và giới hạn 100 mục cho mỗi khối.
BidiEngine là dịch vụ ranh giới cho Unicode Bidirectional Algorithm, được định nghĩa bởi Unicode Standard Annex #9 (UAX #9), Unicode 16. Khi hỗ trợ isolate bị tắt, nó ủy quyền cho resolver cũ để các bên gọi hiện có nhận cùng một hành vi. Khi hỗ trợ isolate được bật, nó chạy pipeline nhận biết isolate: ngăn xếp isolate tường minh với độ sâu tối đa là 125, các lượt xử lý kiểu yếu, các lượt xử lý kiểu trung tính bao gồm cả việc giải quyết cặp ngoặc, cùng các lượt xử lý mức ngầm định và sắp xếp lại dòng. Mức độ phủ glyph CJK cho một phông chữ ứng viên là một chẩn đoán riêng biệt: CjkFontValidator lấy mẫu các khối Unicode cần thiết theo từng hệ chữ viết và báo cáo tỷ lệ phần trăm độ phủ.
Bề mặt API
Phần tiêu đề “Bề mặt API”| Kiểu | Loại | Thành viên chính | Độ ổn định | Có từ |
|---|---|---|---|---|
FontRegistry | final class | register(), registerType1(), registerFromBinary(), registerFromDirectory(), get(), has(), all(), warmup(), lock(), isLocked(), memoryUsage() | ổn định | 1.7.0 |
FontInfo | final readonly class | $family, $type, $widths, $unicodeMap, $cmapForward, getKey(), encodeText() | ổn định | 1.0.0 |
FontSubsetter | final class | subset(string, array<int>, int): string | ổn định | 1.0.0 |
CffSubsetter | final class | Tạo tập con đường nét OpenType/CFF | ổn định | 1.0.0 |
FontEncodingStrategyResolver | final class | resolve(FontInfo): FontEncodingStrategy | ổn định | 2.7.0 |
ToUnicodeCMapBuilder | final class | buildFromRun(), buildFromMap(), encodeUnicodeUtf16Be() | ổn định | 2.7.0 |
BidiEngine | final class | Giải quyết nhận biết isolate theo UAX #9 | ổn định | 3.1.0 |
CjkFontValidator | final class | validateCoverage(), detectScript(), isCjkCodepoint() | ổn định | 1.0.0 |
FontInfo là bất biến: chữ ký hàm khởi tạo và các thuộc tính công khai của nó đã được cố định. Các chiến lược mã hóa là những hàm thuần của (FontInfo, UTF-8 text): cùng một đầu vào sẽ trả về cùng một EncodedGlyphRun trong mọi lần gọi.
Mẫu mã — bắt đầu nhanh
Phần tiêu đề “Mẫu mã — bắt đầu nhanh”<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Typography\Encoding\EncodingMode;use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();$cjkFont = $registry->register('/path/to/NotoSansTC-Regular.ttf', alias: 'NotoSansTC');
$encoded = $cjkFont->encodeText('PDF 2.0 引擎 — 使用 CMap 編碼');
// An embedded CJK TrueType face resolves to the two-byte Identity-H path.assert($encoded->mode === EncodingMode::TwoByteCid);register() phân tích phông chữ một lần và trả về một FontInfo bất biến. encodeText() đi qua resolver và trả về một EncodedGlyphRun gồm luồng byte, toán hạng chuỗi PDF, độ rộng tiến của từng glyph, và bản ánh xạ từ định danh glyph (GID) sang Unicode mà một CMap /ToUnicode tiêu thụ.
Mẫu mã — Production
Phần tiêu đề “Mẫu mã — Production”<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Exception\NextPdfException;use NextPDF\Typography\FontRegistry;use Psr\Log\LoggerInterface;
final readonly class FontBootstrap{ public function __construct( private FontRegistry $registry, private LoggerInterface $logger, ) {}
/** * Warm a font set at worker boot, then lock the registry for the * lifetime of the process. * * @param list<string> $fontFiles Absolute paths to font files. */ public function boot(array $fontFiles): void { try { $this->registry->warmup($fontFiles); $this->registry->lock(); } catch (NextPdfException $e) { $this->logger->error('Font warmup failed', ['error' => $e->getMessage()]);
throw $e; }
$report = $this->registry->memoryUsage(); $this->logger->info('Font cache primed', [ 'fonts' => $report->entryCount, 'bytes' => $report->currentBytes, ]); }}warmup() rồi đến lock() là trình tự khởi động của worker. Sau lock(), mọi thay đổi đều ném ngoại lệ, còn việc tra cứu vẫn tiếp tục phục vụ lưu lượng. memoryUsage() trả về một MemoryReport, nhờ vậy worker có thể theo dõi cache phông chữ so với ngân sách của mình.
Trường hợp biên và điểm cần lưu ý
Phần tiêu đề “Trường hợp biên và điểm cần lưu ý”- Khi registry đã bị khóa, nó từ chối
register(),registerFromBinary(),addFontDirectory()vàwarmup(). Hãy nạp sẵn và khóa khi khởi động; đừng bao giờ đăng ký trong lúc xử lý yêu cầu. FontSubsetter::subset()trả về nguyên vẹn các byte gốc khi mức tiết kiệm dưới mười phần trăm hoặc khi thiếu một bảng thiết yếu. Một phông chữ được trả về giống hệt đầu vào là đường đi không-có-lợi đã được ghi rõ trong tài liệu, không phải là lỗi.- Bộ tạo tập con giữ nguyên cách đánh số định danh glyph gốc và lấp số không cho các glyph không dùng đến. Điều này giữ cho
CIDToGIDMap /Identityluôn hợp lệ; đừng giả định rằng các định danh glyph được đánh số lại thành một khoảng liên tục. registerFromBinary()ghi các byte vào một tệp tạm để phân tích và xóa cả tệp phần mở rộng lẫn tệp cơ sởtempnam()trong một khốifinally. Dữ liệu phông chữ không đáng tin là một bề mặt tấn công trong quá trình phân tích; hãy kiểm soát nó trước khi nó đến được bộ phân tích (xem Ghi chú bảo mật).BidiEngineủy quyền nguyên vẹn cho resolver cũ khi hỗ trợ isolate bị tắt. Khi đó, các ký tự định dạng isolate đi qua như những ký tự trung tính về ranh giới. Hãy bật hỗ trợ isolate thông qua chính sách tuân thủ để có đầy đủ hành vi theo UAX #9.CjkFontValidatorlấy mẫu các điểm mã theo bước nhảy thay vì kiểm tra từng điểm một, nên con số độ phủ của nó là một ước lượng đủ tin cậy về mặt thống kê, chứ không phải một phép đếm đầy đủ.
Hiệu năng
Phần tiêu đề “Hiệu năng”Việc phân tích phông chữ chiếm phần lớn chi phí trong lần dùng đầu tiên; registry dàn chi phí đó xuống còn một lần cho mỗi tiến trình. Sau khi nạp sẵn, get() và has() là các phép tra cứu trên map với độ phức tạp O(1). Chi phí tạo tập con tỷ lệ với số lượng glyph mà tài liệu dùng, chứ không tỷ lệ với toàn bộ bảng glyph của phông chữ. Đó là lý do việc tạo tập con cải thiện cả kích thước lẫn tốc độ cho nội dung CJK: bộ tạo tập con xử lý các phông chữ có hơn 20,000 glyph bằng tìm kiếm nhị phân, các bộ đệm được cấp phát trước và các thao tác chuỗi hàng loạt. Việc giải quyết glyph hợp thành có giới hạn; nó dừng ở mức 100 vòng lặp bao đóng để phòng vệ trước các tham chiếu thành phần vòng tròn. Bộ phân tích cmap Format 12 giới hạn số lượng nhóm và mục để hạn chế lượng bộ nhớ sử dụng đối với phông chữ đầu vào ác ý. performance_budget gồm 1500 ms thời gian thực và 64 MB đỉnh, bao gồm một lần nạp sẵn phông chữ thông thường cộng với kết xuất tài liệu.
Ghi chú bảo mật
Phần tiêu đề “Ghi chú bảo mật”Có hai bề mặt có trọng số bảo mật. Bề mặt thứ nhất là đầu vào phông chữ. register() và registerFromBinary() phân tích các byte tùy ý. registerFromBinary() tạo ra một tệp tạm. Ranh giới từ chối các stream wrapper và byte null trong đường dẫn. Dữ liệu phông chữ không đáng tin phải đi qua một chính sách tài nguyên bên ngoài, nơi giới hạn kích thước tệp và số lượng glyph, trước khi đến được bộ phân tích. Các bộ đọc nhị phân của bộ tạo tập con kiểm tra giới hạn cho mọi offset. Các bộ phân tích cmap giới hạn số lượng nhóm, mục và bảng (numGroups > 31000 và giới hạn mục là 200,000 trong Format 12) để một phông chữ được tạo dựng có chủ đích không thể gây ra việc cấp phát không giới hạn. Bề mặt thứ hai là việc khôi phục văn bản: ToUnicodeCMapBuilder kiểm tra rằng mọi mã ký tự đều nằm trong không gian mã 16 bit và mọi giá trị Unicode đều là một scalar hợp lệ. Nó từ chối các nửa surrogate, nên một bản ánh xạ dị dạng không thể tạo ra một tài nguyên trích xuất bị hỏng. Hãy xem mọi phông chữ hoặc văn bản được cung cấp từ bên ngoài là không đáng tin.
Tuân thủ
Phần tiêu đề “Tuân thủ”| Tuyên bố | Tiêu chuẩn | Điều khoản | Bằng chứng |
|---|---|---|---|
| Mọi phông chữ mà tài liệu dùng đều được nhúng để tài liệu hiển thị mà không phải dựa vào các phông chữ hệ thống. | ISO 32000-2 | §9 | |
| Phông chữ được nhúng được tạo tập con gồm các glyph mà tài liệu tham chiếu đến. | ISO 32000-2 | §9 | |
Một kiểu chữ TrueType CJK được nhúng sẽ được phát dưới dạng một phông chữ Type 0 với CMap Identity-H và một hậu duệ CIDFontType2. | ISO 32000-2 | §9.7.4 | Phần tóm tắt RAG bị cắt cụt do giới hạn giấy phép; tiền tố 7a5258772f508e3b, xem _downgraded-claims-o3.md |
Hai điều khoản đầu được diễn giải lại và ghim theo bản tóm tắt. Bản tóm tắt RAG đầy đủ của điều khoản thứ ba đã không được trả về (do bị cắt cụt bởi giới hạn giấy phép); ADR-013 và bản tổng quan dành cho lập trình viên về cmap-encoder xác nhận điều đó, và nó được ghi lại là đã hạ cấp. NextPDF không sao chép lại văn bản quy phạm. Việc tuân thủ PDF/A-4 và PDF/UA-2 cho nội dung CJK phụ thuộc vào việc tạo tập con ở phía writer và việc đấu nối /ToUnicode được theo dõi tại đó.
Bối cảnh thương mại
Phần tiêu đề “Bối cảnh thương mại”Một gói tính năng OpenType thương mại và các chuỗi dự phòng phông chữ cao cấp được xây dựng trên registry Core và lớp mã hóa. Module typography Core nhúng, tạo tập con và mã hóa mọi phông chữ mà không cần giấy phép; gói trả phí bổ sung khả năng giải quyết dự phòng được tuyển chọn. Việc bỏ qua liên kết chuyển đổi là có chủ đích: trang này là tài liệu, không phải kênh bán hàng.
Xem thêm
Phần tiêu đề “Xem thêm”- Font: registry TrueType, OpenType và CID — các kiểu giá trị phông chữ, nhúng và dự phòng.
- Text: tạo hình, ngắt dòng, BiDi — xử lý và tạo hình các run tiêu thụ các glyph đã mã hóa.
- Contracts / Typography — các contract
FontRegistryInterfacevà bộ tiền xử lý văn bản. - Bộ máy kết xuất HTML — cầu nối
@font-facegọi đếnregisterFromBinary().