Technical Article

Gimtoji JBIG2 dviejų lygių vaizdų kompresija Delphi PDF failuose

Nuskaityta sutartis yra kelių šimtų taškų colyje juodo rašalo ant balto popieriaus. Išsaugota kaip vieno bito pikselyje rastrinis vaizdas, ji jau yra nedidelė, tačiau šimtas tokių puslapių vis tiek išpučia PDF failą tiek, kad jo nebeįmanoma išsiųsti el. paštu. Tinkamas filtras pakeičia šią aritmetiką. JBIG2 yra aukščiausio suspaudimo laipsnio algoritmas, kurį ISO 32000-1 apibrėžia dviejų lygių vaizdams, ir nuskaityto teksto krūvoje jis paprastai perpus sumažina CCITT Group 4 kuriamą dydį. Tai filtras, kurį reikėtų rinktis, kai įvestis yra faksuota, nuskaityta ar kitaip sumažinta iki dviejų spalvų, o HotPDF gali jį tiesiogiai įrašyti į PDF

Formatas pasiekia tokį santykį dėl dviejų idėjų, kurių neturi įprasti vaizdų kodekai. Jis modeliuoja, kaip juodos zonos išsidėsto baltame fone, ir pastebi, kad nuskaitytame puslapyje dažniausiai tūkstančius kartų kartojasi tos pačios kelios dešimtys glifų formų. Supratimas abiejų šių aspektų leidžia sąmoningai pasirinkti kodavimo parinktis, o ne spėlioti

Kur JBIG2 yra PDF specifikacijoje

ISO 32000-1 išvardija JBIG2Decode tarp srauto filtrų §7.4.7 skyriuje, prieinamų nuo PDF 1.4 versijos. Tai taikoma tik vienoje vietoje: vaizdų XObjects, kurių /BitsPerComponent yra 1 ir kurių spalvų erdvė susiveda į vieną kanalą. Tai ir yra esmė. JBIG2 yra dviejų lygių kodekas, todėl jis niekada nekonkuruoja su DCT ar JPXDecode apdorojant nuotraukas. Jis konkuruoja su CCITTFaxDecode, Group 3 ir Group 4 faksų filtrais, apdorojant būtent tokius dviejų atspalvių puslapius, kokius sukuria dokumentų skaitytuvai

Dekoduotojas naudoja įterptą JBIG2 organizaciją, kurią standartas vadina PDF profiliu, kur kiekvienas vaizdo srautas laiko segmentų seką, o ne gryną bitų srautą. Pasirenkamas /JBIG2Globals srautas neša segmentus, kuriais dalijamasi keliuose to paties dokumento vaizduose. Tai mechanizmas, leidžiantis pasikartojantį turinį išsaugoti vieną kartą visam failui, o ne kartą kiekvienam puslapiui. HotPDF pagal nutylėjimą generuoja kiekvieno vaizdo srautą, o globalųjį kanalą palieka laisvą, nebent koduotuvo modulis jo paprašo

Moduliais paremta koduotuvo architektūra

Išsamus JBIG2 koduotuvas yra didelė programinė įranga, o agresyviausios jo dalys istoriškai buvo apsunkintos patentais ir platinamos pagal licencijas, kurios tinka ne kiekvienam produktui. HotPDF išsprendžia šią įtampą atskirdamas sąsają nuo variklio. Modulis HPDFJBIG2 apibrėžia iškvietimus, kuriuos atlieka likusi bibliotekos dalis, ir pateikia kuklų įmontuotą koduotuvą, kad JBIG2 veiktų be papildomos konfigūracijos. Kai prireikia gamybinio lygio suspaudimo santykių, registruojate stipresnį variklį, ir biblioteka perduoda darbą jam, nepakeisdama jūsų iškvietimo kodo

Perjungimas yra vienas registracijos iškvietimas. Neįregistravus jokio modulio, koduotuvas naudoja savo įmontuotą kelią. Užregistruokite jį, ir kiekvienas tolesnis kodavimas bus atliekamas per jį

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;

Tokia pati jungtis egzistuoja ir dekodavimui per RegisterJBIG2DecoderBackend, kartu su IsJBIG2DecoderBackendAvailable jam patikrinti. Būtent todėl biblioteka pateikia nedidelį įmontuotą kelią ir modulių jungtį, o ne vieną monolitinį koduotuvą. Įmontuotas kelias išlaiko sukompiliuotą kodą lengvą ir be licencinių suvaržymų, o jungtis leidžia komandai, turinčiai pilno koduotuvo licenciją, jį prijungti visiškai neliečiant PDF rašymo sluoksnio

Ką iš tikrųjų keičia kodavimo parinktys

Kodavimas konfigūruojamas per TJBIG2EncodeOptions, įrašą (record) su laukais Lossless, UseGlobalSegments, UseSymbolDictionary ir LossyLevel. Komponentams pritaikytas apvalkalas THPDFJBIG2Options viešai pateikia Lossless, UseSymbolDictionary ir LossyLevel, kad juos būtų galima nustatyti iš Object Inspector, ir viduje konvertuoja juos į įrašą. Nustatymus lemia trys ketinimai

