Technický článok

Natívna komprimácia JBIG2 dvojúrovňových obrázkov v Delphi PDF súboroch

Naskenovaná zmluva je niekoľko stoviek bodov na palec čierneho atramentu na bielom papieri. Uložená ako bitová mapa s jedným bitom na pixel je už sama o sebe malá, no sto takýchto stránok stále nafúkne PDF nad rámec toho, čo by ste odoslali e-mailom. Správny filter zmení aritmetiku. JBIG2 je komprimácia s najvyšším pomerom, ktorú norma ISO 32000-1 definuje pre dvojúrovňové obrázky, a pri skupinách naskenovaného textu rutinne znižuje veľkosť na polovicu oproti tomu, čo produkuje CCITT Group 4. Toto je filter, po ktorom siahnete, keď vstup pochádza z faxu, skenera alebo je inak redukovaný na dve farby, a HotPDF ho dokáže priamo zapísať do PDF

Formát dosahuje tento pomer vďaka dvom myšlienkam, ktoré bežný obrázkový kodek nemá. Modeluje, ako čierne úseky ležia na bielom pozadí, a rozoznáva, že naskenovaná stránka pozostáva prevažne z niekoľkých stoviek rovnakých tvarov glyfov opakovaných tisíckrát. Pochopenie oboch aspektov vám umožní zámer​ne vyberať možnosti kódovania namiesto hádania

Kde sa JBIG2 nachádza v špecifikácii PDF

Norma ISO 32000-1 uvádza JBIG2Decode medzi filtruváciami streamov v §7.4.7, dostupné od PDF 1.4. Vzťahuje sa len na jedno miesto: obrazové objekty XObject, ktorých hodnota /BitsPerComponent je 1 a farebný priestor sa rozkladá na jediný kanál. To je celý zmysel. JBIG2 je dvojúrovňový kodek, takže nikdy nesúperí s DCT alebo JPXDecode pri fotografiách. Súperí s CCITTFaxDecode, faxovými filtrami Group 3 a Group 4, práve pri type dvojtónovej stránky, ktorú produkuje dokumentový skener

Dekodér spracúva vloženú organizáciu JBIG2, ktorú norma označuje ako PDF profil, kde každý obrazový stream obsahuje sekvenciu segmentov namiesto holého bitového toku. Voliteľný stream /JBIG2Globals prenáša segmenty zdieľané naprieč viacerými obrázkami v tom istom dokumente — to je mechanizmus, ktorý umožňuje uložiť opakujúci sa obsah raz pre celý súbor namiesto raz na stránku. HotPDF predvolene vysiela stream per-image a kanál globals nechá voľný, pokiaľ o to backend nepožiada

Architektúra kódovača s prioriotou backendu

Kompletný kódovač JBIG2 je rozsiahly softvér a jeho najagresívnejšie časti boli historicky zaťažené patentmi a distribuované pod licenciami, ktoré nevyhovujú každému produktu. HotPDF toto napätie rieši oddelením rozhrania od motora. Jednotka HPDFJBIG2 definuje volania, ktoré zvyšok knižnice vykonáva, a obsahuje skromný vstavaný kódovač, aby JBIG2 fungoval hneď po nainštalovaní. Keď potrebujete produkčné kompresné pomery, zaregistrujete silnejší motor a knižnica mu deleguje prácu bez akejkoľvek zmeny vo vašom kóde

Prepínanie sa vykoná jediným registračným volaním. Bez zaregistrovaného backendu kódovač spadne späť na vstavaný postup. Zaregistrujte ho a každé ďalšie kódovanie prebehne cez neho

uses
  HPDFJBIG2;

// Query what is active, then optionally install a stronger engine.
if not IsJBIG2EncoderBackendAvailable then
  // Production backend not present: HotPDF uses its built-in MMR path.
  RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);

// Later, to return to the built-in behaviour:
// ClearJBIG2Backends;

