Teknik Makale

Delphi'den PDF'de CID Type 2 Yazı Tiplerini Gömme

PDFium Component, AddCidType2Text ile bir PDF sayfasına glif düzeyinde metin yazar ve sizin sağladığınız TrueType verisini bir CID Type 2 yazı tipi olarak gömer. Her glif örneğine sıralı bir CID atar, açık CID-ile-GID eşlemini ve ToUnicode CMap'ini üretir ve aynı taban çizgisindeki glifleri tek bir yerel metin nesnesinde birleştirir. İsteğe bağlı alt kümeleme dosyayı küçük tutar; alt kümeleme başarısız olduğunda ne olacağına dair açık bir politikayla birlikte

Glif düzeyinde yazma, metin zaten şekillendirilmişse ihtiyacınız olan şeydir. Arapça, Devanagari ve bağlamsal biçimlere sahip her yazı sistemi, artık karakterlere birebir eşlenmeyen bir glif tanımlayıcıları dizisi üretir, bu yüzden bir dize ve bir yazı tipi adı alan bir API sonucu ifade edemez. Glifleri ve konumları doğrudan teslim etmek, doğru şekillendirilmiş karmaşık yazı sistemi metnini bir PDF'e koymanın tek yoludur

Delphi'de AddCidType2Text, her biçimlendirilmiş glif örneğine sıralı bir CID atar, CIDToGIDMap ve ToUnicode CMap'i yazar ve diziyi temiz ayıklanan tek bir sayfa metin nesnesine harmanlar
Her glif örneği kendi CID'sini alır; yazı tipi sözlüğü CID'leri glif kimliklerine ve oradan Unicode'a eşler ve dizi, amaçlanan metne geri çıkarılan tek bir metin nesnesi olarak sayfaya düşer

Her Glif Örneği Neden Kendi CID'sini Alır

Cazip optimizasyon, yinelenenleri kaldırmaktır: farklı bir glif tanımlayıcısı başına bir CID, o glif nerede görünürse görünsün yeniden kullanılır. Bu, daha küçük bir yazı tipi üretir ve metin çıkarmayı bozar, çünkü aynı glif, farklı yerlerde meşru olarak farklı Unicode içeriğine karşılık gelebilir

Bir ligatür glifi bariz bir örnektir. Aynı "ffi" glifi, bir kelimedeki üç karakteri temsil edebilirken başka bir yerdeki farklı bir şekillendirme kararından sonra başka bir şeyi temsil edebilir. ToUnicode eşlemi CID'ye göre anahtarlanır, bu yüzden paylaşılan bir CID yalnızca bir eşleme taşıyabilir ve bu yarışmayı kaybeden metin çıkarılamaz hale gelir

Bu yüzden her glif örneği kendi CID'sini alır ve her eşleme birkaç UTF-16 kod birimi olmakta serbesttir. Anlamlı metni olmayan bir glif — dekoratif bir öğe, yalnızca konumlandırma amaçlı bir glif — açıkça sıfır genişlikli bir boşluk olan U+200B'ye eşlenir, bu yüzden her CID bir boşluk yerine gözlemlenebilir bir çıkarma sonucuna sahiptir

uses
  PDFium;

var
  Pdf: TPdf;
  Glyphs: TPdfCidGlyphs;
  Options: TPdfCidFontOptions;
  Report: TPdfCidFontReport;
begin
  Pdf := TPdf.Create(nil);
  try
    Pdf.FileName := 'label.pdf';
    Pdf.LoadDocument;
    Pdf.PageNumber := 1;

    // Şekillendirilmiş her glif için bir girdi: glif kimliği, temsil ettiği metin,
    // ve metin uzayındaki ilerlemesi ve ofsetleri
    SetLength(Glyphs, 3);
    Glyphs[0].GlyphID := 402;  Glyphs[0].UnicodeText := 'ffi';
    Glyphs[0].Advance := 18.4;
    Glyphs[1].GlyphID := 71;  Glyphs[1].UnicodeText := 'c';
    Glyphs[1].Advance := 9.8;
    Glyphs[2].GlyphID := 74;   Glyphs[2].UnicodeText := 'e';
    Glyphs[2].Advance := 9.2;

    Options := TPdfCidFontOptions.Default;   // alt küme tercih edilir
    Options.VerifyExtraction := True;

    if Pdf.AddCidType2Text(LoadFileBytes('NotoSans.ttf'), Glyphs,
         11, 72, 700, Options, Report) then
      Writeln(Format('%d glyphs, %d unique, font %d -> %d bytes, match=%s',
        [Report.GlyphCount, Report.UniqueGlyphCount,
         Report.OriginalFontBytes, Report.EmbeddedFontBytes,
         BoolToStr(Report.ExtractionMatches, True)]));
  finally
    Pdf.Free;
  end;
end;

Alt Kümeleme ve Bir Dönüş Kodunun Size Vermediği Kontroller

Bir yazı tipini gerçekte kullanılan gliflere alt kümelemek, 300 KB gömmek ile 12 KB gömmek arasındaki farktır ve birkaç yazı tipine sahip bir belgede bu, dosyanın e-postayla gönderilebilir olup olmadığını belirler. Platform alt kümeleme yolu doğrudan bir glif listesi kabul eder; bu, çağıran zaten kullanımdaki her glif tanımlayıcısını bildiği için bu API'ye mükemmel şekilde uyar

