Bỏ qua để đến nội dung

Phông chữ tùy chỉnh: hợp đồng mở rộng của FontRegistry

FontRegistryInterface định nghĩa hợp đồng đăng ký và tra cứu phông chữ tồn tại trong suốt vòng đời tiến trình. Hãy đăng ký phông chữ từ đường dẫn tệp, thư mục hoặc dữ liệu nhị phân thô, rồi khóa registry để các worker production không thể thay đổi nó.

Terminal window
composer require nextpdf/core:^3

Font registry là một singleton có vòng đời dài hơn từng instance Document. Nó chỉ lưu dữ liệu PHP thuần, không giữ resource handle hay đối tượng extension nào, nên bạn có thể chia sẻ nó giữa các request trong một worker chạy lâu dài.

Hãy dùng một trong ba cách đăng ký:

  • Từ một tệp. register() phân tích một tệp .ttf, .otf, .ttc hoặc .pfb và trả về metadata. Với một TrueType Collection, hãy truyền chỉ mục của phông chữ con.
  • Từ một thư mục. addFontDirectory() thêm đường dẫn tìm kiếm để engine quét khi phân giải họ phông chữ theo tên.
  • Từ dữ liệu nhị phân. registerFromBinary() phân tích các byte TrueType hoặc OpenType thô. Hãy dùng cách này cho cầu nối @font-face khi phông chữ đến từ một Uniform Resource Identifier (URI) data: hoặc từ nguồn từ xa.

Để giảm độ trễ ở request đầu tiên, hãy gọi warmup() khi worker khởi động để phân tích trước một loạt phông chữ. Sau đó gọi lock(). Sau lock(), mọi phương thức gây thay đổi đều ném LogicException: register(), addFontDirectory(), warmup(), registerBase14()registerFromBinary(). Các phương thức tra cứu vẫn dùng được: get(), has(), all()getSearchDirectories(). Cơ chế khóa này bảo vệ các worker production bằng cách đảm bảo không request nào có thể thay đổi tập phông chữ dùng chung.

Trong hầu hết trường hợp, bạn không cần tự hiện thực FontRegistryInterface. Engine cung cấp phần hiện thực; bạn chỉ cần gọi nó. Chỉ tự hiện thực khi bạn cần chiến lược phân giải phông chữ tùy chỉnh, chẳng hạn chiến lược dựa trên kho lưu trữ định địa chỉ theo nội dung. Trong cả hai trường hợp, hợp đồng vẫn là ranh giới.

NextPDF\Contracts\FontRegistryInterface (ổn định, kể từ 1.7.0):

Phương thứcTrả vềMục đích
register(string $fontFile, string $alias, int $fontIndex)FontInfoPhân tích và đăng ký một tệp phông chữ. Ném ngoại lệ khi registry đã bị khóa hoặc tệp không phân tích được.
registerFromBinary(string $fontData, string $alias)FontInfoĐăng ký một phông chữ từ các byte TrueType hoặc OpenType thô.
registerBase14(string $key, FontInfo $font)voidĐăng ký một phông chữ Base 14 chuẩn có sẵn.
addFontDirectory(string $directory)voidThêm một thư mục tìm kiếm phông chữ.
warmup(array $fontFiles)voidPhân tích trước một loạt phông chữ khi worker khởi động.
lock()voidĐóng băng registry để ngăn mọi thay đổi tiếp theo.
isLocked()boolBáo cáo xem registry có đang bị khóa hay không.
get(string $family, string $style)FontInfo | nullTra cứu một phông chữ theo họ và kiểu dáng.
has(string $key)boolKiểm tra xem một khóa đăng ký có tồn tại hay không.
all()array<string, FontInfo>Trả về mọi phông chữ đã đăng ký.
getSearchDirectories()list<string>Trả về các thư mục tìm kiếm theo thứ tự.
memoryUsage()MemoryReportBáo cáo lượng bộ nhớ registry đang sử dụng.
<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;
/** @var FontRegistryInterface $fonts */
$info = $fonts->register('/srv/fonts/Inter-Regular.ttf', 'Inter');
if (!$fonts->has('inter')) {
throw new RuntimeException('Inter failed to register');
}

