Teknik Makale

Delphi'de HotPDF ile PDF Sayfalarını Bit Eşlemine Dönüştürme

HotPDF, yüklü bir PDF sayfasını tek bir çağrıyla Delphi TBitmap'ine dönüştürür: RenderLoadedPageToBitmap(PageIndex, DPI). Bu işlev, sayfanın içerik akışını yorumlar ve seçtiğiniz çözünürlükte, çağıranın sahipliğinde 24 bitlik bir RGB bit eşlemi döndürür; bu, bir küçük resim şeridinin, bir baskı önizlemesinin veya bir PDF'ten resme dışa aktarım süreç hattının tam olarak ihtiyaç duyduğu şeydir. Bu makale API'yi ve ardından kullanılabilir bir işleyiciyi bir oyuncaktan ayıran kısmı (benzer sistem yazı tipleri yerine gömülü yazı tipi programlarının kendilerinden metin çizmeyi) incelemektedir

Bir PDF sayfasını işlemek neden bir resim çizmekten daha zordur?

Bir PDF sayfası bir resim değildir. O bir programdır: ISO 32000-1 §8'de tanımlanan grafik modeline karşı yürütülen yollar oluşturan, yazı tiplerini seçen, renkleri ayarlayan ve glifleri yerleştiren bir operatör akışıdır. Dosyada hiçbir şey herhangi bir pikselin neye benzediğini söylemez. Bir bit eşlemi üretmek için o programı çalıştırmanız (mevcut bir dönüşüm matrisini, q/Q için bir grafik durumu yığınını, bir kırpma yolunu, dolgu ve vuruş renk alanlarını korumanız) ve sonucu rasterleştirmeniz gerekir. Bu nedenle "sadece sayfa 3'ü resim olarak göster", bir dosya biçimi dönüştürme işlemi değil, bir içerik akışı yorumlayıcısıdır

HotPDF'in v2.253.0'da tanıtılan işleyicisi, bu modeli yansıtan altı bağımsız birim olarak oluşturulmuştur: PDF [a b c d e f] dönüşüm cebri için bir afin matris çekirdeği, bir grafik durumu yığını, bir renk alanı çözümleyicisi (DeviceRGB, DeviceGray, DeviceCMYK, Indexed), PDF yol operatörlerini GDI'ya köprüleyen bir yol oluşturucu, doğru ilerlemeler için /Widths dizilerini okuyan bir yazı tipi metrikleri katmanı ve operatörleri dağıtan ve diğer beşini yönlendiren yorumlayıcı. Resim XObject'leri, kütüphanenin çıkarma (extraction) için kullandığı kod çözme yığınının aynısından geçer, bu nedenle HotPDF'in çıkarma için kodunu çözebileceği her resim filtresi (buna JPXDecode sıkıştırmalı JPEG 2000 resimleri de dahildir) işlenen çıktıda da görünür

Yüklü bir sayfayı TBitmap'e dönüştürme

RenderLoadedPageToBitmap, sıfır tabanlı bir sayfa dizini ve bir DPI değeri alır; burada 72 DPI, bir PDF kullanıcı alanı birimini bir piksele eşler. Hata durumunda (aralık dışı dizin, eksik kaynaklar) istisna oluşturmak yerine nil döndürür, böylece görüntüleyici bozuk bir sayfayı atlayıp devam edebilir. Çağıran, döndürülen bit eşlemine sahiptir ve onu serbest bırakmalıdır (free)

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('report.pdf') > 0 then
    begin
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 144);  // 144 DPI'da Sayfa 1
      if Bmp <> nil then
      try
        Image1.Picture.Assign(Bmp);
      finally
        Bmp.Free;  // bit eşleminin sahibi çağırandır
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

DPI bağımsız değişkeni, her yaygın senaryo için ölçeklendirme işini yapar. Bir küçük resim şeridi 36 veya 48 DPI'da işlenir ve küçük, hızlı bit eşlemleri elde eder; 96 veya 144 DPI'lık bir ekran preview'u tipik ekran yoğunluğuyla eşleşir; 300 DPI'lık bir dışa aktarma yolu baskı kalitesinde resimler üretir. /Rotate girişinden gelen sayfa döndürme ve /MediaBox orijin çevirme (PDF orijini sol alta, GDI sol üste yerleştirir) sayfadan cihaza matrisi içinde işlenir, bu nedenle 72 DPI'da bir US Letter sayfası tam olarak 612×792 piksel olarak doğru yönde geri döner

İşlenen PDF küçük resimleri neden yanlış glifler gösteriyor?

İşlenen PDF çıktısındaki yanlış veya yaklaşık glifler, neredeyse her zaman işleyicinin dosyadaki gömülü yazı tipini kullanmak yerine bir sistem yazı tipini ikame ettiği anlamına gelir. İlk HotPDF işleyicisi tam olarak bunu yapıyordu: Alt küme önekini /BaseFont'tan soyuyor (ABCDEF+Arial'i Arial'e dönüştürüyor), GDI'dan bu adda bir sistem yazı tipi istiyor ve metni onunla çiziyordu. Standart kodlamalı Arial veya Times New Roman kullanan bir belge için sonuç yakın görünür. Ancak bu bir yaklaşımdır ve belirgin durumlarda bozulur

