Teknisk artikkel

Innebygd JBIG2 to-nivå bildekomprimering i Delphi PDF-er

En skannet kontrakt er noen hundre punkter per tomme med svart blekk på hvitt papir. Lagret som en en-bit-per-piksel-bitmappe er den allerede liten, men hundre slike sider vil likevel blåse opp en PDF forbi alt du ville sendt på e-post. Det riktige filteret endrer aritmetikken. JBIG2 er komprimeringen med høyest forhold som ISO 32000-1 definerer for to-nivå-bilder, og på en stabel med skannet tekst halverer den rutinemessig det CCITT Group 4 produserer. Dette er filteret du bør strekke deg etter når inndataene er fakset, skannet eller på annen måte redusert til to farger, og HotPDF kan skrive det direkte inn i en PDF

Formatet fortjener forholdet med to ideer som en generisk bildekodek ikke har. Det modellerer hvordan svarte streker sitter mot en hvit bakgrunn, og det legger merke til at en skannet side for det meste er de samme noen hundre glyffformene gjentatt tusenvis av ganger. Å forstå begge deler er det som lar deg velge kodingsalternativene bevisst i stedet for å gjette

Hvor JBIG2 sitter i PDF-spesifikasjonen

ISO 32000-1 lister opp JBIG2Decode blant strømfiltrene i §7.4.7, tilgjengelig fra PDF 1.4 og utover. Det gjelder kun ett sted: bilde-XObjects hvis /BitsPerComponent er 1 og hvis fargerom løses til en enkelt kanal. Det er hele poenget. JBIG2 er en to-nivå-kodek, så den konkurrerer aldri med DCT eller JPXDecode på fotografier. Den konkurrerer med CCITTFaxDecode, Group 3- og Group 4-faksfiltrene, på nøyaktig den typen tofargesider som en dokumentskanner produserer

Dekoderen konsumerer den innebygde JBIG2-organiseringen som standarden kaller PDF-profilen, der hver bildestrøm inneholder en sekvens av segmenter i stedet for en naken bitstrøm. En valgfri /JBIG2Globals-strøm bærer segmenter som deles på tvers av flere bilder i det samme dokumentet, som er mekanismen som lar gjentatt innhold lagres én gang for en hel fil i stedet for én gang per side. HotPDF sender ut per-bilde-strømmen som standard og holder den globale kanalen ledig med mindre en serverdel ber om den

Serverdel-først-koderarkitekturen

En komplett JBIG2-koder er et stort stykke programvare, og de mest aggressive delene av den har historisk sett vært beheftet med patenter og levert under lisenser som ikke passer for alle produkter. HotPDF løser denne spenningen ved å separere grensesnittet fra motoren. Enheten HPDFJBIG2 definerer kallene som resten av biblioteket gjør, og den leveres med en beskjeden innebygd koder slik at JBIG2 fungerer ut av boksen. Når du trenger forhold av produksjonskvalitet, registrerer du en sterkere motor, og biblioteket delegerer til den, uten endringer i den kallende koden din

Bryteren er et enkelt registreringskall. Uten noen registrert serverdel faller koderen tilbake til sin innebygde bane. Registrer én, og hver påfølgende koding kjører gjennom den

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;

Den samme kroken eksisterer for dekoding gjennom RegisterJBIG2DecoderBackend, med IsJBIG2DecoderBackendAvailable for å undersøke den. Dette er grunnen til at et bibliotek leveres med en liten innebygd bane pluss en serverdelsøm i stedet for én monolittisk koder. Den innebygde banen holder den binære filen slank og fri for lisensforviklinger, mens sømmen lar et team som har lisensiert en full koder koble den til uten å røre PDF-skrivelaget i det hele tatt

Hva kodingsalternativene faktisk bytter

Koding konfigureres gjennom TJBIG2EncodeOptions, en post med feltene Lossless, UseGlobalSegments, UseSymbolDictionary og LossyLevel. Den komponentvennlige innpakningen THPDFJBIG2Options publiserer Lossless, UseSymbolDictionary og LossyLevel slik at de kan settes fra Object Inspector, og den konverterer til posten internt. Tre hensikter driver innstillingene

