Tehnički članak

Nativna JBIG2 bilevel kompresija slika u Delphi PDF-ovima

Skeniran ugovor je nekoliko stotina tacaka po incu crnog mastila na beloj hartiji. Smesten kao bitmapa s jednim bitom po pikselu vec je mali, ali sto takvih stranica i dalje naduvava PDF izvan svega sto biste poslali mejlom. Pravi filter menja aritmetiku. JBIG2 je kompresija s najvecim odnosom smanjenjas kojom ISO 32000-1 definise za bilevel slike, i na gomili skeniranog teksta rutinski prepolovi ono sto CCITT Group 4 proizvede. Ovo je filter za koji treba posegnuti kada je ulaz faksovan, skeniran ili inace sveden na dve boje, i HotPDF moze da ga upisuje direktno u PDF

Format zaradjuje taj odnos s dve ideje koje genericki kodek slike nema. Modelira kako crni nizovi stoje na beloj pozadini, i primecuje da se skeniranastrana u sustini sastoji od istih nekoliko stotina oblika glifova koji se ponavljaju hiljadama puta. Razumevanje oba sto vam omogucava da brate opcije kodiranja namerno umesto da pogadjate

Gde JBIG2 sedi u PDF specifikaciji

ISO 32000-1 navodi JBIG2Decode medju filterima tokova u §7.4.7, dostupan od PDF 1.4 nadalje. Primenjuje se na jedno mesto jedino: XObject slike ciji je /BitsPerComponent 1 i ciji se prostor boja razresava u jedan kanal. To je cela poenta. JBIG2 je bilevel kodek, pa nikad ne konkurise DCT ili JPXDecode na fotografijama. Konkurise CCITTFaxDecode, filterima faksa Group 3 i Group 4, na tacno onoj vrsti dvobojne stranice koju skener dokumenata proizvodi

Dekoder trosi ugradenu JBIG2 organizaciju koju standard zove PDF profilom, gde svaki tok slike sadrzi niz segmenata umesto golih bitova. Opcioni tok /JBIG2Globals nosi segmente deljene medju vise slika u istom dokumentu, sto je mehanizam koji dozvoljava da se ponavljajuci sadrzaj cuva jednom za celu datoteku umesto jednom po stranici. HotPDF podrazumevano emituje tok po slici i drzi kanal globals slobodnim osim ako ga backend ne zatrazi

Arhitektura enkodera s backendima na prvom mestu

Kompletan JBIG2 enkoder je velik deo softvera, i njegovi najagresivniji delovi su istorijski bili optereceni patentima i isporucivani pod licencama koje ne odgovaraju svakom proizvodu. HotPDF resava tu tenziju razdvajanjem interfejsa od endzina. Jedinica HPDFJBIG2 definise pozive koje ostatak biblioteke upucuje, i isporucuje skroman ugradjen enkoder tako da JBIG2 radi odmah. Kada su vam potrebni omjeri produkcijskog kvaliteta, registrujete jacis endzin i biblioteka mu delegira, bez ikakve promene u vasem kodu koji poziva

Prekidac je jedan poziv registracije. Bez registrovanog backenda, enkoder se vraca na ugradjenu putanju. Registrujte jedan i svako naknadno kodiranje prolazi kroz njega

Dijagram HotPDF JBIG2 šava enkodera u HPDFJBIG2, koji predaje kodiranje licenciranom registrovanom backend-u koji poštuje LossyLevel 0 do 9 kad je jedan instaliran, a inače koristi ugrađeni bešumno MMR generički region pre umotavanja izlaza u JBIG2Decode image XObject sa opcionim JBIG2Globals
Odmah iz kutije ugrađena MMR putanja odgovara na svaki poziv dok licencirani motor preuzima trenutkom kad se registruje kroz šav
uses
  HPDFJBIG2;

// Proveri šta je aktivno, pa po želji instaliraj jači engine
if not IsJBIG2EncoderBackendAvailable then
  // Produkcioni backend nije prisutan: HotPDF koristi ugrađenu MMR putanju
  RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);