Alt küme (subset) gömülü yazı tipleri en kötü durumdur. Bir alt küme yazı tipi, yalnızca belgenin fiilen kullandığı kırk glifi taşıyabilir ve karakter kodları o dosyaya özel bir sırayla atanabilir; örneğin kod 1 "T", kod 2 "h" olabilir. Bir sistem yazı tipi bu özel atama hakkında hiçbir şey bilmez, bu nedenle metin ya kaybolur ya da tamamen yanlış karakterler olarak çıkar. Özel kodlamalar, sembol yazı tipleri, barkod yazı tipleri ve işleme makinesinde yüklü olmayan herhangi bir yazı tipi aynı şekilde başarısız olur. Sistem yazı tipi ikamesiyle sınırlı kalan bir işleyici, sayfanın tanınabilir küçük resimlerini üretir; ta ki sayfa, gömmeyi en başta gerekli kılan yazı tiplerini kullanana kadar

Gömülü glif işleme: Yazı tipi programının kendisinden çizim yapma

HotPDF, gömülü yazı tipi programlarını ayrıştırarak ve glif anahatlarını içi dolu GDI vektör yolları olarak yeniden oynatarak beş sürümde (v2.268.0 ila v2.272.0 arası) bu boşluğu kapattı. İşlenen bir sayfadaki metin artık uyumlu bir görüntüleyicinin kullandığı anahat verilerinden gelir; bu da alt küme yazı tiplerinin, özel kodlamaların ve yüklü olmayan yazı tiplerinin tam şekilleriyle işlenmesi anlamına gelir. Kapsam, yazı tipi türlerine göre oluşturulmuştur:

Gömülü TrueType programına (FontFile2) sahip Type0/CIDFontType2 yazı tipleri için işleyici, glyf ve loca tablolarını doğrudan ayrıştırır: İkinci dereceden konturlar, GDI'nin anladığı üçüncü dereceden Bézier'ler inde dönüştürülür, ardışık eğri dışı noktalar arasındaki zımni eğri üzerindeki noktalar yeniden oluşturulur ve bileşik glifler özyinelemeli olarak yeniden oynatılır. Hem Identity hem de açık akış CIDToGIDMap düzenleri desteklenir ve CID ilerlemeleri /W ve /DW genişlik girişlerini onurlandırır, böylece iki baytlık Identity-H metin adımları doğru şekilde çalışır

CFF programları (FontFile3, ister CIDFontType0C, Type1C ister bir OpenType sarmalayıcısı olsun) tam bir Type 2 karakter dizgesi yorumlayıcısı elde eder: Çizgiler, eğriler, esnek (flex) ailesi, ipucu maskeleri ve doğru alt program sapmasıyla yerel/küresel alt program çağrıları. CID anahtarlı CFF programları, glif sırası CID sırasından farklı olan alt küme yazı tipleri için önemli olan yazı tipinin karakter seti aracılığıyla karakter kodlarını eşler ve FDArray/FDSelect aracılığıyla glif başına font-DICT seçimi onurlandırılır. Basit (non-CID) TrueType yazı tipleri, tek baytlık kodları gömülü yazı tipinin kendi cmap tablosu aracılığıyla sağlam bir alt tablo zinciriyle çözümler (önce Unicode biçimleri 4 ve 12, ardından F000 özel kullanım yansıtmalı sembol alt tabloları, ardından eski Macintosh biçimleri), basit Type1 yazı tipleri ise CFF programının yerleşik kodlaması aracılığıyla çözümlenir

İki ince ayar resmi tamamlar. İlk olarak, basit yazı tipi /Encoding sözlükleri, ISO 32000-1 §9.6.6'nın öngördüğü önceliğe göre çözümlenir: /Differences dizileri, yazı tipi programının kendi haritasını geçersiz kılan temel kodlamayı geçersiz kılar; bu, TeX ve PostScript türevi araç zincirlerinin dayandığı yoldur; glif adları Adobe Glyph List, CFF karakter seti veya TrueType cmap aracılığıyla çözümlenir. İkinci olarak, glifleri kendi başlarına küçük içerik akışları olan Type3 yazı tipleri, yazı tipi matrisi, yazı tipi boyutu ve metin matrisi birleştirilmiş olarak işleyici aracılığıyla yeniden oynatılır; glif alanı /Widths değerleri, ISO 32000-1 §9.6.5'in gerektirdiği şekilde /FontMatrix aracılığıyla yorumlanır ve d1 sınırlayıcı kutusu beyan eden glif prosedürleri buna kırpılır, böylece hatalı biçimlendirilmiş bir barkod glifi hücresinin dışına boyayamaz. Bir kod eşlenemediğinde (hasarlı bir program, eşlenmemiş bir karakter), işleyici o metin çalışmasını bırakmak yerine o glif için sistem yazı tipi çizimine geri döner

