Technical Article

Indbygget JBIG2-komprimering af tonetryksbilleder i Delphi-PDF'er

Et scannet kontrakt er nogle hundrede punkter per tomme sort blæk på hvidt papir. Gemt som et en-bit-per-pixel-bitmap er det allerede lille, men hundrede sådanne sider gør stadig en PDF for stor til at sende med e-mail. Det rette filter ændrer regnestykket. JBIG2 er den højeste komprimeringsgrad, som ISO 32000-1 definerer for tonetryksbilleder, og på en stak scannet tekst halverer den rutinemæssigt det, CCITT Group 4 producerer. Dette er det filter, man griber efter, når inputtet er faxet, scannet eller på anden måde reduceret til to farver, og HotPDF kan skrive det direkte ind i en PDF

Formatet opnår komprimeringsgraden med to idéer, som en generisk billedcodec ikke har. Det modellerer, hvordan sorte streger sidder mod en hvid baggrund, og det bemærker, at en scannet side stort set er de samme få hundrede glyf-former, der gentages tusindvis af gange. At forstå begge dele er det, der lader dig vælge encode-mulighederne bevidst i stedet for at gætte dig frem

Hvor JBIG2 befinder sig i PDF-specifikationen

ISO 32000-1 opregner JBIG2Decode blandt stream-filtrene i §7.4.7, tilgængeligt fra PDF 1.4 og frem. Det gælder kun ét sted: billed-XObjects, hvis /BitsPerComponent er 1, og hvis farverum opløses til én kanal. Det er hele pointen. JBIG2 er en tonetrykcodec og konkurrerer aldrig med DCT eller JPXDecode på fotografier. Den konkurrerer med CCITTFaxDecode, Group 3- og Group 4-faxfiltrene, på præcis den type to-tones side, som en dokumentscanner producerer

Decoderen forbruger den indlejrede JBIG2-organisation, som standarden kalder PDF-profilen, hvor hver billedstream indeholder en sekvens af segmenter frem for en ren bitstream. En valgfri /JBIG2Globals-stream bærer segmenter, der deles på tværs af flere billeder i samme dokument, hvilket er mekanismen, der lader gentagende indhold lagres én gang for en hel fil frem for én gang per side. HotPDF udsender per-billede-streamen som standard og holder globals-kanalen fri, medmindre en backend anmoder om den

Backend-first encoder-arkitektur

En komplet JBIG2-encoder er et stort stykke software, og de mest aggressive dele har historisk set været belastet af patenter og leveret under licenser, der ikke passer til ethvert produkt. HotPDF løser denne spænding ved at adskille grænsefladen fra motoren. Enheden HPDFJBIG2 definerer de kald, resten af biblioteket foretager, og den leveres med en beskeden indbygget encoder, så JBIG2 fungerer ud af boksen. Når du har brug for produktionsgodkendte komprimeringsgrader, registrerer du en stærkere motor, og biblioteket delegerer til den uden ændringer i din kaldekode

Skiftet er ét enkelt registreringskald. Uden en registreret backend falder encoderen tilbage til sin indbyggede sti. Registrer én, og al efterfølgende kodning kører igennem 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 krog findes til dekodning via RegisterJBIG2DecoderBackend, med IsJBIG2DecoderBackendAvailable til at sondere den. Det er grunden til, at et bibliotek leveres med en lille indbygget sti plus en backend-sømforbindelse frem for én monolitisk encoder. Den indbyggede sti holder den binære fil slank og fri for licensproblemer, mens sømmen lader et team, der har licenseret en fuld encoder, tilslutte den uden at røre PDF-skrivningslaget overhovedet

Hvad encode-mulighederne faktisk afvejer

Kodning konfigureres via TJBIG2EncodeOptions, en record med felterne Lossless, UseGlobalSegments, UseSymbolDictionary og LossyLevel. Den komponentvenlige wrapper THPDFJBIG2Options udgiver Lossless, UseSymbolDictionary og LossyLevel, så de kan indstilles fra Object Inspector, og den konverterer internt til recorden. Tre hensigter styrer indstillingerne

