Teknisk artikkel

HotPDF nedskaleringskjerner og utskriftsdithering

HotPDF eksponerer tre kjerner for bildenedskalering gjennom egenskapen ImageDownsampleKernel og et separat Floyd-Steinberg-trinn gjennom RenderOutputDither. Det første styrer hvordan fotografier ser ut etter at du har krympet dem for å treffe et størrelsesbudsjett, det andre styrer hvordan de ser ut etter at en side er redusert til svart-hvitt. Ingen av dem er på som standard, og begge er opt-in av samme grunn: de koster ekte tid

Presset som fører folk hit, er kjent. En skannet kontrakt på 60 MB må sendes gjennom en e-postgateway som avviser alt over 10 MB, eller en bunke med kontoutskrifter må lande på en fakslignende monokrom enhet som rendrer hver grå piksel som enten papir eller toner. Begge problemer er resamplingsproblemer, og begge har et raskt svar som ser dårlig ut og et sakte svar som ser riktig ut

Hva de tre kjernene egentlig skiller seg på

THPDFResampleKernel har tre verdier, og de ligger på genuint forskjellige punkter på fart- og kvalitetskurven. rkHalftone delegerer til den historiske GDI StretchBlt-veien med HALFTONE-modus, som til tross for navnet er bilinearklasse-filtrering: rask, adekvat for strektegninger og skjermbilder, og utsatt for de harde kantene du gjenkjenner umiddelbart på nedskalerte fotografier. rkBicubic kjører en separabel Catmull-Rom-kjerne, og rkLanczos3 kjører en separat windowed sinc med tre-lobe-støtte

Begge separable kjernene kjører som to gjennomløp, horisontalt så vertikalt, med 6 til 12 taps per destinasjonspiksel i ren Pascal. Det er omtrent en størrelsesorden tregere enn GDI-veien, noe som er nøyaktig grunnen til at rkHalftone forblir standard. På et nattlig parti av tusenvis av sider er forskjellen en planleggingsbeslutning, ikke en preferanse. På ett enkelt dokument en bruker venter på, er Lanczos3 nesten gratis og merkbar bedre

Vektkurvene til de tre HotPDF nedskaleringskjernene: rkHalftone delegerer til den bilinearklasse GDI HALFTONE-veien med støtte på én, rkBicubic kjører en separabel Catmull-Rom-kubikk med støtte på to, og rkLanczos3 kjører en windowed sinc med støtte på tre, og bytter omtrent en størrelsesorden i fart for merkbar bedre fotografier
De tre kjerneverdiene ligger på genuint forskjellige punkter på fart- og kvalitetskurven: en bilinearklasse GDI-vei, en Catmull-Rom-kubikk og en tre-lobe windowed sinc, og de separable kjernene normaliserer vekter slik at ingenting ringer forbi svart eller hvitt

To implementasjonsegenskaper er verdt å kjenne fordi de bestemmer hva utdataen kan og ikke kan gjøre. Kanter klemmes ved kantreplikering snarere enn innbrytning eller utfading, og vektene normaliseres per destinasjonspiksel. Sammen betyr de to at resultatet aldri ringer under svart eller over hvitt, så den klassiske Lanczos-overshoot-haloen rundt en hard kant dukker ikke opp som klippede artefakter i det kodede bildet

var
  Pdf: THotPDF;
  Info: THPDFLoadedResourceOptimizationInfo;
  Changed: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('scanned-contract.pdf');
    Pdf.ImageDownsampleKernel := rkLanczos3;   // sett før kallet
    Changed := Pdf.DownsampleLoadedImages(150, 82, 4096, Info);
    if Changed > 0 then
    begin
      Writeln('resampled images: ', Info.DownsampledImageCount);
      Writeln('kept calibrated : ', Info.PreservedCalibratedImageCount);
      Pdf.SaveToFile('scanned-contract-150dpi.pdf');
    end;
  finally
    Pdf.Free;
  end;
end;

Argumentet MinimumSavingsBytes, 4096 ovenfor, er vakten som holder operasjonen ærlig. Re-koding av et bilde som allerede var effektivt komprimert, kan gi en større strøm enn originalen, og en nedskalerer som blindt erstatter hvert bilde, vil av og til få filen den ble bedt om å krympe, til å vokse. Terskelen sier: bare forplikt erstatningen når den sparer minst dette antallet byte. PreservedCalibratedImageCount rapporterer den andre konservative beslutningen, bilder latt i fred fordi de bærer et kalibrert fargerom som resampling ville kompromittert

Hvorfor er en feil polynomkoeffisient så vanskelig å oppdage?

Fordi en ødelagt interpolasjonskjerne ikke krasjer eller kaster unntak, produserer den bare et bilde som ser subtilt galt ut på en måte ingen kan tilskrive noe. Catmull-Rom-kjernen er piecewise kubikk, og dens ytterste gren i nøstet Horner-form er ((-0.5t + 2.5)t - 4)t + 2. Skriv den midterste koeffisienten som -5 i stedet for -4, og funksjonen evaluerer fortsatt, returnerer fortsatt tall i et plausibelt område, og produserer fortsatt et bilde

Skaden viser seg som W(1) som evaluerer til -1 der den må være 0. Negative vekter akkumuleres, summen klippes ved null, og det synlige symptomet er en gradient hvis venstre ende blir svart og en sprangkant som mister sine mellomtoner. Ingenting i feilen peker på et polynom. Kontrollen som fanger det på sekunder, er aritmetikk snarere enn visuell: en interpolerende kjerne må tilfredsstille W(0) = 1 og W(±1) = W(±2) = 0, og enhver kjerne som bommer på de tre punktene, har en koeffisientfeil, punktum. Test på de tre verdiene i en enhetstest, og hele klassen av skrivefeildefekter forsvinner

