Odborný článok

Downsampling kernele v HotPDF a dithering pri tlači

HotPDF vystavuje tri kernele na downscaling obrázkov cez vlastnosť ImageDownsampleKernel a osobitný Floyd-Steinberg prechod cez RenderOutputDither. Ten prvý riadi, ako vyzerajú fotografie potom, čo ich zmenšíte, aby ste sa zmestili do rozpočtu veľkosti, ten druhý riadi, ako vyzerajú potom, čo sa strana zredukuje na čierno-bielo. Ani jeden nie je zapnutý defaultne a oba sú opt-in z toho istého dôvodu: stoja reálny čas

Tlak, ktorý sem ľudí privádza, je známy. Naskenovaná zmluva s 60 MB musí vyjsť cez emailovú bránu, ktorá odmietne všetko nad 10 MB, alebo dávka výpisov musí dopadnúť na monochromatické zariadenie faxového typu, ktoré vykreslí každý sivý pixel buď ako papier, alebo ako toner. Oba problémy sú problémy resamplovania a oba majú rýchlu odpoveď, ktorá vyzerá zle, a pomalú odpoveď, ktorá vyzerá správne

V čom sa tri kernele reálne líšia

THPDFResampleKernel má tri hodnoty a stoja na reálne odlišných miestach krivky rýchlosť a kvalita. rkHalftone deleguje na historickú GDI cestu StretchBlt s režimom HALFTONE, ktorá napriek názvu je filtrovanie triedy bilinear: rýchla, postačujúca pre line art a screenshoty a náchylná na tie drsné hrany, ktoré spoznáte okamžite na zmenšených fotografiách. rkBicubic beží so separovateľným kernelom Catmull-Rom a rkLanczos3 beží so separovateľným okienkovaným sinc s podporou troch lalokov

Oba separovateľné kernele bežia ako dva prechody, najprv vodorovný, potom zvislý, s 6 až 12 tapmi na cieľový pixel v čistom Pascale. To je zhruba o rad pomalšie než GDI cesta a presne preto rkHalftone zostáva defaultom. V nočnej dávke tisícok strán je rozdiel rozhodnutím o plánovaní, nie preferenciou. Pri jedinom dokumente, na ktorý používateľ čaká, je Lanczos3 takmer zadarmo a viditeľne lepší

Krivky váh troch kernelov HotPDF na downscaling: rkHalftone deleguje na GDI cestu HALFTONE triedy bilinear s podporou jedna, rkBicubic beží so separovateľnou kubikou Catmull-Rom s podporou dva a rkLanczos3 beží s okienkovaným sinc s podporou tri, pričom obetuje zhruba jeden rad rýchlosti za viditeľne lepšie fotografie
Tri hodnoty kernelov stoja na reálne odlišných miestach krivky rýchlosť a kvalita: GDI cesta triedy bilinear, kubika Catmull-Rom a okienkovaný sinc s troma lalokmi a separovateľné kernele normalizujú váhy, takže nič nezvoní za čiernou alebo bielou

Dve implementačné vlastnosti stoja za poznanie, lebo určujú, čo výstup dokáže a čo nedokáže. Okraje sa upínajú replikáciou hrany namiesto zavinutia alebo blednutia a váhy sa normalizujú na každý cieľový pixel. Tieto dve veci spolu znamenajú, že výsledok nikdy nezvoní pod čiernou alebo nad bielou, takže klasická Lanczos prestreľovacia aura okolo tvrdej hrany sa neobjaví ako orezané artefakty v zakódovanom obrázku

var
  Pdf: THotPDF;
  Info: THPDFLoadedResourceOptimizationInfo;
  Changed: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('scanned-contract.pdf');
    Pdf.ImageDownsampleKernel := rkLanczos3;   // nastav pred volaním
    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;