Size vermediği şey güvendir. Bir alt kümeleme çağrısı başarı bildirebilir ve kullanılamaz bir çıktı döndürebilir, bu yüzden bileşen sonucu kabul etmeden önce üç özelliği doğrular: çıktı özgününden küçük olmalıdır, okunabilir bir maxp tablosuna sahip geçerli bir sfnt olarak yeniden ayrıştırılmalıdır ve istenen en yüksek özgün tanımlayıcıya kadar glifleri korumalıdır. Herhangi bir başarısızlık, alt kümenin reddedildiği anlamına gelir

Bundan sonra ne olacağı çağıranın politikasıdır. Varsayılan olan pcfemSubsetPreferred altında, reddedilen bir alt küme tam yazı tipini gömmeye geri döner, bu yüzden sayfa doğrudur ve yalnızca daha büyüktür. pcfemSubsetRequired altında ise, sayfa değiştirilmeden önce işlem başarısız olur; bu, boyut kısıtlı bir boru hattının istediği şeydir. pcfemFull, alt kümelemeyi tamamen atlar. Rapor, SubsetAttempted, SubsetApplied, UsedFullFontFallback ve SubsetErrorCode aracılığıyla hangi yolun izlendiğini söyler

Delphi'de CID Type 2 yazı tipi alt kümeleme, kabulden önce boyut, sfnt bütünlüğü ve glif kapsamı için üç doğrulama kontrolünden geçer ve reddedilen bir alt küme, tam yazı tipi yedeği veya sert başarısızlık pcfem politikasını izler
Bir alt küme yalnızca boyut, sfnt ve glif kapsamı kontrolleri geçtikten sonra kabul edilir; reddedilen alt küme ise çağıran politikasını izler — tam yazı tipine dön ya da sayfa değiştirilmeden önce başarısız ol

Yanlış Pozitif Üretemeyen Doğrulama

VerifyExtraction etkinleştirildiğinde bileşen, yazdığı şeyin geri okunabildiğini doğrular. Bunu yapmanın naif yolu tüm sayfayı çıkarmak ve beklenen dizeyi aramaktır ve bu yanlıştır: zaten o metni içeren bir sayfa, yeni metin yanlış yazılmış olsa bile kontrolü geçer

Bunun yerine metin sayfası yeniden oluşturulur ve bu çağrı tarafından eklenen nesne tanıtıcıları tek tek, ekleme sırasına göre okunur ve birleştirilir. Sonuç, beklenen metinle karşılaştırılır ve rapor, boolean ile birlikte her iki dizeyi de gösterir, bu yüzden bir uyumsuzluk yalnızca tespit edilmekle kalmaz teşhis de edilebilir

Geliştirme sırasında ve çıkarılabilirliğin bir gereksinim olduğu her boru hattında etkinleştirin — aranabilir arşivler, erişilebilirlik uyumluluğu, sonraki metin madenciliği. Maliyeti, çağrı başına bir metin sayfası yeniden oluşturmadır; sıkı döngülerde varsayılan olarak açık olmamasının nedeni budur

Bütçeler ve Atomik Başarısızlık

Yazı tipi baytları, glif örnekleri ve Unicode kod birimlerinin her biri ayırmadan önce üst sınırlandırılır ve yazı tipi biçimi, TTC indeksi, glif tanımlayıcı aralığı ve geometri değerleri bir şey yazılmadan önce doğrulanır. Geometri sonlu olmalıdır; bu, bir şekillendirme motoru size bozuk bir yazı tipinden bir NaN ilerlemesi verene kadar bariz görünür

Başarısızlık sayfa düzeyinde atomiktir. Yazı tipi yükleme, nesne yazma, içerik üretme veya çıkarma doğrulaması başarısız olursa, o çağrının eklediği her nesne ters sırada kaldırılır ve sayfa içeriği yeniden üretilir. Başarısız bir çağrı sayfayı üzerinde yarım bir metin dizisiyle değil, olduğu gibi bırakır

Bunun Bir Metin Boru Hattında Nereye Oturduğu

İş bölümünü açıkça belirtmeye değer. Şekillendirme — karakterleri konumlandırılmış gliflere dönüştürmek — bu API'nin işi değildir; bir şekillendirme motoruna aittir ve bileşenin kendi çift yönlü ve karmaşık yazı sistemi desteği, emoji, CJK ve vekil çift işleme başlığında ele alınmıştır. Bu API, şekillendiricinin ürettiği glif dizisiyle sonrasında çağırdığınız şeydir

Bağlamsal şekillendirme gerektirmeyen sıradan Latin metin için daha basit dize tabanlı metin API'leri doğru araçtır ve daha küçük kod üretir. Şekillendirilmiş çıktınız olduğunda, glif tanımlayıcıları üzerinde tam denetime ihtiyaç duyduğunuzda veya yazı tipi ada göre çözümlenmek yerine elinizdeki baytlardan gömülmesi gerektiğinde CID Type 2 yazımına başvurun — yazı tipi çözümleme alternatifi, PDF yazı tipi ikamesini denetleme başlığında anlatılan sağlayıcı mekanizmasıdır

Bir dağıtım notu: bir yazı tipini gömmek, teknik olduğu kadar bir lisanslama sorusudur da. Yazı tipleri, gömmeye hiç izin verilip verilmediği, yalnızca görüntüleme için izin verildiği veya düzenleme için izin verildiği bakımından farklılık gösterir. Kitaplık, kendisine verdiğiniz her ne baytsa gömer ve lisansı kontrol etmek dosya biçiminin değil sizin sorumluluğunuzdadır

Glif düzeyinde metin yazma, yazı tipi sağlama ve metin çıkarma, Delphi, C++Builder ve Lazarus'ta aynı sayfa modelini paylaşır; tam API, Delphi için PDFium Component sayfasında açıklanmıştır