Teknik Makale

JBIG2 Kodlayıcı Arka Uçları ve Free Pascal Bağlayıcısı

PDFlibPas, iki düzeyli görüntüleri iki farklı arka uç üzerinden JBIG2 olarak kodlayabilir. Biri, her zaman mevcut olan yerel bir Object Pascal MMR kodlayıcısıdır. Diğeri, taranmış metinde belirgin biçimde daha küçük çıktı üreten harici bir sembol sözlüğü kodlayıcısıdır ve isteğe bağlıdır: onun var olması için projenin arka uç birimini bağlaması gerekir. Bu ayrım, bu özellikle ilgili en yaygın sürprizin kaynağıdır, bu yüzden önce söylenmeye değer: DefaultJBIG2EncodeOptions varsayılan olarak harici kodlayıcıyı ister ve arka uç birimi bağlı olmadığında istek sessizce Pascal MMR yoluna düşer

Delphi ve C++Builder üzerinde harici arka uç, önceden derlenmiş statik nesneler kümesidir. Free Pascal üzerinde bir DLL olmak zorunda kaldı ve bu sonuca giden yol, Free Pascal programına C++ nesneleri bağlamayı denemiş herkese faydalı bir bağlayıcı öyküsüdür

Kayıt sözleşmedir

Arka uç birimi, başlangıç bölümünden RegisterJBIG2EncoderBackend çağırarak kendini kaydeder. Çağıranlar ona ya 4 değerine sahip PDF_JBIG2_OPTION_EXTERNAL_ENCODER seçenek biti üzerinden ya da genişletilmiş görüntü giriş noktalarının UseExternalEncoder parametresi üzerinden ister. Kitaplık şemsiyesi arka uç birimini bilinçli olarak içine çekmez, çünkü büyük bir nesne kümesini taşımak her projenin kararı olmalıdır; örneğin C++Builder ağacında, isteyen projeler tarafından açıkça dahil edilir

Çağıranlar için sonuç şudur: harici kodlayıcıyı istemek bir tercihtir, garanti değil, ve birimi unutan bir derleme hata değil daha büyük dosyalar üretir. Çıktı boyutu daha iyi kodlayıcıyı isteyecek kadar önemliyse, onu gerçekten aldığınızı denetlemek de o kadar önemlidir

PDFlibPas JBIG2 kodlama isteği akışı; arka uç birimi olmadan harici kodlayıcı tercihi sessizce yerel Pascal MMR yoluna düşer
Harici sembol sözlüğü kodlayıcısını istemek bir tercihtir: bağlıysa çıktı küçülür; bağlı değilse Pascal MMR yolu sessizce daha büyük dosyalarla çalışır
uses
  PDFlibrary,
{$IFDEF FPC}
  PDFlibJBIG2EncDLL;    // Free Pascal için dinamik arka uç
{$ELSE}
  PDFlibJBIG2EncC;      // Delphi / C++Builder için statik nesne kümesi
{$ENDIF}

var
  Pdf: TPDFlib;
  ImageId: Integer;
begin
  Pdf := TPDFlib.Create(nil);
  try
    Pdf.NewDocument;
    Pdf.NewPage;
    // Interpolate, SymbolExtract, UseExternalEncoder, SkipBlackDots,
    // BlackDotSize, LossyLevel
    ImageId := Pdf.AddImageJBIG2FromFileEx('scan-page-1.tif',
      0, 1, 1, 0, 0, 0);
    if ImageId = 0 then
      raise Exception.Create('JBIG2 encoding failed');
    Pdf.SaveToFile('archive.pdf');
  finally
    Pdf.Free;
  end;
end;

Birimi derlemek iki satırdı. Semboller asıl işti

Arka uç biriminin kendisini Free Pascal altında derletmek tam olarak iki değişiklik aldı: assembler lehçesini ayarlamak ve kayıt tabanlı bir biçim ayarları kurucusunu genel varsayılan değişkenle değiştirmek. Bu, düz Pascal'ın iki derleyici arasında ne kadar taşınabilir olduğunun adil bir yansımasıdır

