Üretimde yazı tiplerini sağlayın
Bir bakışta
“Bir bakışta” başlıklı bölümPDF’iniz dizüstü bilgisayarınızda doğru işlenir, sonra bir kapsayıcıya gönderilir ve bir dizi boş kutu — “tofu” glifi — olarak ya da eksik aksanlar ve Latin olmayan karakterlerle çıkar. Neden neredeyse her zaman aynıdır: seçtiğiniz yazı tipi, dağıtılan görüntüde mevcut değildir.
Yerel, süreç içi NextPDF motoru, yazı tiplerini yazı tipi kayıt defterinin
okuyabildiği yazı tipi dosyalarından çözümler. OS veya fontconfig yazı
tiplerini otomatik olarak keşfetmez — OS’a kurulu yazı tipi dosyaları yalnızca, bu
dosyaları açıkça kaydederseniz veya onları içeren dizini FontRegistry arama
yoluna eklerseniz işe yarar. Yalın bir temel görüntüden derlenmiş bir kapsayıcıda
apt/apk ile kurulu yazı tipleri yoktur ve olsalar bile, kayıt defterini
dosyalarına yönlendirmediğiniz sürece yerel motor bunları yok sayar. Çözüm, gerçek
yazı tipi dosyalarını uygulamanızın veya görüntünüzün içinde paketlemek ve onları
motora kaydetmektir. Kayıt defteri, TrueType (.ttf), OpenType (.otf) ve
TrueType Collection (.ttc) dosyalarını okur; eski Type1 (.pfb) de kabul edilir
ancak yeni işler için nadiren gereklidir.
Başlamadan önce, şu parçaların yerinde olduğunu onaylayın:
- NextPDF core kuruludur.
- Kullanmayı düşündüğünüz gerçek yazı tipi dosyalarına sahipsiniz ve bunları gömme lisansınız var. Gömme hakları sizin sorumluluğunuzdadır — bkz. Bir TrueType yazı tipini gömün ve alt küme oluşturun.
- Derlemeniz bu dosyaları dağıtılan yapıta kopyalayabilir.
Bu bir işletim nasıl-yapılır kılavuzudur. Kod en azdır; iş, derlemede ve dosya sistemi düzenindedir. Tek bir yüzeyi kaydetme ve alt küme oluşturmanın API düzeyindeki mekaniği için yukarıda bağlantısı verilen embed-and-subset tarifini okuyun. Bu sayfa, dosyaları makineye almayı ve motoru onlara yönlendirmeyi kapsar.
Yerel motor OS yazı tiplerini neden otomatik olarak bulmaz
“Yerel motor OS yazı tiplerini neden otomatik olarak bulmaz” başlıklı bölümİki ayrı işleme yolu vardır ve yazı tipi öyküsü aralarında farklıdır.
- Yerel süreç içi motor (varsayılan,
Document/writeHtml): motor, keşif için işletim sisteminin yazı tipi sistemini veyafontconfig’i çağırmaz. Bir yüzeyi, kaydettiğiniz belirli bir yazı tipi dosyasını okuyan ya da arama yolu olarak yapılandırdığınız bir dizinin içinde birini bulan yazı tipi kayıt defteri aracılığıyla çözümler.apt-get install fonts-notoile bir yazı tipi kurmak veyafc-cacheçalıştırmak tek başına hiçbir şey yapmaz — yerel motor, bu dosyaları yalnızca onları kaydederseniz ya da dizinlerini kayıt defterinin arama yoluna eklerseniz görür. - Chrome köprüsü (başsız bir tarayıcıyı süren HTML’den PDF’e işleyici): bu yol
tarayıcının normal yazı tipi keşfi aracılığıyla ana makinenin kurulu yazı
tiplerini kullanır, dolayısıyla
apt/apkyazı tipi paketleri vefontconfigorada önemlidir.
Genel “bu sistem yazı tipi paketlerini Dockerfile’ınıza kurun” yönergesini okursanız, bu Chrome köprüsü için geçerlidir, bu sayfada ele alınan yerel motor için değil. Yerel üretim için dosyaları paketleyin ve onları kaydedin.
1. Adım — Gerçek yazı tipi dosyalarını paketleyin
“1. Adım — Gerçek yazı tipi dosyalarını paketleyin” başlıklı bölümYazı tipi dosyalarını, sürümlenip her derlemeyle birlikte gönderilmeleri için
uygulama ağacınızın içine koyun. Geleneksel bir konum, bir resources/fonts/
dizinidir.
your-app/├── resources/│ └── fonts/│ ├── DejaVuSans.ttf│ ├── DejaVuSans-B.ttf│ └── NotoSansCJK-Regular.ttc└── src/Dosyaları, motorun dizin aramasının onları aileye ve stile göre bulabilmesi için
adlandırın. Belirli bir dosya yerine bir dizin kaydettiğinizde ve daha sonra
setFont('DejaVuSans', 'B', 12) çağırdığınızda, motor yapılandırılmış her dizinde
DejaVuSans-B.ttf, DejaVuSansB.ttf veya DejaVuSans.ttf gibi dosyalar arar.
Dizin araması bu aday adları, yazılı bir sözcükten değil, setFont’a geçirdiğiniz
aynı tek harfli stil kodundan oluşturur (B kalın için, I italik için, BI
kalın-italik için) — bu nedenle güvenilir biçim Family-<StyleCode>.ttf’dir
(örneğin DejaVuSans-B.ttf veya DejaVuSans-BI.ttf), Family-Bold.ttf değil.
DejaVuSans-Bold.ttf adlı bir dosya, dizin araması tarafından asla bulunmaz; böyle
bir dosyayı kullanmak için onu register() ile açıkça kaydedin — bu yazı tipini
ayrıştırır ve dosyanın kendi ad tablolarından okunan aileye ve stile göre dizinler,
böylece yazılı dosya adı artık önemli olmaz (bkz. 2. Adım).
2. Adım — Yazı tiplerini motora kaydedin
“2. Adım — Yazı tiplerini motora kaydedin” başlıklı bölümDosyaları görünür kılmanın iki eşdeğer yolu vardır. İkisi de
NextPDF\Contracts\FontRegistryInterface arayüzünü uygulayan
NextPDF\Typography\FontRegistry üzerinden gider.
Tam yüzeyi denetlediğinizde, bir takma ad altında belirli bir dosyayı kaydedin:
use NextPDF\Typography\FontRegistry;
$registry = new FontRegistry();$registry->register(__DIR__ . '/../resources/fonts/DejaVuSans.ttf', alias: 'DejaVuSans');register(string $fontFile, string $alias = '', int $fontIndex = 0), .ttf,
.otf ve .ttc dosyalarını, ayrıca eski Type1 .pfb dosyalarını (eşlik eden
.afm ölçümlerini aynı yoldan yükler) kabul eder; $fontIndex, bir TrueType
Collection (.ttc) içindeki bir alt yazı tipini seçer. register(), dosyayı
ayrıştırır ve yüzeyi kendi ad tablolarından okunan aileye ve stile göre dizinler,
böylece kaydedildikten sonra fiziksel dosya adı önemsizdir. İsteğe bağlı $alias,
yüzey için yalnızca ek bir arama adıdır — bir stil kodu değildir ve dosyanın
hangi stili sağladığını değiştirmez; setFont()’u yazı tipinin gömülü aile
adından farklı bir adla çağırmak istediğinizde geçirin. Ayrıştırılan FontInfo’yu
döndürür.
Motorun, denetlediğiniz bir klasörden yüzeyleri ada göre çözümlemesini istediğinizde bir dizin kaydedin:
$registry = new FontRegistry('/var/www/app/resources/fonts');// or, equivalently, after construction:$registry->addFontDirectory('/var/www/app/resources/fonts');FontRegistry yapıcısı bu dizini ilk argümanı olarak alır ve addFontDirectory()
daha fazla arama yolu ekler. Yalın bir Document da bağımsız durum için
addFontDirectory() sunar.
Kendiniz doldurduğunuz bir kayıt defterini kullanmak için belgeleri,
oluşturduğu her belgeye tam olarak o kayıt defterini bağlayan DocumentFactory
üzerinden oluşturun:
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;
$factory = new DocumentFactory($registry, new ImageRegistry(maxCacheBytes: 0));
$doc = $factory->create();$doc->addPage();$doc->setFont('DejaVuSans', '', 12);$doc->cell(0, 10, 'Réndéred wîth a bundled face — no tofu.', newLine: true);$doc->save('/tmp/out.pdf');Document::createStandalone() kendi iç kayıt defterini oluşturur, dolayısıyla
ayrı bir FontRegistry üzerinde kaydettiğiniz bir yüzey ona görünmez. Üretimde,
doldurulan kayıt defterinin kullanımda olanı olması için DocumentFactory (veya
çerçevenizin fabrikası) üzerinden gidin.
Çerçeve yapılandırması
“Çerçeve yapılandırması” başlıklı bölümHer çerçeve tümleştirmesi aynı iki kavramı yapılandırma olarak sunar, dolayısıyla
kayıt defterine nadiren doğrudan dokunursunuz. Laravel paketinin nextpdf.php
dosyasında, fonts_path (varsayılan NEXTPDF_FONTS_PATH, resource_path('fonts')
değerine geri düşerek) arama dizinidir ve preload_fonts, çalışan başlatmasında
ayrıştırılan mutlak yazı tipi dosyası yollarının bir listesidir. fonts_path
değerini paketlediğiniz dizine yönlendirin; kaydedilen yüzeyleriniz otomatik olarak
çözümlenir.
3. Adım — Bir Docker görüntüsünde yazı tiplerini sağlayın
“3. Adım — Bir Docker görüntüsünde yazı tiplerini sağlayın” başlıklı bölümBir kapsayıcıda yazı tipi dosyaları, derleme zamanında kopyalanarak görüntü
katmanının parçası olmalıdır. Uygulama kodu ve yazı tipleri, onları
resources/fonts/ altında paketlediğinizde birlikte gönderildiği için, normal bir
COPY . . zaten onları taşır. Yazı tiplerini derleme bağlamı dışında tutarsanız,
onları açıkça kopyalayın ve kaydettiğiniz yolun görüntü içindeki yolla eşleştiğinden
emin olun.
# Native engine: NO system font packages are required.# The native engine does not discover OS-installed fonts automatically; install OS# font packages (`apt-get install fonts-*`) only if you also register them or point# the font registry's search directory at their files.FROM php:8.4-cli
WORKDIR /var/www/app
# Bundle the application, including resources/fonts/, into the image.COPY . /var/www/app
# Make the bundled directory the engine's font search path.ENV NEXTPDF_FONTS_PATH=/var/www/app/resources/fonts
CMD ["php", "bin/generate.php"]Değişmez veya salt okunur bir dosya sisteminde (bir readOnlyRootFilesystem
kapsayıcısı, bir sunucusuz görüntü veya sertleştirilmiş bir ana makine), yazı tipi
dosyaları üretim zamanında okunur ve asla yazılmaz, dolayısıyla salt okunur bir
bağlama sorunsuzdur. Motorun isteyebileceği tek yazma, ayrıştırılmış yazı tipi
önbelleğidir: ya o dizine küçük bir yazılabilir birim verin ya da çalışma zamanında
hiçbir yazma veya kayıt denenmemesi için başlatmada kayıt defterini ısıtıp kilitleyin
(sonraki bölüm).
4. Adım — Isıtın ve doğrulayın
“4. Adım — Isıtın ve doğrulayın” başlıklı bölümUzun ömürlü bir çalışanda, her yüzeyi başlatmada bir kez ayrıştırın, ardından kayıt defterini kilitleyin; böylece istek başına kayıt gerçekleşmez ve bir yanlış yapılandırma sessizce geri düşmek yerine yüksek sesle başarısız olur:
$registry = new FontRegistry('/var/www/app/resources/fonts');$registry->warmup([ '/var/www/app/resources/fonts/DejaVuSans.ttf', '/var/www/app/resources/fonts/DejaVuSans-B.ttf',]);$registry->lock();lock()’tan sonra register(), addFontDirectory() ve warmup() fırlatır; bu da
“görüntüdeki yanlış yol” hatasını üretimdeki bir tofu sayfası yerine sert bir
başlatma başarısızlığına çevirir.
Gereken her yüzeyle bir sayfa işleyen bir dağıtım duman denetimi ekleyin. Aşağıdaki başlık denetimi yalnızca belgenin çıktı ürettiğini doğrular — yazı tipinin ayrıştırıldığını, gömüldüğünü ya da çözümlendiğini bile kanıtlamaz. Motorun bulamadığı bir yüzey, geçerli ve boş olmayan bir PDF yaymaya devam ederken standart bir temel yazı tipine geri düşebilir (ve geçerli katı olmayan davranış altında, bir uyumluluk profili bunun yerine paketlenmiş bir ikame sağlayabilir) — bu nedenle o geri düşme gerçekleştiğinde bile yalnızca bu denetim sessiz bozulmayı yakalamaz. Geri düşmenin her yolda garantili veya sessiz olduğuna güvenmeyin; gömülü programı, aşağıda gösterildiği gibi doğrudan doğrulayın:
$doc = $factory->create();$doc->addPage();$doc->setFont('DejaVuSans', '', 12);$doc->cell(0, 10, 'warmup check', newLine: true);
$pdf = $doc->getPdfData();
// `getPdfData()` would normally throw on a real failure; this header check only// confirms serialization returned PDF bytes, not that any specific font resolved.if (!str_starts_with($pdf, '%PDF')) { throw new RuntimeException('Font warmup smoke check produced no PDF output.');}Bir yüzey eksik olduğunda dağıtımı gerçekten başarısız kılmak için yayılan PDF’i
gömülü yazı tipi programı açısından denetleyin. Çözümlenen kaydedilmiş bir yüzey,
gömülü bir programa sahip kendi yazı tipi sözlüğünü taşır, dolayısıyla varlığını
ileri sürmek, başlık denetiminin kaçırdığı, istenen yüzeyin hiç çözümlenmediği
(motorun her ne şeye geri düştüğünden bağımsız) durumu yakalar. Programı hangi
anahtarın tuttuğu, ana hat biçimine bağlıdır: TrueType ana hatları (.ttf,
.ttc) /FontFile2 kullanır, CFF/OpenType ana hatları (PostScript ana hatlı
.otf) /FontFile3 kullanır ve eski Type1 (.pfb) /FontFile kullanır.
Tek ihtiyacınız biçimden bağımsız bir “bir yazı tipi programı gömülü” sinyaliyse,
yalnızca /FontFile için test edin — çünkü /FontFile hem /FontFile2 hem de
/FontFile3’ün bir alt dizesidir, dolayısıyla yalın bir alt dize denetimi zaten her
ana hat türüyle eşleşir ve /FontFile2//FontFile3’ü ek || dalları olarak eklemek
gereksizdir:
if (!str_contains($pdf, '/FontFile')) { throw new RuntimeException('No embedded font program found — face fell back.');}Ancak yalın bir /FontFile alt dizesi, ana hat türlerini ayırt edemez. Onları ayırt
etmek için, /FontFile’ın /FontFile2 veya /FontFile3 üzerinde de tetiklenmemesi
için bir sözcük sınırı ile tam belirteç üzerinde eşleştirin:
$isTrueType = preg_match('~/FontFile2\b~', $pdf) === 1; // TrueType (.ttf/.ttc)$isCffOtf = preg_match('~/FontFile3\b~', $pdf) === 1; // CFF/OpenType (.otf)$isType1 = preg_match('~/FontFile(?![23])\b~', $pdf) === 1; // Type1 (.pfb)
if (!$isTrueType && !$isCffOtf && !$isType1) { throw new RuntimeException('No embedded font program found — face fell back.');}Her iki durumda da bunu güvenilir bir dağıtım kapısı olarak değil, yalnızca kaba
bir buluşsal yöntem olarak ele alın. Serileştirilen PDF üzerinde ham bir bayt
araması birkaç nedenle hatalıdır: yazı tipi programları sıkıştırılmış nesne
akışlarının içinde bulunabilir (burada /FontFile* asla düz bayt olarak görünmez),
artımlı güncellemeler nesneleri ekleyebilir veya üzerine yazabilir, gömülü
olmayan veya standart-14 yazı tipleri haklı olarak hiçbir yazı tipi programı
taşımaz ve serileştirme farklılıkları (nesne sıralaması, boşluk, ad kodlaması)
belirteci taşıyabilir veya gizleyebilir. En iyi durumda bir yüzeyin bir program
gömdüğünü onaylar — istediğiniz belirli yüzeyin çözümlendiğini asla.
Gerçek bir dağıtım kapısı için bayt aramasına güvenmeyin. Yayılan PDF’i uygun bir
PDF ayrıştırıcısı veya nesne denetçisiyle ayrıştırın ve hedef yüzeyiniz için yazı
tipi nesnesinin gömülü bir /FontFile//FontFile2//FontFile3 programı taşıdığını
ileri sürün ya da tümleştirmenize uygunsa ürünün sağladığı bir yazı tipi çözümleme
ifadesini kullanın. Yukarıdaki belirteç farkındalıklı düzenli ifadeler hızlı bir
yerel akıl sağlığı denetimi için yararlıdır, ancak dağıtımı başarısız kılması
gereken şey yapısal bir incelemedir. Gömme ve yazı tipi sözlüğü yapısı
Bir TrueType yazı tipini gömün ve alt küme oluşturun
sayfasında tarif edilmiştir.
Sınır durumları ve püf noktaları
“Sınır durumları ve püf noktaları” başlıklı bölümcreateStandalone()’un kendi kayıt defteri vardır. Ayrı birFontRegistryüzerinde kaydedilen bir yüzey, bağımsız bir belgeye görünmez. Kayıt defterinizin etkin olanı olması içinDocumentFactory(veya çerçeve fabrikası) kullanın.- Stil dosyaları, dosya olarak var olmalıdır. Motor, normal bir yüzeyden kalın
veya italik sentezlemez.
setFont('DejaVuSans', 'B')çağırırsanız, dizin aramasıDejaVuSans-B.ttf,DejaVuSansB.ttfveyaDejaVuSans.ttf(küçük harf ve.otfvaryantları da) arar — adayı sözcük anlamıylaBstil kodundan oluşturur, dolayısıyla aslaDejaVuSans-Bold.ttfaramaz.DejaVuSans-Bold.ttfgibi yazılı bir ada sahip bir dosya yalnızca onuregister()ile açıkça kaydettiğinizde çözümlenir; bu da onu dosya adından bağımsız olarak dosyanın kendi ad tablolarından okunan aileye ve stile göre dizinler; onu bulması için dizin aramasına güvenmek bir ıskaya yol açar, ardından motor bir temel yazı tipine geri düşebilir (garantili veya her zaman sessiz olmayan bir yol) — bu sayfanın uyardığı bozulma. - Akış sarmalayıcı ve uzak yollar reddedilir. Kayıt defteri, bir URI şeması ya
da bir null bayt içeren yolları reddeder. Yalnızca yerel dosyaları kaydedin;
çalışma zamanında getirilen yazı tipleri için ham baytlarla
registerFromBinary()kullanın. - Kilitli kayıt defteri değişmezdir.
lock()çağırdığınızda, sonraki herhangi birregister(),addFontDirectory()veyawarmup()fırlatır. Arama yöntemleri kullanılabilir kalır. Kilitlemeden önce her şeyi kaydedin ve ısıtın. - CJK koleksiyonları büyüktür. Bir
.ttc’nin doğru alt yazı tipini$fontIndexile kaydedin ve daha büyük bir gömülü alt küme için bütçe ayırın. embed-and-subset tarifindeki CJK notlarına bakın.
Güvenlik notları
“Güvenlik notları” başlıklı bölüm- Bir yazı tipi dosyası, güvenilmeyen ikili girdidir. Yalnızca güvendiğiniz kaynaklardan yazı tiplerini paketleyin ve son kullanıcılardan kabul edilen herhangi bir yüzeyin kökenini doğrulayın.
- Isıtmadan sonra kayıt defterini kilitlemek, bir çalışma zamanı mutasyon yüzeyini kaldırır ve bir yol hatasının çıktıyı sessizce bozmak yerine başlatmada başarısız olmasını sağlar.
- Kullanıcı girdisini kaydedilmiş bir dosya yoluna eklemeyin. Paketlenmiş sabit bir yüzey kümesini kaydedin; bir isteğin keyfi bir dosya sistemi yolu seçmesine izin vermeyin.
Uyumluluk
“Uyumluluk” başlıklı bölümBu kılavuz normatif bir standart iddiasında bulunmaz. Gösterilen her sembol
doğrulanmış genel yüzeydir: NextPDF\Typography\FontRegistry (register(),
addFontDirectory(), warmup(), lock(), dizin yapıcı argümanı), onun
NextPDF\Contracts\FontRegistryInterface sözleşmesi,
NextPDF\Core\DocumentFactory::create() ve NextPDF\Core\Document::setFont()
/ addFontDirectory(). Laravel fonts_path ve preload_fonts anahtarları,
nextpdf/laravel paketinin belgelenmiş yapılandırmasıdır. Gömme ve alt küme
etiketi davranışı, ISO 32000-2 alıntılarıyla birlikte, Ayrıca bakınız altında
bağlantısı verilen embed-and-subset tarifinde belgelenmiştir.
Ayrıca bakınız
“Ayrıca bakınız” başlıklı bölüm- Bir TrueType yazı tipini gömün ve alt küme oluşturun: tek bir yüzeyi kaydetmenin ve kaydetmede otomatik alt küme oluşturmanın API düzeyindeki tarifi.
- HTML’i bir PDF sayfasına işleyin: aynı kayıt defteri aracılığıyla yazı tiplerini çözümleyen yerel HTML yolu.
- Bir denetleyiciden üretilen bir PDF döndürün: fabrika ile oluşturulmuş bir belgeyi bir çerçeve yanıtına bağlayın.
- Laravel üretim kullanımı: çerçeve yazı tipi yapılandırması ve çalışan başlatma ısıtması.