Tapsfri gjenoppbygging beholder hver piksel. Sett Lossless til True og la LossyLevel være på null, og den dekodede bitmappen er bit-for-bit identisk med inndataene. Dette er det eneste trygge valget for strektegninger, tekniske tegninger og enhver side der en mistet piksel kan endre mening, for eksempel en signatur eller et stempel. Symbol-ordbok-koding slår på tekstbevisst deduplisering og er alternativet som skiller JBIG2 fra faksfiltrene. Tapsnivået, et heltall fra 0 til 9, lar en kapabel serverdel bytte troskap mot størrelse ved å behandle nesten identiske merker som det samme symbolet. Null betyr tapsfri. Den innebygde koderen respekterer bare den tapsfrie banen og ignorerer ethvert tapsnivå ulikt null, så de høyere nivåene trer i kraft først når en serverdel som implementerer dem, er registrert

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;

Symbolordbøker og hvorfor tekstskanninger vinner

En side med skannet tekst er egentlig ikke et bilde av ord. Det er den samme bokstaven e trykt flere hundre ganger, den samme t, det samme kommaet, hver forekomst en litt støyende kopi av en underliggende form. En symbolordbok fanger opp den strukturen. Koderen samler de distinkte merkene på siden i en ordbok, lagrer hver form én gang, og registrerer deretter siden som en liste med posisjoner som refererer til ordbokoppføringer. Tusen forekomster av den samme glyffen koster én lagret bitmappe pluss tusen billige plasseringer

Dette er nettopp der JBIG2 trekker fra CCITT Group 4. Group 4 koder hver skannelinje mot linjen over den uten noen anelse om en glyff, så den betaler den fulle kostnaden for hver bokstav hver gang bokstaven vises. JBIG2 betaler én gang. Når den samme ordboken forfremmes til strømmen på dokumentnivå for globale variabler, bygger besparelsen seg opp over en flersidig skanning, fordi formene som deles av side etter side, lagres én enkelt gang for hele filen. På tett tekst er ikke forskjellen marginal. Det er grunnen til at JBIG2 eksisterer

Generisk region og MMR for alt annet

Ikke alle to-nivå-bilder er tekst. Kart, skjemaer, tekniske tegninger og blandede sider har strektegninger som ingen ordbok kan oppsummere. For de tilfellene koder JBIG2 en generisk region, et rektangel av piksler komprimert direkte uten noen symboltrening. Standarden tillater at en generisk region bruker MMR, den modifiserte modifiserte READ-kodingen som Group 4-faks allerede bruker, som modellerer hver rad med piksler mot raden over den

Dette er banen HotPDF leverer i sin innebygde koder. Når ingen serverdel er registrert og forespørselen er tapsfri, komprimerer biblioteket bitmappen som en enkelt MMR generisk region og pakker den inn i JBIG2-segmentstrukturen som PDF-profilen krever. Den trenger ingen ordbok, ingen treningsgjennomgang og ingen andre bilder å referere til, så den er den pålitelige standarden for strektegninger og blandet to-nivå-innhold. Den vil ikke matche en full symbol-ordbok-koder på ren tekst, men den er alltid riktig, alltid tapsfri og alltid til stede. Koder-overflaten for den er ett kall

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;

Slå den på når du bygger et dokument

For daglig bruk rører du ikke koder-klassen direkte. HotPDF avslører JBIG2 som et bildekomprimeringsvalg på dokumentet. Opplistingen THPDFImageCompressionType inkluderer icJBIG2 ved siden av Flate-, JPEG- og CCITT-alternativene, og dokumentet bærer en JBIG2Options-egenskap av typen THPDFJBIG2Options som inneholder innstillingene som brukes når den komprimeringen velges. Konfigurer begge deler før du legger til to-nivå-bildene du vil ha komprimert på denne måten

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;

En bekvemmelighet verdt å merke seg er DBGridHotPDFExport-tillegget, som gjengir en TDBGrid rett til en PDF. Utdataene derfra er i stor grad to-nivå-linjer og tekst, så et dokument konfigurert for JBIG2 holder disse eksportene kompakte uten ekstra håndtering fra din side. To relaterte emner på denne bloggen går dypere inn i den omkringliggende arbeidsflyten. For hvordan bilder og skrifter legges ned når du bygger rapporter, se rapportutdata med skrifter og bilder i Delphi. Når et komprimert dokument må tilfredsstille en arkivprofil, forteller reglene i validering av PDF/A, PDF/X og PDF/UA i Delphi deg hvilke filtre et gitt samsvarsnivå aksepterer. JBIG2 leveres som en del av HotPDF Component for Delphi og C++Builder, ved siden av API-ene for innlasting, redigering og kryptering som dekkes andre steder her