Sembol tarafı asıl işti. Nesne kümesi 176 C sembolüne atıf yapar. Bunlardan 128'inin birimin içinde zaten Pascal uygulamaları vardı ve yalnızca dışa aktarım adlarının eklenmesi gerekiyordu; çünkü Delphi işlev adını sembol adı olarak kullanırken Free Pascal açık bir public ad bildirimi gerektirir. Yirmi yedisi JPEG 2000 kodeciyle paylaşıldı ve tam olarak tek bir yerden dışa aktarılmaları gerekti, çünkü iki kez tanımlanmaları her ikisini de bağlayan her programı bozar. Kalan 21 platform ve C çalışma zamanı girdisiydi; on altı Win32 dosya işlevi artı bir avuç standart kitaplık çağrısı ve bunlar yeni bir uyumluluk birimine gitti

Bunların hiçbiri kavramsal olarak zor değildir ve hepsi, bağlayıcının şans bile denemesinden önce gereklidir. Durduğu yer ise bağlayıcıydı

Üç bağlama yolu, üç çıkmaz

Free Pascal'ın iç bağlayıcısı nesne dosyalarını okuyamaz, çünkü bunlar ilişkisel COMDAT bölümleri yayan bir derleyici tarafından üretilmiştir ve iç bağlayıcı bunları desteklemediğini bildirir. Bu düz bir rettur, uyarı değil

Harici bir bağlayıcıya geçmek cevap gibi görünüyordu. Free Pascal ile gelen binutils bağlayıcısı, bu arşive bölüm çöp toplama uygularken doğrudan çöküyor ve o bayrak, Free Pascal'ın 64 bitlik Windows hedefi için geçtiği sabit parametre kümesinin parçası; dolayısıyla komut satırından çıkarılamıyor, onu bastırmaya yönelik belgelenmiş anahtarlar bu yolda yok sayılıyor. Bunun yerine çok daha yeni bir binutils vermek ise başka türlü başarısız oluyor: Free Pascal bağlama betiğini hiç işleyemiyor, betiksiz boş bir çıktı, betikle birlikte de bir duvar dolusu yer değiştirme hatası üretiyor

Yolda keşfedilen bir sınırlama, bağlayıcı sorununa asla takılmasanız bile bilmeye değer: harici bağlayıcı nesne dosyası yollarını kaynak ağacına göre değil, çalıştırılabilir çıktı dizinine göre çözer; dolayısıyla göreli bir nesne dahil etme yönergesi yalnızca çıktı dizininin derleme zamanı çalışma dizinine denk düştüğü durumda çalışır. Bir kitaplık bunu bir tüketicinin projesi hakkında varsayamaz; bu tek başına, gevşek nesnelere tercih edilerek bağlı bir kitaplığın nedeni olmaya yeter

Free Pascal altında C++ JBIG2 kodlayıcı nesneleri için başarısız olan üç bağlayıcı yolu ve bunları çözen iki düz C giriş noktası açan DLL
COMDAT bölümleri iç bağlayıcıyı yener ve her iki harici bağlayıcı da başarısız olur; bu yüzden C++ kodlayıcı, arka uç birimi tarafından dinamik bağlanan tek bir DLL olarak gönderilir

Başka bir C++ derleyicisi neden işe yaramaz

Bir sonraki bariz fikir, C++ tarafını Free Pascal'ın okuyabildiği nesneler üreten bir derleyiciyle yeniden derlemektir. Bu da işe yaramaz ve nedeni anahtarlar meselesi değil, kökten bir meseledir. Bir şablon içeren, tüm kod üretim özellikleri kapatılmış minimal bir C++ çeviri birimi bile zayıf dış semboller yayar, çünkü şablon ve inline örneklemeleri bunları kurgusal olarak üretir. Free Pascal o sembol sınıfını düpedüz reddeder. Ters yön de başarısız olur: ana akım bir C++ bağlayıcısı, aynı COMDAT bölüm ele alma biçimi yüzünden diğer derleyicinin nesnelerini tüketemez