Argument MinimumSavingsBytes, vyššie 4096, je ochrana, ktorá drží operáciu poctivú. Znovu zakódovať obrázok, ktorý už bol efektívne komprimovaný, môže vyprodukovať väčší stream než originál a downscaler, ktorý zaslepo nahrádza každý obrázok, občas zväčší súbor, ktorý mal zmenšiť. Táto prahová hodnota hovorí: potvrď náhradu len vtedy, keď ušetrí aspoň toľko bajtov. PreservedCalibratedImageCount hlási druhé konzervatívne rozhodnutie, obrázky ponechané nedotknuté, pretože nesú kalibrovaný farebný priestor, ktorý by resampling skompromitoval

Prečo je zlý polynomický koeficient taký ťažko postrehnuteľný?

Pretože pokazený interpolačný kernel nespadne ani nehodí výnimku, len vyprodukuje obrázok, ktorý vyzerá jemne zle spôsobom, ktorý nikto nepriradí. Kernel Catmull-Rom je po častiach kubický a jeho vonkajšia vetva vo vnorenom Hornerovom tvare je ((-0.5t + 2.5)t - 4)t + 2. Napíšte ten prostredný koeficient ako -5 namiesto -4 a funkcia stále vyhodnocuje, stále vracia čísla v plausible rozsahu a stále produkuje obrázok

Škoda sa ukáže ako W(1) vyhodnocujúce sa na -1, kde musí byť 0. Záporné váhy sa hromadia, suma sa oreže na nulu a viditeľným príznakom je gradient, ktorého ľavý koniec sčernie, a skoková hrana, ktorá stratí svoje medzitóny. Nič v zlyhaní neukazuje na polynóm. Kontrola, ktorá to chytí za sekundy, je aritmetická, nie vizuálna: interpolačný kernel musí spĺňať W(0) = 1 a W(±1) = W(±2) = 0 a každý kernel, ktorý míňa tieto tri body, má chybu v koeficiente, bodka. Tvrďte tieto tri hodnoty v unit teste a celá trieda preklepových defektov zmizne

Graf vonkajšej vetvy bicubic Catmull-Rom v HotPDF ukazujúci, prečo sa zlý koeficient skrýva: preklep píšuci -5 namiesto -4 vo vnorenom Hornerovom tvare stále vyhodnocuje a necháva W(1) na -1 a W(2) na -2, kde je nutná nula, takže tvrdenie W(0) rovná sa 1 plus dve nulové obmedzenia to chytí za sekundy
Pokazený kernel nikdy nespadne, len vracia čísla pôsobiace plausible, a preto oko nechytí preklep v koeficiente. W(0) = 1 s nulami v plus a mínus jedna a dva je trojriadkový unit test

Dithering Floyd-Steinberg a kde patrí do pipeline

Dither prechod je iný problém než resampling a býva na inom mieste pipeline. RenderOutputDither aplikuje error diffusion Floyd-Steinberg po zložení strany, čo je jediné umiestnenie, ktoré dáva zmysel pre monochromatický tlačový náhľad alebo export faxového typu: operácia je o redukcii hotového rastra na jeden bit na pixel, nie o tom, ako boli jednotlivé obrázky zmenšené na ceste dnu

Algoritmus sám je krátky. Luminancia sa prahuje na 50 percent a kvantizačná chyba sa difunduje štyrom susedom s klasickými váhami 7/16, 3/16, 5/16 a 1/16, doprava, doľava dole, dole a doprava dole. Výstupný pixel je 0 alebo 255 v každom kanáli. Naivná alternatíva vám namiesto toho, tvrdý prah bez difúzie, zmení fotografiu na siluetu a stratí každý poltón, ktorý niesol obsah

Umiestnenie v render pipeline ditheringu Floyd-Steinberg v HotPDF: RenderOutputDither beží po zložení strany na hotovom 24-bitovom rastre, prahuje luminanciu na 50 percent a difunduje každú kvantizačnú chybu doprava a dole s váhami 7/16, 3/16, 5/16 a 1/16 cez riadkový buffer, ktorý musí akumulovať, a produkuje jednobitový monochromatický výstup
Dithering patrí po zložení, pretože redukuje hotový raster na jeden bit, nie kvôli tomu, ako boli obrázky zmenšené. Difúzne váhy sa sčítajú na jednu a riadkový buffer musí akumulovať, nie prepisovať
// Dithering pri vykresľovaní pre monochromatické náhľadové zariadenie
Pdf.RenderOutputDither := True;