// Kasnije, za povratak na ugrađeno ponašanje:
// ClearJBIG2Backends;

Ista kuka postoji za dekodiranje kroz RegisterJBIG2DecoderBackend, s IsJBIG2DecoderBackendAvailable za ispitivanje. Zato biblioteka isporucuje malu ugradjenu putanju plus spojnicu za backend umesto jednog monolitnog enkodera. Ugradjena putanja drzi binarni fajl malim i slobodnim od licencnih opterecenja, dok spojnica dozvoljava timu koji je licencirao pun enkoder da ga prikljuci bez dodirivanja sloja za upisivanje PDF-a uopste

Sta opcije kodiranja zapravo razmenjuju

Kodiranje se konfigurise kroz TJBIG2EncodeOptions, zapis s poljima Lossless, UseGlobalSegments, UseSymbolDictionary i LossyLevel. Omotac prilagodjen komponentama THPDFJBIG2Options objavljuje Lossless, UseSymbolDictionary i LossyLevel tako da se mogu postaviti iz Object Inspector-a, i interno ih konvertuje u zapis. Tri namere pokrecus postavke

Lossless rekonstrukcija cuva svaki piksel. Postavite Lossless na True i ostavite LossyLevel na nuli, i dekodovana bitmapa je bit-po-bit identicna ulazu. Ovo je jedini bezbedan izbor za linijsku umetnost, tehnicke crtezes i svaku stranicu gde bi izgubljen piksel mogao da promeni znacenje, kao sto su potpis ili pecat. Kodiranje recnikom simbola ukljucuje deduplikaciju svesnu teksta i opcija je koja razdvaja JBIG2 od faks filtera. Lossy nivo, ceo broj od 0 do 9, dozvoljava sposobnom backendu da trguje vernoscu za velicinu tretiranjem gotovo identicnih oznaka kao istog simbola. Nula znaci lossless. Ugradjen enkoder postuje samo lossless putanju i ignorise bilo koji nenulti lossy nivo, pa visi nivoi stupaju na snagu tek jednom kada je registrovan backend koji ih implementira

var
  Options: TJBIG2EncodeOptions;
begin
  Options := DefaultJBIG2EncodeOptions;   // Lossless True, rečnik simbola uključen
  Options.Lossless := True;
  Options.LossyLevel := 0;                // 0 čuva svaki piksel
  Options.UseSymbolDictionary := True;    // ukloni duplikate ponovljenih glifova
  // Prosledi Options backendu ili prepusti THPDFJBIG2Options da ih nosi
end;

Recnici simbola i zasto tekstualni skenovi pobedjuju

Stranica skeniranog teksta zapravo nije slika reci. To je isto slovo e odstampano nekoliko stotina puta, isto t, isti zarez, svaka instanca malo bucna kopija jednog osnovnog oblika. Recnik simbola hvata tu strukturu. Enkoder prikuplja razlicite oznake na stranici u recnik, cuva svaki oblik jednom, a zatim beleizi stranicu kao listu pozicija koje upucuju na stavke recnika. Hiljadu pojava istog glifa kostaju jednu sacuvanu bitmapu plus hiljadu jeftinih plasiranja

Upravo tu JBIG2 pretice CCITT Group 4. Group 4 kodira svaki red skeniranja u odnosu na red iznad njega bez ikakvog pojma o glifu, pa placa pun troskak svakog slova svaki put kad se slovo pojavi. JBIG2 placa jednom. Kada se isti recnik promovise u tok globals na nivou dokumenta, usteda se mnozi kroz visestrani sken, jer su oblici zajednicki od stranice do stranice sacuvani jednom za celu datoteku. Na gustom tekstu razlika nije marginalna. To je razlog zasto JBIG2 postoji

HotPDF dijagram koji poredi kako CCITT Group 4 naplaćuje svaku pojavu glyph-a posebno dok JBIG2 svaki poseban oblik čuva jednom u rečniku simbola i postavlja ga jeftinom referencom, unaprećujući deljene oblike u document-level JBIG2Globals tok tako da višestrane skenove čuva jednom po obliku
Ponovljeni glifovi ugnežde se u rečnik pa stranica fakturiše jednu bitmapu po obliku plus jeftina postavljanja, i globali rastegnu uštedu preko stranica

