Teknik Makale

HotPDF Görüntü Küçültme Çekirdekleri ve Baskı Dithering'i

HotPDF, üç imge küçültme çekirdeğini ImageDownsampleKernel özelliği üzerinden, ayrı bir Floyd-Steinberg geçişini ise RenderOutputDither üzerinden açar. İlki, boyut bütçesine oturmak için fotoğrafları küçülttükten sonraki görünümlerini kontrol eder; ikincisi, bir sayfa siyah beyaza indirildikten sonraki görünümlerini. İkisi de varsayılan olarak kapalıdır ve her ikisi de aynı nedenle opt-in'dir: gerçek zaman maliyetleri vardır

İnsanları buraya getiren baskı tanıdıktır. 60 MB'lık taranmış bir sözleşme, 10 MB üzerindeki her şeyi reddeden bir e-posta ağ geçidinden çıkmalıdır ya da bir hesap özeti kümesinin, her gri pikseli ya kağıt ya da toner olarak render eden faks tarzı bir monokrom cihaza düşmesi gerekir. İki sorun da yeniden örnekleme sorunudur ve ikisinin de kötü görünen hızlı bir cevabı, doğru görünen yavaş bir cevabı vardır

Üç çekirdeğin gerçekte ayrıştığı nokta

THPDFResampleKernel üç değer taşır ve bunlar hız-kalite eğrisinde gerçekten farklı noktalarda durur. rkHalftone, HALFTONE modlu tarihî GDI StretchBlt yoluna devreder; adına rağmen bu bilinear sınıfı bir filtredir: hızlıdır, çizgi sanatı ve ekran görüntüleri için yeterlidir ve küçültülmüş fotoğraflarda anında tanıdığınız pütürlü kenarlara yatkındır. rkBicubic ayrılabilir bir Catmull-Rom çekirdeği, rkLanczos3 ise üç loblu desteği olan ayrılabilir bir pencere sinc çalıştırır

Her iki ayrılabilir çekirdek de saf Pascal'da, önce yatay sonra dikey olmak üzere iki geçiş halinde, hedef piksel başına 6-12 tap ile çalışır. Bu, GDI yolundan kabaca bir mertebeye kadar yavaştır; rkHalftone'un varsayılan kalmasının nedeni de tam olarak budur. Binlerce sayfalık bir gece toplu işinde fark bir zamanlama kararıdır, tercih değil. Bir kullanıcının beklediği tekil bir belgede ise Lanczos3 neredeyse bedavadır ve gözle görülür biçimde daha iyidir

Üç HotPDF küçültme çekirdeğinin ağırlık eğrileri: rkHalftone desteği bir olan bilinear sınıfı GDI HALFTONE yoluna devreder, rkBicubic desteği iki olan ayrılabilir bir Catmull-Rom kübik çalıştırır, rkLanczos3 ise desteği üç olan pencere sinc çalıştırır; kabaca bir hız mertebesini gözle görülür biçimde daha iyi fotoğraflarla takas eder
Üç çekirdek değeri hız ve kalite eğrisinde gerçekten farklı noktalarda durur: bilinear sınıfı bir GDI yolu, bir Catmull-Rom kübik ve üç loblu pencere sinc; ayrılabilir çekirdekler ağırlıkları normalize eder, böylece hiçbir şey siyahın ya da beyazın ötesine çınlamaz

İki uygulama özelliği bilmeye değer; çünkü çıktının neyi yapıp yapamayacağını belirlerler. Kenarlar, sarmalama ya da sönme yerine kenar tekrarıyla kırpılır ve ağırlıklar hedef piksel başına normalize edilir. Bu ikisi birlikte, sonucun asla siyahın altına ya da beyazın üstüne çınlamadığı anlamına gelir; sert bir kenarın çevresindeki klasik Lanczos overshoot halo'su, kodlanan imgede kırpılmış artifact'ler olarak görünmez

