Tehnički članak

JBIG2 pozadinski enkoderi i Free Pascal povezivač

PDFlibPas može kodirati dvorazinske slike kao JBIG2 kroz dva različita pozadinska enkodera. Jedan je izvorni Object Pascal MMR enkoder koji je uvijek prisutan. Drugi je vanjski enkoder simboličkog rječnika koji na skeniranom tekstu proizvodi znatno manji izlaz, i on je neobavezan: projekt mora povezati pozadinsku jedinicu da bi uopće postojao. Ta je razlika izvor najčešćeg iznenađenja s ovom značajkom, pa vrijedi reći prvo: DefaultJBIG2EncodeOptions prema zadanim postavkama traži vanjski enkoder, i kada pozadinska jedinica nije povezana taj se zahtjev tiho vraća na Pascal MMR put

Na Delphiju i C++Builderu vanjska pozadina jest skup prethodno izgrađenih statičkih objekata. Na Free Pascalu morala je postati DLL, a put do tog zaključka priča je o povezivaču korisna svakome tko je pokušao povezati C++ objekte u Free Pascal program

Registracija je ugovor

Pozadinska jedinica registrira se iz svog dijela za inicijalizaciju pozivom RegisterJBIG2EncoderBackend. Pozivatelji je traže ili kroz bit opcija, PDF_JBIG2_OPTION_EXTERNAL_ENCODER, koji ima vrijednost 4, ili kroz parametar UseExternalEncoder proširenih ulaznih točaka za slike. Kišobranska jedinica knjižnice namjerno ne povlači pozadinsku jedinicu, jer nošenje velikog skupa objekata treba biti odluka svakog projekta; u C++Builder stablu, na primjer, uključuje ga izričito projekt koji ga želi

Posljedica za pozivatelje jest da je traženje vanjskog enkodera preferencija, ne jamstvo, i izgradnja koja zaboravi jedinicu proizvodi veće datoteke umjesto pogreške. Ako vam veličina izlaza vrijedi dovoljno da tražite bolji enkoder, vrijedi dovoljno i da provjerite jeste li ga dobili

