· kaynak dev.to (home feed)
pdf-lib'un standart fontları WinAnsi olmayan isimleri kodlayamıyor, yaygın temizleme düzeltmesi de bunları sessizce siliyor
dev.to'da yayımlanan bir yazı, pdf-lib'un yerleşik fontlarının Ł ve ź gibi WinAnsi dışı karakterlerde nasıl başarısız kaldığını ve çizmeden önce bu karakterleri silmek şeklindeki yaygın düzeltmenin üretilen PDF'lerdeki kullanıcı verisini sessizce nasıl bozduğunu anlatıyor.

Bir müşterinin adı iki harfini nasıl kaybetti
dev.to'da yazan bir geliştirici, PDF üretmek için yaygın olarak kullanılan Node.js kütüphanesi pdf-lib'taki bir veri bozulması tuzağını belgeledi. Sunucusuz (serverless) bir fonksiyonda fatura üretirken yazar, Łódź Sp. z o.o. olan bir müşterinin şirket adının bitmiş faturada ód Sp. z o.o. olarak göründüğünü fark etti. Ł ve ź yok olmuştu. PDF yapısal olarak geçerliydi, her okuyucuda sorunsuz açılıyordu ve hiçbir log çıktısı üretmiyordu — bunu yakalamanın tek yolu işlenmiş sayfaya bakmaktı.
Standart fontlar Batı Avrupa Latin alfabesinde kalıyor
Uyumlu her PDF okuyucusu on dört standart fontu desteklemek garanti edilir; bu yüzden pdf-lib öğreticileri neredeyse her zaman embedFont(StandardFonts.Helvetica) gibi bir şeyle başlar: gönderilecek font dosyası yok, düşünülecek lisans yok. Yazıya göre bu fontlar WinAnsi — yaklaşık Windows-1252 — ile kodlanıyor ve glif kümeleri Batı Avrupa Latin alfabesini kapsıyor, ötesini hiç.
Yazar sınırın nerede olduğunu varsaymak yerine denedi. Euro işareti, tipografik tırnak işaretleri ve tireler sorunsuz çiziliyor — geliştiricilerin endişelendiği aralık tam da bu. Çekçe ř, Türkçe noktasız ı, Kiril metni ve CJK karakterlerinin hepsi başarısız oluyor. Başka bir deyişle, gerçek isimlerde, adreslerde ve şirket tescillerinde görünen karakterler tam olarak kümenin dışında kalanlar.
Veriyi bozan geçici çözüm
Dokunulmadığında pdf-lib düzgün davranıyor: standart bir fontla Ł çizmeye çalışmak, WinAnsi'nin bu karakteri kodlayamadığını belirten açık bir hata fırlatıyor. Asıl tehlike bu çöküşe verilen bariz tepki. Yazar — daha önce birçok geliştirici gibi — metin drawText'e ulaşmadan önce temel Latin-1 aralığı dışındaki tüm karakterleri silen bir regex ekledi. İstisna kayboluyor, test paketi yeşile dönüyor ve kod, üçüncü bir tarafa gidecek bir belgeden kullanıcı verisi parçalarını silmeye devam ediyor.
O noktada fark edilecek hiçbir şey yok. PDF geçerli, loglar sessiz ve string karşılaştıran birim testleri, yalnızca işlenmiş çıktıda var olan bir kusuru göremiyor.
Gerçek bir font gömmek
Yazının açıkladığına göre doğru çözüm, @pdf-lib/fontkit aracılığıyla bir TrueType veya OpenType font gömmek; bu, 1990'lardan kalma bir kodlama tablosuna bağımlılığı ortadan kaldırıyor. Yanında birkaç pratik not da var:
registerFontkitzorunlu; onu çağırmadan ham font baytları üzerindeembedFontçağırmak, altta yatan sorunla bağlantısı bariz olmayan bir hata fırlatıyor.- Alt kümeleme (subsetting) umulandan daha önemli. Archivo yazı tipinin tam bir ağırlığı yaklaşık 180 KB; bu yüzden alt kümelenmemiş üç ağırlık gömmek her belgeye yaklaşık yarım megabayt ekler.
subset: trueile yazarın üç ağırlık taşıyan dört sayfalık faturası 35 KB çıktı, çünkü yalnızca gerçekten kullanılan glifler gömülüyor. - Font baytları bir kez okunup modül düzeyinde bir değişkende önbelleğe alınmalı, böylece ısınmış serverless çağrıları her seferinde dosya okuma maliyeti ödemez.
- Bir yazı tipini projeye dahil etmeden önce lisansları kontrol etmek gerekir. Archivo, gömmeye izin veren SIL Open Font License altında; birçok ticari font ise izin vermiyor.
Kapsam hâlâ garanti değil
Gömme, kodlama sorununu çözüyor ama kapsamı çözmüyor. Archivo hiç CJK glifi içermiyor, bu yüzden Japonca bir şirket adı hâlâ widthOfTextAtSize'da hata fırlatıyor. Yazarın tavsiyesi bir yedek bulundurmak ama görünür kılması: çizilemeyen bir karakteri silmek yerine boşlukla değiştirmek, böylece belgeyi prova eden bir insan boşluğu fark etme şansı buluyor.
Yalnızca render'ın ortaya çıkardığı hatalar
Çıktıya zaten yönlendirilmiş bir rasterleştiriciyle yazar, ne kadar kod okunursa okunsun ortaya çıkmayacak iki yerleşim kusuru buldu. Dört haneye göre boyutlandırılmış bir sütunda 20pt ile sağa hizalanmış altı haneli bir toplam, kendi "TOTAL DUE" etiketinin üzerine geri doğru taştı. Ayrı olarak, uzun bir şirket adı sayfanın sağ kenarından dümdüz ilerledi. drawText metni mutlak koordinatlarda konumlandırır ve container kavramı yoktur; bu yüzden metin ne sarılır ne uyarır — sadece çizer.
Tavsiye, test döngüsüne bir rasterleştirme adımı eklemek — yazıda sistem bağımlılığı gerektirmeyen PyMuPDF kullanılıyor — ve ardından ortaya çıkan görüntüyü gerçekten açmak. Yazar bunu bu sınıf hataları yakalayan tek test olarak nitelendiriyor.
Neden önemli
pdf-lib, Node'da fatura, makbuz ve bilet üretimi için varsayılan bir seçim ve bu belgeler rutin olarak kullanıcıların kendilerinin yazdığı metinden oluşturuluyor. Bu metinlerin herhangi biri WinAnsi ötesi karakterler içerebilir ve iki başarısızlık modu da kötü: üretimde sert bir istisna, ya da — popüler karakterleri-sil düzeltmesinden sonra — markanız altında çıkan bir belgede müşteri adının sessizce bozulması. Savunmalar ucuz: fontkit ile alt kümelenmiş bir font gömmek, çizilemeyen karakterler için görünür yer tutucular koymak ve temsili çıktıyı CI'da görüntüye dönüştürmek. Faturanın ürünün kendisi olduğu HourToBill adlı bir ürün geliştiren yazar, üreticinizin Łódź ile ne yaptığını kontrol etmek için yirmi dakika ayırmanızı öneriyor.
- #pdf-lib
- #node-js
- #unicode
- #javascript