Khi worker khởi động, hãy làm nóng tập phông chữ, khóa registry và ghi nhận từng lần tải để theo dõi giấy phép. Ví dụ này chỉ dùng các kiểu công khai.

<?php
declare(strict_types=1);
use NextPDF\Contracts\FontRegistryInterface;
use NextPDF\Event\Content\FontLoadedEvent;
use NextPDF\Event\EventDispatcher;
use NextPDF\Event\ListenerProvider;
use Psr\Log\LoggerInterface;
final class FontWarmup
{
/** @param list<string> $fontFiles */
public function __construct(
private readonly FontRegistryInterface $fonts,
private readonly LoggerInterface $logger,
private readonly array $fontFiles,
) {}
public function boot(): EventDispatcher
{
$listeners = new ListenerProvider();
$listeners->addListener(
FontLoadedEvent::class,
function (FontLoadedEvent $event): void {
$this->logger->info('font.loaded', [
'family' => $event->family,
'style' => $event->style,
'type' => $event->fontType->name,
]);
},
);
if (!$this->fonts->isLocked()) {
$this->fonts->warmup($this->fontFiles);
$this->fonts->lock();
}
return new EventDispatcher($listeners);
}
}
  • Registry đã khóa. Sau lock(), mọi thay đổi đều ném LogicException. Hãy kiểm tra isLocked() trước khi làm nóng có điều kiện trong một worker được dùng lại.
  • Đăng ký nhị phân không được cache theo khóa. registerFromBinary() ghi ra một tệp tạm rồi phân tích tệp đó. Hãy dùng FontInfo được trả về làm handle.
  • Chỉ mục TrueType Collection (TTC). Với một TrueType Collection, đối số thứ ba của register() chọn phông chữ con. Giá trị mặc định 0 chọn face đầu tiên.
  • Phân giải họ phông chữ. get() trả về null với một cặp họ-và-kiểu không xác định. Đừng bao giờ giả định kết quả khác null.

warmup() chuyển chi phí phân tích từ request đầu tiên sang lúc worker khởi động. Các phương thức registry dùng dữ liệu PHP thuần, còn các lần tra cứu là thao tác đọc map với thời gian hằng số. Hãy gọi memoryUsage() để cân đối tập phông chữ thường trú của worker với ngân sách bộ nhớ của bạn.

Một phông chữ đã đăng ký có thể được nhúng vào nội dung Portable Document Format (PDF). Hãy xác thực nguồn gốc của phông chữ trước khi đăng ký. Đừng đăng ký dữ liệu nhị phân do kẻ tấn công kiểm soát nếu chưa kiểm tra kích thước và định dạng. Hãy dùng hook FontLoadedEvent để thực thi việc tuân thủ giấy phép phông chữ và ghi lại những face mà tài liệu đã nhúng.

Không có tuyên bố quy chuẩn nào về ký số hoặc lưu trữ áp dụng ở đây. Việc nhúng phông chữ và tạo tập con tuân theo mô hình phông chữ của PDF 2.0. Bộ tạo tập con nội bộ chịu trách nhiệm cho sự tuân thủ đó; hợp đồng này thì không.

NextPDF Enterprise bổ sung chứng thực giấy phép phông chữ và chính sách tạo tập con được kiểm toán trên cùng một FontRegistryInterface. Mã đăng ký của bạn hoạt động như nhau trên các phiên bản vì hợp đồng là ranh giới.

Bảng thuật ngữ định nghĩa font registry, image registryevent listener; hãy xem bảng thuật ngữ đã xuất bản để biết định nghĩa chuẩn.