Tekrarlanan işlemeleri nasıl hızlı yaparsınız?

HotPDF'in gönderdiği yanıt, en son kullanılan sayfa önbelleğidir: RenderLoadedPageToBitmapCached, sayfa dizini ve DPI değerine göre anahtarlanmış RenderCacheCapacity adede kadar işlenmiş sayfayı (varsayılan 8) tutar ve önbellek isabeti, içerik akışına dokunmadan çağıranın sahipliğinde yeni bir kopya döndürür; bu, genellikle sayfanın yeniden yorumlanmasından binlerce kat daha hızlıdır. Bu model, görüntüleyicilere tam olarak uyar: İki sayfa arasında geçiş yapan bir kullanıcı veya aynı sayfayı aynı DPI'da yeniden talep eden bir yeniden boyutlandırma olayı, her seferinde önbelleğe isabet eder

// Küçük resim şeridi: ilk geçiş işlenir, geri kaydırma önbelleğe isabet eder
for I := 0 to ThumbCount - 1 do
begin
  Bmp := Pdf.RenderLoadedPageToBitmapCached(I, 48);
  if Bmp <> nil then
  try
    ThumbList.AddThumbnail(I, Bmp);
  finally
    Bmp.Free;
  end;
end;

// Yüklü bir sayfayı yerinde düzenledikten sonra:
Pdf.InvalidateRenderedPageCache;  // bir sonraki işleme değişikliği yansıtır

Kapasiteyi artırmadan önce bellek maliyeti konusunda dürüst olun. 300 DPI'lık bir US Letter sayfası 2550×3300 pikseldir ve 24 bitlik bir bit eşlem olarak yaklaşık 25 MB tutar, bu nedenle dışa aktarma çözünürlüğünde önbelleğe alınmış sekiz sayfa kabaca 200 MB yer kaplar. Küçük resim DPI'ında aynı sekiz giriş bir megabaytın çok altındadır. RenderCacheCapacity değerini gerçekten önbelleğe aldığınız DPI'a göre boyutlandırın ve yerinde düzenlemeden sonra InvalidateRenderedPageCache çağrısı yapın; önbellek yalnızca sayfa ve DPI ile anahtarlanır ve altındaki içeriğin değiştiğini göremez. Yeni bir belge yüklemek bunu otomatik olarak temizler

Sayfa önbelleğinin altında ikinci bir önbellek çalışır: Kodu çözülmüş resim XObject'leri, en son kullanılanlerin çıkarıldığı ImageCacheMaxBytes (varsayılan 32 MB) ile sınırlandırılmış bayt bütçeli bir depoda tutulur. Her sayfada tekrarlanan bir logo veya antetli kağıt resmi, her Do operatörü için bir kez yerine belge yüklemesi başına bir kez çözülür; bu, paylaşılan resimli sayfalar için işleme süresini kabaca yarıya indirir ve çok sayfalı TIFF dışa aktarımını aynı ölçüde hızlandırır. InvalidateRenderedPageCache bu önbelleği de temizler

Hala yaklaşık olarak işlenen şeyler

İşleyici, yaygın belge-PDF alt kümesini hedefler ve sınırların nerede olduğunu bilmek değerlidir. CalRGB, Lab ve ICC tabanlı renk alanları renk yönetimi yapılmak yerine yaklaşılarak hesaplanır; cihaz renk alanları, Indexed paletleri ve örneklenmiş Type 0 işlevi renk aramaları işlenir ancak ICC işleme amaçlarına dayanan bir baskı üretim dosyası renk ölçümü açısından tam olarak doğru olmayacaktır. Gölgeleme desenleri (sh) ve basit alfanın ötesindeki karışım (blend) modları da aynı şekilde kapsam dışıdır ve Form XObject özyinelemesi bir döngü koruması olarak derinlik sınırlıdır. Metin, yollar ve resimlerden oluşan sayfalar (faturalar, raporlar, sözleşmeler ve formlar) için çıktı sadıktır; gradyanlar ve şeffaflık gruplarıyla dolu bir tasarım provası için bit eşlemini prova olarak değil, önizleme olarak ele alın

Pratik okuma: Süreç hattınız HotPDF ile belgeler üretiyorsa veya tipik iş PDF'lerini tüketiyorsa, RenderLoadedPageToBitmap bunları tam gömülü glif şekilleri, doğru CID ilerlemeleri ve doğru sayfa geometrisi ile gidiş-dönüş yaptırır. Yaklaşık hesaplamalar, iş belgelerinin nadiren ziyaret ettiği grafik modelinin köşelerinde yaşar

RenderLoadedPageToBitmap, önbelleğe alınmış varyantı ve burada açıklanan gömülü glif işleme süreç hattı; PDF oluşturma, düzenleme, metin çıkarma ve sayfa işlemeyi tek bir pakette kapsayan, harici DLL bağımlılığı olmayan yerel bir VCL kütüphanesi olan Delphi ve C++Builder için HotPDF Bileşeni'nin bir parçası olarak gönderilir