Plott av HotPDF bicubic Catmull-Rom yttergren som viser hvorfor en feil koeffisient gjemmer seg: skrivefeilen som skriver -5 i stedet for -4 i den nøstede Horner-formen evaluerer fortsatt og etterlater W(1) på -1 og W(2) på -2 der null kreves, så å teste at W(0) er lik 1 pluss de to nullbetingelsene fanger det på sekunder
En ødelagt kjerne krasjer aldri, den returnerer bare tall som ser plausible ut, noe som er grunnen til at øyet ikke fanger en koeffisient-skrivefeil. W(0) = 1 med nuller på pluss og minus én og to er en enhetstest på tre linjer

Floyd-Steinberg-dithering, og hvor den hører hjemme i rørledningen

Dither-trinnet er et annet problem enn resampling og bor på et annet sted i rørledningen. RenderOutputDither anvender Floyd-Steinberg-feildiffusjon etter sidekomponering, noe som er den eneste plasseringen som gir mening for en monokrom utskriftsforhåndsvisning eller en fakslignende eksport: operasjonen handler om å redusere et ferdig raster til én bit per piksel, ikke om hvordan enkeltbilder ble skalert på veien inn

Algoritmen i seg selv er kort. Luminansen terskles ved 50 prosent, og kvantiseringsfeilen diffunderes til fire naboer med de klassiske vektene 7/16, 3/16, 5/16 og 1/16, mot høyre, under-venstre, under og under-høyre. Utdatapikselen er 0 eller 255 i hver kanal. Det det naive alternativet gir deg i stedet, en hard terskel uten diffusjon, forvandler et fotografi til en silhuett og mister hver mellomtone som bar innholdet

Rendringsrørledning-plassering av HotPDF Floyd-Steinberg-dithering: RenderOutputDither kjører etter sidekomponering på det ferdige 24-bits rasteret, terskler luminansen ved 50 prosent og diffunderer hver kvantiseringsfeil til høyre og under med vektene 7/16, 3/16, 5/16 og 1/16 gjennom en radbuffer som må akkumulere, og produserer énbits monokrom utdata
Dithering hører hjemme etter komponering fordi den reduserer et ferdig raster til én bit, ikke på grunn av hvordan bilder ble skalert. Diffusjonsvektene summerer til én, og radbufferen må akkumulere snarere enn overskrive
// Dithering ved rendring for en monokrom forhåndsvisningsenhet
Pdf.RenderOutputDither := True;

// Eller bruk samme trinn på en bitmap du allerede eier. Bitmapen må
// være pf24bit; funksjonen returnerer False i stedet for å gjette
if not HPDFFloydSteinbergDitherBitmap(Preview) then
  raise Exception.Create('dither expects a 24-bit bitmap');

// Direkte kjerne-tilgang når du resampler utenfor dokumentrørledningen
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
  Small.SaveToFile('thumb.bmp');
finally
  Small.Free;
end;

Det er én implementasjonsdetalj i feildiffusjon som biter alle én gang. Feilbufferen fra rad til rad må akkumulere. Hver piksel i neste rad mottar bidrag fra tre forskjellige piksler i gjeldende rad, tapene 3/16, 5/16 og 1/16, og hvis koden tilordner i stedet for å legge til, forkaster hver skriving det forrige bidraget, og bare siste tap overlever. Bildet ser fortsatt dithret ut, noe som er det som gjør det vanskelig å legge merke til, men teksturen er feil og tonalreproduksjonen driver. Testen som fanger det, er kvantitativ: dither et jevnt mellomgrått felt og krev at interiørdekningen lander mellom 40 og 60 prosent

Hvilken kombinasjon bør en størrelsesreduserende rørledning bruke?

Match kjernen mot hva bildene faktisk er, og behandle dithering som et enhetsanliggende snarere enn et kompresjonsanliggende. For fotografiske skanninger som må overleve et størrelsesbudsjett, holder rkLanczos3 ved 150 eller 200 DPI detaljene folk legger merke til, mens pikselantallet kuttes med en faktor fire eller mer. For skjermbilder, diagrammer og strektegninger er rkHalftone genuint fint og mye raskere, fordi de bildene har få tonale gradienter å bevare. For et blandet parti der du ikke kan inspisere hvert bilde, er rkBicubic det fornuftige midtpunktet: bedre enn bilinear, omtrent halvparten av tap-antallet til Lanczos3

Nedskalering er én spak blant flere, og den er ikke alltid den største. Bilevel-skanninger responderer vanligvis langt bedre på encoderen dekket i innfødt JBIG2 bilevel-kompresjon i Delphi, der gevinsten kommer fra symbolordbøker snarere enn pikselantall. Før du bestemmer deg, hjelper det å vite hva som faktisk er i filen, noe uttrekk av bilder og deres dekodefiltre er til for: et inventar av bildeobjekter og deres eksisterende kompresjon forteller deg om resampling har noe å hente

Hvis du bygger forhåndsvisningsflaten som viser resultatet, er det samme rendringsveien dokumentert i rendring av en PDF-side til en bitmap der RenderOutputDither virker, så den dithrede forhåndsvisningen og det dithrede utdataet kommer fra én kodevei snarere enn to implementasjoner som driver fra hverandre

Bredprinsippet bak begge funksjonene er at kvalitetsinnstillinger bør være eksplisitte og reversible. HotPDF beholder den historiske atferden som standard, slik at en eksisterende applikasjon oppgraderes uten en overraskende endring i utdata eller timing, og legger de penere, saktere veiene én egenskapstilordning unna. Begge er del av HotPDF Delphi PDF-komponent, ved siden av ressursoptimaliseringen og rendringsmaskineriet de bygger på