Rovnaký háčik existuje pre dekódovanie prostredníctvom RegisterJBIG2DecoderBackend, pričom IsJBIG2DecoderBackendAvailable slúži na jeho overenie. Preto knižnica dodáva malý vstavaný postup plus švík backendu namiesto jedného monolitického kódovača. Vstavaný postup udržuje binárny súbor štíhlym a oslobodeným od licenčných záväzkov, zatiaľ čo švík umožňuje tímu, ktorý si licencoval plný kódovač, zapojiť ho bez toho, aby sa vôbec dotýkal vrstvy zápisu PDF

Čo možnosti kódovania skutočne obchodujú

Kódovanie sa konfiguruje cez TJBIG2EncodeOptions, záznam s poliami Lossless, UseGlobalSegments, UseSymbolDictionary a LossyLevel. Obal priateľský ku komponentom THPDFJBIG2Options zverejňuje Lossless, UseSymbolDictionary a LossyLevel, aby ich bolo možné nastaviť z Inšpektora objektov, a interne ich prevádza na záznam. Tri zámery riadia nastavenia

Bezstratová rekonštrukcia zachováva každý pixel. Nastavte Lossless na True a nechajte LossyLevel na nule a dekódovaná bitmapa bude bit za bitom identická so vstupom. Toto je jediná bezpečná voľba pre čiarové umenie, technické výkresy a akúkoľvek stránku, kde by chýbajúci pixel mohol zmeniť význam, napríklad podpis alebo pečiatka. Kódovanie slovníka symbolov zapína deduplikáciu s vedomosťou textu a je voľbou, ktorá odlišuje JBIG2 od faxových filtrov. Stratová úroveň, celé číslo od 0 do 9, umožňuje schopnému backendu obchodovať vernosť za veľkosť tým, že skoro identické značky považuje za rovnaký symbol. Nula znamená bezstratové. Vstavaný kódovač rešpektuje len bezstratový postup a ignoruje akúkoľvek nenulovú stratovú úroveň, takže vyššie úrovne sa uplatnia až po zaregistrovaní backendu, ktorý ich implementuje

var
  Options: TJBIG2EncodeOptions;
begin
  Options := DefaultJBIG2EncodeOptions;   // Lossless True, symbol dictionary on
  Options.Lossless := True;
  Options.LossyLevel := 0;                // 0 keeps every pixel
  Options.UseSymbolDictionary := True;    // dedupe repeated glyphs
  // Pass Options to a backend, or let THPDFJBIG2Options carry them.
end;

Slovníky symbolov a prečo naskenovaný text vyhráva

Stránka naskenovaného textu nie je naozaj obrázok slov. Je to to isté písmeno e vytlačené niekoľko stokrát, to isté t, tá istá čiarka — každá výskyt je mierne zašumená kópia jedného základného tvaru. Slovník symbolov zachytáva túto štruktúru. Kódovač zhromažďuje odlišné značky na stránke do slovníka, každý tvar uloží raz a potom zaznamená stránku ako zoznam pozícií odkazujúcich na záznamy slovníka. Tisíc výskytov toho istého glyfu stojí jednu uloženú bitmapu plus tisíc lacných umiestnení

Práve tu JBIG2 predbehne CCITT Group 4. Group 4 kóduje každý riadok skenu oproti riadku nad ním bez akéhokoľvek pojmu o glyfe, takže platí plnú cenu každého písmena zakaždým, keď sa písmeno objaví. JBIG2 zaplatí raz. Keď sa rovnaký slovník povýši na stream globálov na úrovni dokumentu, úspora sa znásobuje naprieč viacestránkovým skenovaním, pretože tvary zdieľané stránkou za stránkou sú uložené jedenkrát pre celý súbor. Pri hustom texte nie je rozdiel okrajový. To je dôvod, prečo JBIG2 existuje

Všeobecná oblasť a MMR pre všetko ostatné