Tijek zahtjeva JBIG2 kodiranja u PDFlibPas u kojem preferencija vanjskog enkodera tiho pada natrag na izvorni Pascal MMR put bez pozadinske jedinice
Traženje vanjskog enkodera simboličkog rječnika jest preferencija: povezan, izlaz se smanjuje; nepovezan, Pascal MMR put tiho radi s većim datotekama
uses
  PDFlibrary,
{$IFDEF FPC}
  PDFlibJBIG2EncDLL;    // dinamička pozadina za Free Pascal
{$ELSE}
  PDFlibJBIG2EncC;      // statički skup objekata za Delphi / C++Builder
{$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;

Kompajliranje jedinice bilo je dva retka. Simboli su bili posao

Navesti pozadinsku jedinicu da se kompajlira pod Free Pascalom uzelo je točno dvije promjene: postavljanje dijalekta asemblera i zamjenu konstruktora postavki formata temeljenog na zapisu globalnom zadanom varijablom. To je pošteno odražavanje koliko je jednostavan Pascal prenosiv između ta dva kompajlera

Simbolička strana bila je pravi posao. Skup objekata referencira 176 C simbola. Od tih ih je 128 već imalo Pascal implementacije unutar jedinice i trebalo je samo prikačiti imena izvoza, jer Delphi koristi ime funkcije kao ime simbola dok Free Pascal zahtijeva izričitu deklaraciju javnog imena. Dvadeset sedam dijeljeno je s JPEG 2000 kodekom i moralo se izvesti iz točno jednog mjesta, jer ih dvostruka definicija slomi u svakom programu koji povezuje oboje. Preostalih 21 bili su platformski i C runtime ulazi, šesnaest Win32 funkcija datoteka plus nekoliko poziva standardne biblioteke, i otišli su u novu jedinicu za kompatibilnost

Ništa od toga konceptualno nije teško, a sve je to nužno prije nego povezivač uopće pokuša. Kod povezivača je stalo

Tri povezivačka puta, tri mrtva kraja

Interni Free Pascal povezivač ne može čitati objektne datoteke, jer ih je proizveo kompajler koji emitira asocijativne COMDAT sekcije, a interni povezivač javlja da ih ne podržava. To je ravan odbitak, ne upozorenje

Prelazak na vanjski povezivač izgledao je kao odgovor. Binutils povezivač priložen uz Free Pascal sruši se ravno dok primjenjuje sakupljanje smeća sekcija nad ovim arhivom, a ta je zastavica dio fiksnog skupa parametara koje Free Pascal prosljeđuje za 64-bitni Windows cilj, pa se ne može ukloniti iz naredbenog retka; dokumentirani prekidači za njezino suzbijanje ignoriraju se na ovom putu. Dostavljanje mnogo novijeg binutilsa umjesto toga ne uspijeva drugačije: ne može uopće obraditi Free Pascal skriptu povezivanja, proizvodeći prazan izlaz bez skripte i zid grešaka relokacija sa skriptom

Granica otkrivena usput vrijedi znati čak i ako nikad ne pogodite problem povezivača. Vanjski povezivač razrješuje putanje objektnih datoteka relativno u odnosu na izlazni direktorij izvršne datoteke, a ne u odnosu na stablo izvora, pa relativna direktiva uključivanja objekta radi samo kada izlazni direktorij slučajno odgovara radnom direktoriju u vremenu kompajliranja. Knjižnica ne može to pretpostaviti o projektu potrošača, što je samo po sebi razlog preferirati povezanu biblioteku umjesto rasutih objekata

Tri neuspjela povezivačka puta za C++ JBIG2 enkoderske objekte pod Free Pascalom i DLL koji izlaže dvije ravne C ulazne točke koje su ih razriješile
COMDAT sekcije svladavaju interni povezivač, oba vanjska povezivača ne uspijevaju, pa se C++ enkoder isporučuje kao jedan DLL koji pozadinska jedinica dinamički veže

Zašto drugi C++ kompajler ne pomaže

Očita sljedeća ideja je ponovno izgraditi C++ stranu kompajlerom čije objekte Free Pascal može čitati. I to ne radi, a razlog je temeljan, a ne pitanje prekidača. Minimalna C++ prijevodna jedinica koja sadrži predložak, kompajlirana sa svim značajkama generiranja kôda isključenima, i dalje emitira slabe vanjske simbole, jer instanciranje predložaka i inline proizvodi ih po konstrukciji. Free Pascal taj razred simbola odbacuje bez razmatranja. Obrnuti smjer također ne uspijeva: glavni C++ povezivač ne može konzumirati objekte drugog kompajlera zbog istog rukovanja COMDAT sekcijama

C++ kôd dakle ne može biti dostavljen kao objekti Free Pascalu nijednim dostupnim putem. Može biti dostavljen kao DLL, što se i dogodilo: enkoder i njegova ovisnost o obradi slika izgrađeni su u jednu biblioteku koja izlaže dvije ravne C ulazne točke, a Free Pascal pozadinska jedinica ih dinamički veže i registrira se točno kao statička pozadina. Delphi i C++Builder put nije diran uopće, što je ispravan ishod; problem prenosivosti na jednom alatnom lancu ne smije uznemiriti alatni lanac koji je već radio

Polaritet je jedina stvar koja će vas ugristi

Između Windows dvorazinske bitmape i JBIG2 enkodera postoji nepodudarnost konvencija koju nijedan sustav tipova neće uhvatiti. Scanline uređajno neovisne bitmape od jednog bita po pikselu tretira postavljeni bit kao bijeli. Enkoder tretira postavljeni bit kao crni. Predajte scanlineove nepromijenjene i dobit ćete savršeno valjan JBIG2 tok fotografskog negativa vaše stranice

Konvencije polariteta jednobitnog DIB-a i JBIG2 gdje je postavljeni bit bijeli u scanlineu i crni u enkoderu, ispravljeno invertiranjem svakog bajta
Isti bajtovi, suprotno značenje: bez invertiranja svakog bajta enkoder proizvodi valjan JBIG2 tok fotografskog negativa
// Jednobitni DIB: postavljeni bit znači bijelo. JBIG2 enkoder:
// postavljeni bit znači crno. Invertirajte svaki bajt na ulazu
for I := 0 to RowBytes - 1 do
  Row[I] := Row[I] xor $FF;

Metoda provjere vrijedi jednako kao i ispravak. Uspoređivanje duljina komprimiranih tokova vam ne govori ništa, jer negativ slike komprimira se u sličnu veličinu. Gledanje stranice dokazuje samo da nije očito invertirana. Pouzdana provjera jest prikazati izlaz oba puta kodiranja, izvorni Pascal i vanjski, u PNG i usporediti ih bajt po bajt: oba enkodera bezgubitni su na istoj izvornoj slici, pa sve što nije točno podudaranje jest greška u jednom od njih. Ta je usporedba sada stalna regresijska provjera, a to je vrsta tvrdnje vrijedna izgradnje kad god dvije implementacije trebaju slagati se točno

Koju pozadinu koristiti

Za opći dvorazinski sadržaj, razmućene polutonske snimke, linijsku grafiku, miješanu grafiku, izvorni Pascal MMR enkoder je dostatan i nema trošak raspoređivanja. Za skenirani tekst, slučaj za koji je JBIG2 dizajniran, vanjski enkoder simboličkog rječnika je mjesto gdje živi smanjenje veličine, jer ponavljajuće oblike glifova faktorizira u rječnik umjesto ponovnog kodiranja svake pojave. Ako proizvodite arhive skeniranih dokumenata, ta je razlika dovoljno velika da promijeni planiranje pohrane

Upstream pitanje, kako se dvorazinska slika uopće proizvodi, jednako je važno za veličinu izlaza; prikazivanje regije u monokromu pokriveno je u članku o prikazivanju monokromne regije, a strategija veličine cijelog dokumenta u optimizaciji veličine PDF datoteke i podskupovima fontova. Za skenirane skupove s ponavljajućim stranicama, deduplikacija često pobjeđuje bolju kompresiju, što je tema perceptualne deduplikacije slika. Dostupnost alatnog lanca i pozadine po platformi navedena je na stranici proizvoda losLab PDF Developer Library