A PDFlibPas kéttónusú képeket két különböző backenden keresztül kódolhatja JBIG2-be. Az egyik egy natív Object Pascal MMR kódoló, amely mindig jelen van. A másik egy külső szimbólumszótár-kódoló, amely a beolvasott szövegen lényegesen kisebb kimenetet állít elő, és ez opcionális: egy projektnek a backend egységet kell linkelnie, hogy egyáltalán létezzen. Ez a megkülönböztetés e funkció leggyakoribb meglepetésének forrása, ezért érdemes először kimondani: a DefaultJBIG2EncodeOptions alapértelmezés szerint a külső kódolót kéri, és ha a backend egység nincs linkelve, a kérés csendben a Pascal MMR útra esik vissza
Delphi és C++Builder alatt a külső backend előre lefordított statikus objektumok halmaza. Free Pascal alatt DLL-lé kellett válnia, és az út erre a következtetésre linker-történet, amely hasznos bárkinek, aki megpróbált C++ objektumokat linkelni Free Pascal programba
A regisztráció a szerződés
A backend egység az inicializációs szakaszában regisztrálja magát a RegisterJBIG2EncoderBackend hívásával. A hívók az opciós biten keresztül kérik, a PDF_JBIG2_OPTION_EXTERNAL_ENCODER jelzőn, amelynek értéke 4, vagy a kibővített képbemeneti pontok UseExternalEncoder paraméterén keresztül. A könyvtár esernyőegysége szándékosan nem húzza be a backend egységet, mert egy nagy objektumkészlet cipelése minden projekt saját döntése kell legyen; a C++Builder fában például azok a projektek foglalják be explicit módon, amelyek igénylik
A hívók számára a következmény az, hogy a külső kódoló kérése preferencia, nem garancia, és az egységet elfelejtő build hiba helyett nagyobb fájlokat állít elő. Ha a kimenet mérete elég fontos ahhoz, hogy a jobb kódolót kérje, elég fontos ahhoz is, hogy ellenőrizze, megkapta-e
uses
PDFlibrary,
{$IFDEF FPC}
PDFlibJBIG2EncDLL; // dinamikus backend Free Pascalhoz
{$ELSE}
PDFlibJBIG2EncC; // statikus objektumkészlet Delphihez / C++Builderhez
{$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;
Az egység lefordítása két sor volt. A szimbólumok jelentették a munkát
A backend egység Free Pascal alá való lefordítása pontosan két változtatást vett igénybe: az assemblerdialektus beállítását és egy rekordalapú formátumbeállítás-konstruktor cseréjét a globális alapértelmezett változóra. Ez korrekt tükrözi, mennyire hordozható az egyenes vonalú Pascal a két fordító között
A szimbólumoldal volt az igazi munka. Az objektumkészlet 176 C szimbólumra hivatkozik. Ebből 128-nak már volt Pascal-implementációja az egységen belül, és csak exportneveket kellett hozzácsatolni, mert a Delphi a függvénynevet használja szimbólumnévként, míg a Free Pascal explicit publikus névdeklarációt követel. Huszonhét a JPEG 2000 kodekkel osztozott, és pontosan egy helyről kellett exportálni, mert kétszeres definíciójuk megtör minden programot, amely mindkettőt linkeli. A maradék 21 platform- és C futásidejű bejegyzés volt, tizenhat Win32 fájlfüggvény plusz néhány standard függvénytári hívás, és ezek egy új kompatibilitási egységbe kerültek
Egyik sem koncepciójában nehéz, és mindegyik szükséges, mielőtt a linker egyáltalán megpróbálkozna. A linker volt az, ahol megállt
Három linkelési útvonal, három zsákutca
A Free Pascal belső linkere nem tudja olvasni az objektumfájlokat, mert azokat egy olyan fordító állította elő, amely asszociatív COMDAT szekciókat bocsát ki, és a belső linker arról számol be, hogy nem támogatja őket. Ez lapos elutasítás, nem figyelmeztetés
Külső linkerre váltás válasznak látszott. A Free Pascallel érkező binutils linker nyíltan összeomlik, amikor szekció-szemétszedést alkalmaz erre az archívumra, és ez a jelző a Free Pascal 64 bites Windows célhoz átadott rögzített paraméterkészletének része, tehát nem távolítható el a parancssorból; az elnyomására dokumentált kapcsolók ezen az úton figyelmen kívül maradnak. Egy sokkal újabb binutils szolgáltatása egészen másképp bukik meg: egyáltalán nem tudja feldolgozni a Free Pascal linkszkriptjét, szkript nélkül üres kimenetet ad, szkripttel pedig relokációs hibák falát
Egy útközben felfedezett határvonal akkor is tudásra érdemes, ha soha nem ütközik a linkerproblémába. A külső linker az objektumfájl-útvonalakat a végrehajtható fájl kimeneti könyvtárához képest oldja fel, nem a forrásfához, így egy relatív include-object direktíva csak akkor működik, amikor a kimeneti könyvtár éppen egyezik a fordítási munkakönyvtárral. Egy könyvtár ezt nem feltételezheti egy fogyasztó projektről, ami önmagában ok arra, hogy lazán objektumok helyett linkelt függvénytárat részesítsen előnyben
Miért nem segít egy másik C++ fordító
A kézenfekvő következő ötlet a C++ oldal újbóli lefordítása egy olyan fordítóval, amelynek objektumait a Free Pascal olvasni tudja. Ez sem működik, és az ok fundamentális, nem kapcsolókérdés. Egy sablont tartalmazó minimális C++ fordítási egység, minden kódgenerációs szolgáltatás kikapcsolásával lefordítva, gyenge külső szimbólumokat is kibocsát, mert a sablon- és inline-példányosítás konstrukcióból fakadóan állítja elő őket. A Free Pascal ezt a szimbólumosztályt laposan elutasítja. A fordított irány is megbukik: egy főáramú C++ linker a másik fordító objektumait nem tudja fogyasztani ugyanezen COMDAT szekciókezelés miatt
Tehát a C++ kód nem szállítható objektumként a Free Pascalnak egyetlen elérhető úton sem. DLL-ként szállítható, és ez történt: a kódoló és a képfeldolgozási függősége egyetlen függvénytárba épült, amely két lapos C belépési pontot tesz ki, és a Free Pascal backend egység ezeket dinamikusan köti be, majd pontosan úgy regisztrálja magát, ahogyan a statikus backend teszi. A Delphi és C++Builder útvonalat egyáltalán nem érintették, ami a helyes kimenet; egy eszközlánc hordozhatósági problémája nem zavarhatja meg azt az eszközláncot, amely már működött
A polaritás az egyetlen dolog, amely csíphet
Egy Windows kéttónusú bittérkép és egy JBIG2 kódoló között konvencióeltérés van, amelyet egyetlen típusrendszer sem fog el. Egy bitenként-egypixeles eszközfüggetlen bittérkép pásztázásvonala a beállított bitet fehérként kezeli. A kódoló a beállított bitet feketeként kezeli. Adja át a pásztázásvonalakat változatlanul, és egy tökéletesen érvényes JBIG2 folyamot kap, amely az oldalának fényképészeti negatívja
// Egybites DIB: a beállított bit fehéret jelent. JBIG2 kódoló:
// a beállított bit feketét jelent. Minden bájt inverziója útközben
for I := 0 to RowBytes - 1 do
Row[I] := Row[I] xor $FF;
Az ellenőrzési módszer ugyanannyit számít, mint a javítás. A tömörített folyamok hosszának összehasonlítása semmit nem mond, mert egy negatív kép hasonló méretre tömörödik. Az oldal megnézése csak azt bizonyítja, hogy nem nyilvánvalóan invertált. A megbízható ellenőrzés az, hogy mindkét kódolási út — a natív Pascal és a külső — kimenetét PNG-be rendereli, és bájtonként összehasonlítja: mindkét kódoló veszteségmentes ugyanazon forráskép esetén, tehát bármi más, mint a tökéletes egyezés, az egyikben lévő hiba. Ez az összehasonlítás mostantól állandó regressziós teszt, és az az állításfajta, amelyet érdemes felépíteni, akárhányszor két implementációnak pontosan kell egyeznie
Melyik backendet használja
Általános kéttónusú tartalomhoz, ditherelt rácsos árnyalatokhoz, vonalas grafikákhoz, vegyes grafikákhoz a natív Pascal MMR kódoló elegendő, és nincs telepítési költsége. Beolvasott szöveghez, amelyre a JBIG2-t tervezték, a külső szimbólumszótár-kódoló az, ahol a méretcsökkentés lakik, mert az ismétlődő glífaalakokat szótárba helyezi ki minden egyes előfordulás újrakódolása helyett. Ha beolvasott dokumentumok archívumait állítja elő, ez a különbség elég nagy ahhoz, hogy megváltoztassa a tárolástervezést
A felsőbb szintű kérdés, hogyan állítják elő egyáltalán a kéttónusú képet, ugyanannyira számít a kimenet méretére; a régión alapuló monokróm renderelést a monokróm régiórenderelési cikk tárgyalja, a dokumentumszintű méretstratégiát pedig a PDF fájlméret-optimalizálás és betűtípus-szubszettelés. Ismétlődő oldalakkal rendelkező szkenneléskészleteknél a deduplikáció gyakran legyőzi a jobb tömörítést, amellyel a perceptuális képdeduplikáció foglalkozik. Az eszközlánc és a backend elérhetősége platformonként a losLab PDF Developer Library terméklapon található