Nie každý dvojúrovňový obrázok je text. Mapy, schémy, technické výkresy a zmiešané stránky obsahujú čiarové umenie, ktoré žiadny slovník nedokáže zhrnúť. Pre tieto prípady JBIG2 kóduje všeobecnú oblasť — obdĺžnik pixelov komprimovaný priamo bez akéhokoľvek trénovania symbolov. Norma umožňuje všeobecnej oblasti používať MMR, modifikované modifikované READ kódovanie, ktoré fax Group 4 už používa a ktoré modeluje každý riadok pixelov oproti riadku nad ním

Toto je postup, ktorý HotPDF dodáva vo svojom vstavanom kódovači. Keď nie je zaregistrovaný žiadny backend a požiadavka je bezstratová, knižnica komprimuje bitmapu ako jedinú MMR všeobecnú oblasť a zabalí ju do štruktúry segmentov JBIG2 požadovanej PDF profilom. Nepotrebuje žiadny slovník, žiadny tréningový prechod ani žiadny druhý obrázok na referenciu, takže je spoľahlivým predvoleným pre čiarové umenie a zmiešaný dvojúrovňový obsah. Na čistom texte sa nevyrovná plnému kódovaču so slovníkom symbolov, ale je vždy správny, vždy bezstratový a vždy prítomný. Povrch kódovača pre neho je jedno volanie

var
  Encoder: THPDFJBIG2Encoder;
  ImageData: TJBIG2ByteArray;
  Scanlines: TJBIG2ScanlineArray;  // one byte array per row, MSB-first
  W, H: Integer;
begin
  // Scanlines, W and H describe a 1-bit page; each row is (W + 7) div 8 bytes.
  Encoder := THPDFJBIG2Encoder.Create;
  try
    if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
      // ImageData now holds a JBIG2 stream ready for a /JBIG2Decode XObject.
      ;
  finally
    Encoder.Free;
  end;
end;

Zapnutie pri vytváraní dokumentu

Pri bežnom používaní sa triedy kódovača priamo nedotýkate. HotPDF sprístupňuje JBIG2 ako voľbu komprimácie obrázkov v dokumente. Enumerácia THPDFImageCompressionType zahŕňa icJBIG2 vedľa možností Flate, JPEG a CCITT, a dokument obsahuje vlastnosť JBIG2Options typu THPDFJBIG2Options, ktorá obsahuje nastavenia používané pri výbere tejto komprimácie. Nakonfigurujte oboje pred pridaním dvojúrovňových obrázkov, ktoré chcete takto komprimovať

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.ImageCompressionType := icJBIG2;     // route 1-bit images through JBIG2
    Pdf.JBIG2Options.Lossless := True;        // keep every pixel
    Pdf.JBIG2Options.UseSymbolDictionary := True;
    Pdf.JBIG2Options.LossyLevel := 0;
    // Add pages and place your scanned 1-bit images here.
  finally
    Pdf.Free;
  end;
end;

Jedna pohodlná funkcia, ktorú stojí za zmienku, je doplnok DBGridHotPDFExport, ktorý vykreslí TDBGrid priamo do PDF. Jeho výstup je prevažne dvojúrovňové čiary a text, takže dokument nakonfigurovaný pre JBIG2 udržiava tieto exporty kompaktné bez akéhokoľvek ďalšieho spracovania z vašej strany. Dve súvisiace témy na tomto blogu sa hlbšie venujú okolitému pracovnému postupu. Ako sa obrázky a písma ukladajú pri vytváraní zostáv nájdete v článku výstup zostavy s písomami a obrázkami v Delphi. Keď komprimovaný dokument musí spĺňať archivačný profil, pravidlá v článku validácia PDF/A, PDF/X a PDF/UA v Delphi vám povedia, ktoré filtre daná úroveň zhody akceptuje. JBIG2 je súčasťou HotPDF Component pre Delphi a C++Builder, vedľa rozhraní API pre načítanie, úpravu a šifrovanie, ktoré sú pokryté na iných miestach tu