Genericki region i MMR za sve ostalo

Nije svaka bilevel slika tekst. Karte, sheme, inzenjerski crtezes i mesovite stranice imaju linijsku umetnost koju nijedan recnik ne moze da sazme. Za njih, JBIG2 kodira genericki region, pravougaonik piksela kompresovan direktno bez ikakvog treninga simbola. Standard dozvoljava generickom regionu da koristi MMR, modifikovano modifikovano READ kodiranje koje Group 4 faks vec koristi, koje modelira svaki red piksela u odnosu na red iznad njega

Ovo je putanja koju HotPDF isporucuje u svom ugradjenom enkoderu. Kada nijedan backend nije registrovan i zahtev je lossless, biblioteka kompresuje bitmapu kao jedan MMR genericki region i umotava ga u JBIG2 strukturu segmenata koju PDF profil zahteva. Ne treba joj recnik, ni trening prolaz, ni druga slika za referencu, pa je pouzdana podrazumevana vrednost za linijsku umetnost i mesovit bilevel sadrzaj. Nece odgovarati punom enkoderu recnika simbola na cistom tekstu, ali je uvek tacan, uvek lossless i uvek prisutan. Povrsina enkodera za to je jedan poziv

var
  Encoder: THPDFJBIG2Encoder;
  ImageData: TJBIG2ByteArray;
  Scanlines: TJBIG2ScanlineArray;  // jedan niz bajtova po redu, MSB-first
  W, H: Integer;
begin
  // Scanlines, W i H opisuju 1-bitnu stranicu; svaki red ima (W + 7) div 8 bajtova
  Encoder := THPDFJBIG2Encoder.Create;
  try
    if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
      // ImageData sada sadrži JBIG2 tok spreman za /JBIG2Decode XObject
      ;
  finally
    Encoder.Free;
  end;
end;

Ukljucivanje pri gradnji dokumenta

Za svakodnevnu upotrebu ne dodirujete klasu enkodera direktno. HotPDF izlaze JBIG2 kao izbor kompresije slike na dokumentu. Enumeracija THPDFImageCompressionType ukljucuje icJBIG2 pored Flate, JPEG i CCITT opcija, i dokument nosi osobinu JBIG2Options tipa THPDFJBIG2Options koja cuva postavke koriscene kada je izabrana ta kompresija. Podesite oba pre nego sto dodate bilevel slike koje zelite da kompresujete na ovaj nacin

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.ImageCompressionType := icJBIG2;     // usmeri 1-bitne slike kroz JBIG2
    Pdf.JBIG2Options.Lossless := True;        // sačuvaj svaki piksel
    Pdf.JBIG2Options.UseSymbolDictionary := True;
    Pdf.JBIG2Options.LossyLevel := 0;
    // Dodaj stranice i ovde postavi skenirane 1-bitne slike
  finally
    Pdf.Free;
  end;
end;

Jedna pogodnost vredna napomene je dodatak DBGridHotPDFExport, koji renderuje TDBGrid direktno u PDF. Njegov izlaz je uglavnom bilevel linije i tekst, pa dokument konfigurisan za JBIG2 drzi te izvoze kompaktnim bez ikakvog dodatnog rukovanja s vase strane. Dve srodne teme na ovom blogu idu dublje u okruzujuci tok rada. Za nacin na koji se slike i fontovi polazu kada gradite izvestaje, pogledajte izlaz izvestaja s fontovima i slikama u Delphi-ju. Kada kompresovan dokument mora da zadovolji arhivski profil, pravila u PDF/A, PDF/X i PDF/UA validaciji u Delphi-ju govore vam koje filtere odredjeni nivo uskladjenosti prihvata. JBIG2 se isporucuje kao deo HotPDF Delphi Component za Delphi i C++Builder, pored API-ja za ucitavanje, uredjivanje i sifrovanje pokrivenih na drugim mestima ovde