Atkuriant be nuostolių (lossless), išsaugomas kiekvienas pikselis. Nustatykite Lossless į True ir palikite LossyLevel lygų nuliui, ir dekoduotas rastrinis vaizdas bus identiškas originalui bitas į bitą. Tai vienintelis saugus pasirinkimas vektorinei grafikai (line art), techniniams brėžiniams ir bet kuriam puslapiui, kur prarastas pikselis galėtų pakeisti prasmę, pavyzdžiui, parašui ar antspaudui. Kodavimas naudojant simbolių žodyną įjungia teksto pasikartojimų šalinimą ir yra parinktis, atskirianti JBIG2 nuo faksų filtrų. Nuostolių lygis (lossy level), sveikasis skaičius nuo 0 iki 9, leidžia pajėgiam kodavimo moduliui aukoti tikslumą dėl dydžio, traktuojant beveik identiškas žymes kaip tą patį simbolį. Nulis reiškia, kad nuostolių nėra. Įmontuotas koduotuvas atsižvelgia tik į kelią be nuostolių ir ignoruoja bet kokį nelygų nuliui nuostolių lygį, todėl aukštesni lygiai įsigalioja tik užregistravus juos palaikantį modulį

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;

Simbolių žodynai ir kodėl teksto nuskaitymai yra pranašesni

Nuskaityto teksto puslapis iš tikrųjų nėra žodžių vaizdas. Tai ta pati raidė e, atspausdinta kelis šimtus kartų, ta pati t, tas pats kablelis – kiekvienas atvejis yra šiek tiek triukšminga vienos pagrindinės formos kopija. Simbolių žodynas užfiksuoja šią struktūrą. Koduotuvas surenka unikalias puslapio žymes į žodyną, kiekvieną formą išsaugo vieną kartą, o tada užrašo puslapį kaip pozicijų, nurodančių žodyno įrašus, sąrašą. Tūkstantis to paties glifo pasikartojimų kainuoja vieną išsaugotą rastrinį vaizdą ir tūkstantį pigių išdėstymų

Būtent čia JBIG2 išsiveržia į priekį prieš CCITT Group 4. Group 4 koduoja kiekvieną nuskaitymo eilutę lyginant su aukščiau esančia eilute, neturėdamas glifo sampratos, todėl jis sumoka visą kainą už kiekvieną raidę kiekvieną kartą, kai toji raidė atsiranda. JBIG2 sumoka vieną kartą. Kai tas pats žodynas perkeliamas į dokumento lygio globalųjį srautą, sutaupymas sumuojasi per kelių puslapių nuskaitymą, nes formos, kuriomis dalijasi puslapis po puslapio, visam failui išsaugomos vieną kartą. Esant tankiam tekstui, skirtumas nėra mažas. Tai yra priežastis, dėl kurios JBIG2 egzistuoja

Bendrinis regionas ir MMR visam kitam

Ne kiekvienas dviejų lygių vaizdas yra tekstas. Žemėlapiai, schemos, inžineriniai brėžiniai ir mišrūs puslapiai turi vektorinę grafiką (line art), kurios joks žodynas negali apibendrinti. Tokiems atvejams JBIG2 koduoja bendrinį regioną – pikselių stačiakampį, suspaudžiamą tiesiogiai, be jokio simbolių mokymo. Standartas leidžia bendriniam regionui naudoti MMR (modifikuotą modifikuotą READ kodavimą), kurį jau naudoja Group 4 faksas, modeliuojantį kiekvieną pikselių eilutę pagal aukščiau esančią eilutę

Būtent tokį kelią HotPDF pateikia savo įmontuotame koduotuve. Kai nėra užregistruoto modulio ir prašymas yra koduoti be nuostolių, biblioteka suspaudžia rastrinį vaizdą kaip vieną MMR bendrinį regioną ir apgaubia jį JBIG2 segmentų struktūra, kurios reikalauja PDF profilis. Jam nereikia jokio žodyno, jokio mokymo praėjimo ir jokio antro vaizdo nuorodai, todėl tai yra patikimas numatytasis nustatymas vektorinei grafikai ir mišriam dviejų lygių turiniui. Jis neprilygs pilnam simbolių žodyno koduotuvui gryname tekste, tačiau jis visada yra teisingas, visada be nuostolių ir visada prieinamas. Jam skirtas koduotuvo interfeisas tėra vienas iškvietimas

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;

Jo įjungimas kuriant dokumentą

Kasdieniam naudojimui koduotuvo klasės tiesiogiai neliesti nereikia. HotPDF pateikia JBIG2 kaip vaizdų kompresijos pasirinkimą dokumente. Išvardijimas THPDFImageCompressionType apima icJBIG2 kartu su Flate, JPEG ir CCITT parinktimis, o dokumentas turi THPDFJBIG2Options tipo savybę JBIG2Options, kurioje saugomi nustatymai, naudojami pasirinkus šią kompresiją. Sukonfigūruokite abu prieš pridėdami dviejų lygių vaizdus, kuriuos norite taip suspausti

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;

Vienas paminėtinas patogumas yra DBGridHotPDFExport priedas, kuris vizualizuoja TDBGrid tiesiai į PDF. Jo išvestis dažniausiai yra dviejų lygių linijos ir tekstas, todėl dokumentas sukonfigūruotas naudoti JBIG2 išlaiko tokius eksportus kompaktiškus be jokio papildomo jūsų įsikišimo. Dvi susijusios temos šiame tinklaraštyje giliau panagrinėja supančią darbo eigą. Apie tai, kaip išdėstomi vaizdai ir šriftai kuriant ataskaitas, skaitykite apie ataskaitų išvestį su šriftais ir vaizdais Delphi programose. Kai suspaustas dokumentas turi atitikti archyvavimo profilį, taisyklės, pateiktos straipsnyje PDF/A, PDF/X ir PDF/UA validacija Delphi aplinkoje, nurodo, kuriuos filtrus priima konkretus atitikties lygis. JBIG2 pateikiamas kaip HotPDF Component, skirto Delphi ir C++Builder, dalis, kartu su įkėlimo, redagavimo ir šifravimo API, aptartais kitur