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
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
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: 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