var
  Pdf: THotPDF;
  Info: THPDFLoadedResourceOptimizationInfo;
  Changed: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('scanned-contract.pdf');
    Pdf.ImageDownsampleKernel := rkLanczos3;   // çağrıdan önce ayarlanır
    Changed := Pdf.DownsampleLoadedImages(150, 82, 4096, Info);
    if Changed > 0 then
    begin
      Writeln('resampled images: ', Info.DownsampledImageCount);
      Writeln('kept calibrated : ', Info.PreservedCalibratedImageCount);
      Pdf.SaveToFile('scanned-contract-150dpi.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Yukarıdaki 4096 değerindeki MinimumSavingsBytes argümanı, işlemin dürüst kalmasını sağlayan guard'dır. Halihazırda verimli sıkıştırılmış bir imgeyi yeniden kodlamak, orijinalden daha büyük bir akış üretebilir ve her imgeyi körlemesine değiştiren bir küçültücü, küçültmesi istenen dosyayı arada büyütür. Eşik şunu söyler: değişikliği en az bu kadar bayt tasarruf sağladığında uygula. PreservedCalibratedImageCount ise öteki muhafazakar kararı bildirir: yeniden örnekleme tehlikeye atacağı için kalibre renk alanı taşıyan imgeler dokunulmadan bırakılır

Yanlış bir polinom katsayısı neden bu kadar zor fark edilir?

Çünkü bozuk bir interpolasyon çekirdeği çökmez ya da istisna fırlatmaz; kimseye atfedilemeyen bir şekilde hafif yanlış görünen bir imge üretir. Catmull-Rom çekirdeği parça parça kübiktir ve iç içe Horner biçimindeki dış dalı ((-0.5t + 2.5)t - 4)t + 2'dir. O orta katsayıyı -4 yerine -5 yazın; işlev yine hesaplanır, hâlâ makul aralıkta sayılar döndürür ve hâlâ bir imge üretir

Hasar, 0 olması gereken W(1) değerinin -1 çıkması olarak görünür. Negatif ağırlıklar birikir, toplam sıfırda kırılır ve gözle görünen belirti, sol ucu simsiyah olan bir gradyan ile ara tonlarını kaybeden bir basamak kenarıdır. Hatada polinoma işaret eden hiçbir şey yoktur. Saniyeler içinde yakalayan kontrol aritmetiktir, görsel değil: enterpole eden bir çekirdek W(0) = 1 ile W(±1) = W(±2) = 0 koşullarını sağlamak zorundadır ve o üç noktayı ıskalayan her çekirdekte katsayı hatası vardır, nokta. Bir unit test'te o üç değere doğrulama kurun; yazım hatası sınıfındaki kusurların tamamı kaybolur

HotPDF bicubic Catmull-Rom dış dalının grafiği, yanlış bir katsayının neden saklandığını gösteriyor: iç içe Horner biçiminde -4 yerine -5 yazan yazım hatası yine de hesaplanır ve sıfır gerekirken W(1)'de -1, W(2)'de -2 bırakır; W(0) 1'e eşittir doğrulaması artı iki sıfır kısıtı saniyeler içinde yakalar
Bozuk bir çekirdek asla çökmez, yalnızca makul görünen sayılar döndürür; gözün bir katsayı yazım hatasını yakalayamamasının nedeni budur. W(0) = 1 artı artı ve eksi bir ile ikide sıfır koşulu, üç satırlık bir unit test'tir

Floyd-Steinberg dithering ve işlem hattındaki yeri

Dither geçişi, yeniden örneklemeden farklı bir sorundur ve işlem hattında başka bir noktada durur. RenderOutputDither, Floyd-Steinberg hata difüzyonunu sayfa kompozisyonunun ardından uygular; bu, monokrom bir baskı önizlemesi ya da faks tarzı bir dışa aktarım için anlamlı olan tek konumdur: işlem, tamamlanmış bir raster'i piksel başına tek bite indirmekle ilgilidir, girdi yolda imgelerin nasıl ölçeklendiğiyle değil

Algoritmanın kendisi kısadır. Luminance yüzde 50'de eşiklenir ve nicemleme hatası, klasik 7/16, 3/16, 5/16 ve 1/16 ağırlıklarıyla dört komşuya yayılır: sağa, sol alta, alta ve sağ alta. Çıktı pikseli her kanalda 0 ya da 255'tir. Naif alternatifin verdiği şey, difüzyonsuz sert bir eşik, fotoğrafı bir siluete çevirir ve içeriği taşıyan her ara tonu kaybeder

HotPDF Floyd-Steinberg dithering'in render işlem hattındaki konumu: RenderOutputDither, tamamlanmış 24 bitlik raster üzerinde sayfa kompozisyonundan sonra çalışır; luminance'i yüzde 50'de eşikler ve her nicemleme hatasını 7/16, 3/16, 5/16 ve 1/16 ağırlıklarıyla, biriktirmek zorunda olan bir satır tamponu üzerinden sağa ve alta yayar; tek bitlik monokrom çıktı üretir
Dithering kompozisyondan sonraya aittir; çünkü tamamlanmış bir raster'i tek bite indirir, imgelerin nasıl ölçeklendiğiyle değil. Difüzyon ağırlıkları bire toplanır ve satır tamponu üzerine yazmak yerine biriktirmek zorundadır
// Monokrom bir önizleme cihazı için render zamanı dithering
Pdf.RenderOutputDither := True;

// Ya da zaten sahibi olduğunuz bir bit eşleme aynı geçişi uygulayın.
// Bit eşlem pf24bit olmalı; işlev tahmin yürütmek yerine False döndürür
if not HPDFFloydSteinbergDitherBitmap(Preview) then
  raise Exception.Create('dither expects a 24-bit bitmap');

// Belge işlem hattı dışında yeniden örneklerken doğrudan çekirdek erişimi
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
  Small.SaveToFile('thumb.bmp');
finally
  Small.Free;
end;

Hata difüzyonunda herkesi bir kez ısıran tek bir uygulama ayrıntısı vardır. Satırdan satıra hata tamponu biriktirmek zorundadır. Bir sonraki satırdaki her piksel, güncel satırdaki üç farklı pikselden katkı alır (3/16, 5/16 ve 1/16 tap'leri) ve kod ekleme yerine atama yaparsa her yazım önceki katkıyı atar, yalnızca son tap hayatta kalır. İmge hâlâ dithering'li görünür; fark edilmesini zorlaştıran budur ama doku yanlıştır ve tonal üretim sürüklenir. Yakalayan test niceldir: düzgün bir orta gri alanı dithering'e sokun ve iç kapsamanın yüzde 40 ile 60 arasında çıkmasını şart koşun

Boyut düşürme işlem hattı hangi kombinasyonu kullanmalı?

Çekirdeği imgelerin gerçekte ne olduğuna göre seçin ve dithering'i bir sıkıştırma konusu değil cihaz konusu sayın. Boyut bütçesinden geçmek zorunda olan fotoğrafik taramalar için 150 ya da 200 DPI'daki rkLanczos3, piksel sayısını dört kat ya da daha fazla keserken insanların fark ettiği detayı korur. Ekran görüntüleri, diyagramlar ve çizgi sanatı için rkHalftone gerçekten yeterlidir ve çok daha hızlıdır; o imgelerde korunacak az sayıda tonal gradyan vardır. Her imgeyi inceleyemediğiniz karma bir kümede makul orta yol rkBicubic'tir: bilinear'dan iyi, Lanczos3 tap sayısının kabaca yarısı

Küçültme, birkaç kaldıraçtan biridir ve her zaman en büyüğü değildir. İki seviyeli taramalar genellikle Delphi'de yerli JBIG2 bilevel sıkıştırma makalesinde ele alınan kodlayıcıya çok daha iyi yanıt verir; kazanç orada piksel sayısından değil sembol sözlüklerinden gelir. Karar vermeden önce dosyada gerçekte ne olduğunu bilmek işe yarar; imgeleri ve decode filtrelerini çıkarma tam bunun içindir: imge nesnelerinin ve mevcut sıkıştırmalarının envanteri, yeniden örneklemenin kazanacak bir şeyi olup olmadığını söyler

Sonucu gösteren önizleme yüzeyini kuruyorsanız, bir PDF sayfasını bit eşleme render etme makalesinde belgelenen aynı render yolu, RenderOutputDither'ın devreye girdiği yerdir; böylece dithering'li önizleme ile dithering'li çıktı, birbirinden ayrışan iki uygulama değil tek bir kod yolundan gelir

İki özelliğin ardındaki genel ilke, kalite ayarlarının açık ve geri alınabilir olması gerektiğidir. HotPDF, tarihî davranışı varsayılan olarak tutar; böylece mevcut bir uygulama, çıktısında ya da süresinde sürpriz bir değişiklik olmadan yükselir ve daha iyi görünen, daha yavaş yollar tek bir özellik ataması uzaklıktadır. Her ikisi de, üzerine kuruldukları kaynak optimizasyonu ve render mekanizmasıyla birlikte HotPDF Delphi PDF bileşeni kapsamındadır