Lewati ke konten

Fon kustom: kontrak ekstensi FontRegistry

FontRegistryInterface mendefinisikan kontrak yang berlaku sepanjang masa hidup proses untuk mendaftarkan dan menemukan fon. Daftarkan fon dari path berkas, direktori, atau data biner mentah, lalu kunci registri agar worker produksi tidak dapat mengubahnya.

Terminal window
composer require nextpdf/core:^3

Registri fon adalah singleton yang masa hidupnya lebih panjang daripada setiap instance Document. Registri ini hanya menyimpan data PHP murni, tanpa handle sumber daya maupun objek ekstensi, sehingga Anda dapat membagikannya di antara permintaan dalam worker yang berjalan lama.

Gunakan salah satu dari tiga jalur pendaftaran berikut:

  • Dari berkas. register() mengurai berkas .ttf, .otf, .ttc, atau .pfb, lalu mengembalikan metadata. Untuk TrueType Collection, berikan indeks sub-fon.
  • Dari direktori. addFontDirectory() menambahkan path pencarian yang dipindai mesin saat menyelesaikan famili berdasarkan nama.
  • Dari data biner. registerFromBinary() mengurai bita TrueType atau OpenType mentah. Gunakan jalur ini sebagai jembatan @font-face ketika fon berasal dari Uniform Resource Identifier (URI) data: atau sumber jarak jauh.

Untuk mengurangi latensi permintaan pertama, panggil warmup() saat boot worker untuk mengurai sekumpulan fon sejak awal. Kemudian panggil lock(). Setelah lock(), setiap metode mutasi melempar LogicException: register(), addFontDirectory(), warmup(), registerBase14(), dan registerFromBinary(). Metode pencarian tetap tersedia: get(), has(), all(), dan getSearchDirectories(). Penguncian ini melindungi worker produksi dengan memastikan tidak ada permintaan yang dapat mengubah set fon bersama.

Dalam sebagian besar kasus, Anda tidak mengimplementasikan FontRegistryInterface. Mesin menyediakan implementasinya, dan Anda cukup memanggilnya. Implementasikan hanya ketika Anda memerlukan strategi penyelesaian fon kustom, misalnya yang didukung oleh penyimpanan beralamat-konten. Dalam kedua kasus tersebut, kontrak tetap menjadi batasnya.

NextPDF\Contracts\FontRegistryInterface (stabil, sejak 1.7.0):

MetodeMengembalikanTujuan
register(string $fontFile, string $alias, int $fontIndex)FontInfoMengurai dan mendaftarkan berkas fon. Melempar pengecualian jika registri terkunci atau berkas tidak dapat diurai.
registerFromBinary(string $fontData, string $alias)FontInfoMendaftarkan fon dari bita TrueType atau OpenType mentah.
registerBase14(string $key, FontInfo $font)voidMendaftarkan fon standar Base 14 bawaan.
addFontDirectory(string $directory)voidMenambahkan direktori pencarian fon.
warmup(array $fontFiles)voidMengurai sekumpulan fon sejak awal saat boot worker.
lock()voidMembekukan registri untuk mencegah mutasi lebih lanjut.
isLocked()boolMelaporkan apakah registri terkunci.
get(string $family, string $style)FontInfo | nullMencari fon berdasarkan famili dan gaya.
has(string $key)boolMemeriksa keberadaan kunci pendaftaran.
all()array<string, FontInfo>Mengembalikan semua fon yang terdaftar.
getSearchDirectories()list<string>Mengembalikan direktori pencarian dalam urutannya.
memoryUsage()MemoryReportMelaporkan penggunaan memori registri saat ini.
<?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');
}

Saat boot worker, lakukan warmup pada set fon, kunci registri, dan pantau setiap pemuatan untuk pelacakan lisensi. Contoh ini hanya menggunakan tipe publik.

<?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);
}
}
  • Registri terkunci. Setelah lock(), mutasi apa pun melempar LogicException. Periksa isLocked() sebelum melakukan warmup bersyarat pada worker yang didaur ulang.
  • Pendaftaran biner tidak di-cache berdasarkan kunci. registerFromBinary() menulis ke berkas sementara lalu menguraikannya. Gunakan FontInfo yang dikembalikan sebagai handle.
  • Indeks TrueType Collection (TTC). Untuk TrueType Collection, argumen ketiga pada register() memilih sub-fon. Nilai standar 0 memilih face pertama.
  • Penyelesaian famili. get() mengembalikan null untuk pasangan famili-dan-gaya yang tidak dikenal. Jangan pernah mengasumsikan hasilnya bukan null.

warmup() memindahkan biaya penguraian dari permintaan pertama ke boot worker. Metode registri menggunakan data PHP murni, dan pencarian adalah pembacaan map dengan waktu konstan. Panggil memoryUsage() untuk menyesuaikan ukuran set fon residen pada worker dengan anggaran memori Anda.

Fon yang terdaftar dapat disematkan ke dalam konten Portable Document Format (PDF). Validasi asal-usul fon sebelum pendaftaran. Jangan mendaftarkan data biner yang dikendalikan penyerang tanpa pemeriksaan ukuran dan format. Gunakan hook FontLoadedEvent untuk menegakkan kepatuhan lisensi fon dan mencatat face mana saja yang disematkan dalam sebuah dokumen.

Tidak ada klaim normatif penandatanganan atau pengarsipan yang berlaku. Penyematan dan subsetting fon sesuai dengan model fon PDF 2.0. Kesesuaian tersebut dipikul oleh subsetter internal; bukan oleh kontrak ini.

NextPDF Enterprise menambahkan atestasi lisensi fon dan kebijakan subsetting teraudit di atas FontRegistryInterface yang sama. Kode pendaftaran Anda berfungsi sama di seluruh edisi karena kontrak tersebut menjadi batasnya.

Glosarium mendefinisikan registri fon, registri gambar, dan pendengar peristiwa; lihat glosarium yang diterbitkan untuk definisi kanoniknya.