// Alebo aplikujte ten istý prechod na bitmapu, ktorú už máte. Bitmapa
// musí byť pf24bit; funkcia vráti False namiesto hádania
if not HPDFFloydSteinbergDitherBitmap(Preview) then
  raise Exception.Create('dither expects a 24-bit bitmap');

// Priamy prístup ku kernelu, keď resamplujete mimo dokumentovej pipeline
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
  Small.SaveToFile('thumb.bmp');
finally
  Small.Free;
end;

V error diffusion je jeden implementačný detail, ktorý každého raz zahryzne. Buffer chýb medzi riadkami musí akumulovať. Každý pixel v ďalšom riadku dostáva príspevky od troch rôznych pixelov v aktuálnom riadku, tapov 3/16, 5/16 a 1/16, a ak kód priraďuje namiesto sčítania, každý zápis zahodí predchádzajúci príspevok a prežije len posledný tap. Obrázok stále vyzerá ditherovane, čo je to, čo to robí ťažko postrehnuteľným, ale textúra je zlá a tónová reprodukcia driftuje. Test, ktorý to chytí, je kvantitatívny: dithernite uniformné pole stredne sivej a vyžadujte, aby vnútorné pokrytie dopadlo medzi 40 a 60 percent

Ktorú kombináciu má použiť pipeline na zmenšovanie veľkosti?

Priraďte kernel k tomu, čo obrázky skutočne sú, a berte dithering ako záležitosť zariadenia, nie kompresie. Pre fotografické skeny, ktoré musia prežiť rozpočet veľkosti, udrží rkLanczos3 pri 150 alebo 200 DPI detail, ktorý si ľudia všimnú, pri zrezaní počtu pixelov o faktor štyri a viac. Pre screenshoty, diagramy a line art je rkHalftone úprimne v poriadku a oveľa rýchlejší, lebo tie obrázky majú málo tónových gradientov na zachovanie. Pre zmiešanú dávku, kde nemôžete skontrolovať každý obrázok, je rkBicubic rozumný stred: lepší než bilinear, zhruba polovica počtu tapov Lanczos3

Downscaling je jedna páka z viacerých a nie je vždy tou najväčšou. Dvojúrovňové skeny zvyčajne reagujú oveľa lepšie na enkodér popísaný v článku natívna JBIG2 dvojúrovňová kompresia v Delphi, kde zisk pochádza zo symbolových slovníkov, nie z počtov pixelov. Pred rozhodnutím pomôže vedieť, čo je v súbore skutočne obsiahnuté, na čo slúži článok extrakcia obrázkov a ich decode filtrov: inventár objektov obrázkov a ich existujúcej kompresie vám povie, či má resampling čo získať

Ak staviate náhľadovú plochu, ktorá ukazuje výsledok, rovnaká renderovacia cesta popísaná v článku vykreslenie PDF strany do bitmapy je miesto, kde RenderOutputDither účinkuje, takže ditherovaný náhľad aj ditherovaný výstup pochádzajú z jednej kódovej cesty, nie z dvoch implementácií, ktoré sa rozídu

Široký princíp za oboma funkciami je, že nastavenia kvality majú byť explicitné a vratké. HotPDF necháva historické správanie ako default, aby existujúca aplikácia upgradovala bez prekvapivej zmeny vo výstupe alebo časovaní, a lepšie vyzerajúce, pomalšie cesty sú jedno priradenie vlastnosti ďaleko. Obe sú súčasťou HotPDF Delphi PDF komponentu, spolu s optimalizáciou resources a renderovacím strojárstvom, na ktorom stoja