Tabsfri rekonstruktion bevarer alle pixels. Sæt Lossless til True og lad LossyLevel stå på nul, og det dekodede bitmap er bit-for-bit identisk med inputtet. Dette er det eneste sikre valg til linjekunst, tekniske tegninger og enhver side, hvor en tabt pixel kan ændre betydningen, for eksempel en underskrift eller et stempel. Symbol-ordbogskodning aktiverer tekstbevidst deduplikering og er den mulighed, der adskiller JBIG2 fra faxfiltrene. Det tabsgivende niveau, et heltal fra 0 til 9, lader en dygtig backend bytte troskab mod størrelse ved at behandle næsten identiske mærker som det samme symbol. Nul betyder tabsfri. Den indbyggede encoder respekterer kun den tabsfrie sti og ignorerer ethvert ikke-nul tabsgivende niveau, så de højere niveauer kun træder i kraft, når en backend, der implementerer dem, er registreret

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øger og hvorfor tekstscans vinder

En side med scannet tekst er ikke rigtig et billede af ord. Det er det samme bogstav e trykt flere hundrede gange, det samme t, det samme komma, hver forekomst en lidt støjfyldt kopi af én underliggende form. En symbolordbog fanger den struktur. Encoderen samler de distinkte mærker på siden i en ordbog, gemmer hver form én gang og registrerer derefter siden som en liste over positioner, der refererer til ordbogsposter. Et tusinde forekomster af det samme glyf koster ét gemt bitmap plus et tusinde billige placeringer

Det er præcis her, JBIG2 overhaler CCITT Group 4. Group 4 koder hver scanlinje mod linjen ovenfor uden nogen forestilling om et glyf, så den betaler den fulde pris for hvert bogstav, hver gang bogstavet vises. JBIG2 betaler én gang. Når den samme ordbog promoveres til dokumentniveauets globals-stream, sammensættes besparelsen på tværs af en flersidet scanning, fordi formerne, der deles side for side, gemmes én enkelt gang for hele filen. For tæt tekst er forskellen ikke marginal. Det er grunden til, at JBIG2 eksisterer

Generisk region og MMR til alt andet

Ikke ethvert tonetryksbillede er tekst. Kort, diagrammer, ingeniørtegninger og blandede sider har linjekunst, som ingen ordbog kan opsummere. Til disse koder JBIG2 en generisk region, et rektangel af pixels komprimeret direkte uden nogen symboltræning. Standarden tillader en generisk region at bruge MMR, den modificerede READ-kodning, som Group 4-fax allerede bruger, og som modellerer hver pixelrækker mod rækken ovenfor

Dette er den sti, HotPDF leverer med sin indbyggede encoder. Når ingen backend er registreret, og anmodningen er tabsfri, komprimerer biblioteket bitmapfilen som én enkelt MMR-generisk region og pakker den ind i den JBIG2-segmentstruktur, som PDF-profilen kræver. Den behøver ingen ordbog, ingen træningsgennemgang og intet andet billede at referere til, så det er standardvalget for linjekunst og blandet tonetryksinhold. Den matcher ikke en fuld symbolordbogs-encoder på ren tekst, men den er altid korrekt, altid tabsfri og altid til stede. Encoder-overfladen for den er ét kald

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;

Aktivering ved dokumentopbygning

Til daglig brug rører du ikke encoder-klassen direkte. HotPDF eksponerer JBIG2 som et billedkomprimeringsvalg på dokumentet. Optællingen THPDFImageCompressionType inkluderer icJBIG2 ved siden af Flate-, JPEG- og CCITT-mulighederne, og dokumentet bærer en JBIG2Options-egenskab af typen THPDFJBIG2Options, der indeholder de indstillinger, der bruges, når den komprimering er valgt. Konfigurer begge, inden du tilføjer de tonetryksbilleder, du ønsker komprimeret på denne måde

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;

Et praktisk hjælpemiddel er DBGridHotPDFExport-tilføjelsen, som gengiver en TDBGrid direkte til en PDF. Dens output er overvejende tonetryksmønstre og tekst, så et dokument konfigureret til JBIG2 holder disse eksporter kompakte uden ekstra håndtering fra din side. To relaterede emner på denne blog går dybere ned i den omgivende arbejdsgang. For information om, hvordan billeder og skrifttyper placeres, når du bygger rapporter, se rapportoutput med skrifttyper og billeder i Delphi. Når et komprimeret dokument skal opfylde en arkiveringsprofil, fortæller reglerne i PDF/A-, PDF/X- og PDF/UA-validering i Delphi dig, hvilke filtre et givet overensstemmelsesniveau accepterer. JBIG2 leveres som del af HotPDF Component til Delphi og C++Builder, ved siden af de indlæsnings-, redigerings- og krypteringsAPI'er, der er dækket andetsteds her