Yani C++ kodu, mevcut hiçbir yolla Free Pascal'a nesne olarak teslim edilemez. DLL olarak teslim edilebilir ve olan da budur: kodlayıcı ve görüntü işleme bağımlılığı, iki düz C giriş noktası açan tek bir kitaplıkta derlenir ve Free Pascal arka uç birimi bunları dinamik bağlar, tam olarak statik arka ucun yaptığı gibi kendini kaydeder. Delphi ve C++Builder yoluna hiç dokunulmadı; doğru sonuç da budur. Bir araç zincirindeki taşınabilirlik sorunu, zaten çalışan araç zincirini bozmalı değildir

Sizi ısıracak olan tek şey kutupluluktur

Bir Windows iki düzeyli bit eşlem ile bir JBIG2 kodlayıcısı arasında hiçbir tür sistemin yakalayamayacağı bir kural uyuşmazlığı vardır. Piksel başına bir bitlik aygıttan bağımsız bit eşlem tarama satırı, dolu biti beyaz sayar. Kodlayıcı dolu biti siyah sayar. Tarama satırlarını olduğu gibi teslim ederseniz, sayfanızın fotoğrafik negatifinden oluşan tamamen geçerli bir JBIG2 akışı alırsınız

Bir bitlik DIB ve JBIG2 kutupluluk kuralları; dolu bit tarama satırında beyaz, kodlayıcıda siyahtır ve her baytın ters çevrilmesiyle düzeltilir
Aynı baytlar, ters anlamlar: her baytı ters çevirmeden kodlayıcı, fotoğrafik negatiften oluşan geçerli bir JBIG2 akışı üretir
// Bir bitlik DIB: dolu bit beyaz demektir. JBIG2 kodlayıcı: dolu bit
// siyah demektir. Yolda her baytı ters çevirin
for I := 0 to RowBytes - 1 do
  Row[I] := Row[I] xor $FF;

Doğrulama yöntemi, düzeltme kadar önemlidir. Sıkıştırılmış akış uzunluklarını karşılaştırmak hiçbir şey söylemez, çünkü negatif bir görüntü benzer boyuta sıkışır. Sayfaya bakmak yalnızca bariz biçimde ters çevrilmediğini kanıtlar. Güvenilir denetim, her iki kodlama yolunun çıktısını, yerel Pascal ve harici, PNG olarak çizmek ve bayt bayt karşılaştırmaktır: her iki kodlayıcı da aynı kaynak görüntü üzerinde kayıpsızdır, dolayısıyla tam eşleşme dışı her şey onlardan birindeki bir hatadır. O karşılaştırma artık kalıcı bir gerileme testidir ve iki uygulamanın tam olarak örtüşmesi gerektiği her durumda kurulmaya değer bir sav türüdür

Hangi arka uç kullanılmalı

Genel iki düzeyli içerik için, benekli half tonlar, çizgi sanatı, karma grafikler için yerel Pascal MMR kodlayıcısı yeterlidir ve dağıtım maliyeti yoktur. JBIG2'nin tasarım amacı olan taranmış metin için ise küçülmenin yaşadığı yer harici sembol sözlüğü kodlayıcısıdır, çünkü tekrarlanan glif şekillerini her geçtiği yeri yeniden kodlamak yerine bir sözlükte çarpanlarına ayırır. Taranmış belgelerden arşivler üretiyorsanız, bu fark depolama planlamasını değiştirecek kadar büyüktür

İki düzeyli görüntünün başta nasıl üretildiği sorusu, çıktı boyutu için en az o kadar önemlidir; bölge tabanlı tek renk çizimi tek renk bölge çizimi makalesinde ele alınır, belge genelinde boyut stratejisi ise PDF dosya boyutu iyileştirme ve font alt kümelemede. Tekrarlanan sayfalı tarama kümeleri için tekilleştirme genellikle daha iyi sıkıştırmayı geride bırakır; konusu algısal görüntü tekilleştirmesidir. Araç zinciri ve platform başına arka uç kullanılabilirliği losLab PDF Developer Library ürün sayfasında listelenir