Műszaki cikk

HotPDF kicsinyítő kernelek és nyomtatási dithering

A HotPDF három képkicsinyítő kernelt tesz elérhetővé a ImageDownsampleKernel tulajdonságon keresztül, és egy külön Floyd-Steinberg menetet a RenderOutputDither-ön. Az első azt irányítja, hogyan néznek ki a fényképek azután, hogy méretkeret eléréséhez kicsinyítette őket, a második azt, hogyan néznek ki azután, hogy egy oldal feketére és fehérré zsugorodott. Egyik sincs alapból bekapcsolva, és mindkettő ugyanazért opt-in: valós időbe kerülnek

A nyomás, amely ide vezeti az embereket, ismerős. Egy 60 MB-os szkennelt szerződésnek ki kell mennie egy e-mail átjárón, amely 10 MB felett mindent elutasít, vagy egy kimutatás kötegnek kell földet érintenie egy fax jellegű monokróm eszközön, amely minden szürke pixelt papírnak vagy tonernak rajzol. Mindkét probléma újramintavételezési probléma, és mindkettőnek van gyors válasza, amely rosszul néz ki, és lassú válasza, amely jól néz ki

Miben térnek el ténylegesen a három kernel?

A THPDFResampleKernel-nek három értéke van, és ténylegesen eltérő pontokon ülnek a sebesség-minőség görbén. A rkHalftone a történelmi GDI StretchBlt útra delegál HALFTONE móddal, amely a neve ellenére bilineáris osztályú szűrés: gyors, megfelelő vonalas ábrákhoz és képernyőképekhez, és hajlamos a ropogós élekhez, amelyeket leléptetett fényképeken azonnal felismer. A rkBicubic szétválasztható Catmull-Rom kernelt futtat, a rkLanczos3 pedig szétválasztható ablakolt sincet három lebenyű tartással

Mindkét szétválasztható kernel két menetben fut, vízszintesen aztán függőlegesen, célpixelenként 6-12 leolvasással tiszta Pascalban. Ez nagyjából egy nagyságrenddel lassabb a GDI útnál, és pontosan ezért marad a rkHalftone az alapértelmezett. Ezer oldalt feldolgozó éjszakai kötegnél a különbség ütemezési döntés, nem preferencia. Egyetlen, felhasználó által várt dokumentumnál a Lanczos3 majdnem ingyenes, és láthatóan jobb

A három HotPDF képkicsinyítő kernel súlygörbéi: a rkHalftone a bilineáris osztályú GDI HALFTONE útra delegál egyes tartással, a rkBicubic szétválasztható Catmull-Rom kubikust futtat kettes tartással, a rkLanczos3 pedig ablakolt sincet hármas tartással, nagyjából egy nagyságrendnyi sebességet áldozva fel láthatóan jobb fényképekért
A három kernelérték ténylegesen eltérő pontokon ül a sebesség és minőség görbéjén: egy bilineáris osztályú GDI út, egy Catmull-Rom kubikus és egy háromlebenyes ablakolt sinc, és a szétválasztható kernelek normalizálják a súlyokat, így semmi nem cseng át feketén vagy fehéren

Két implementációs tulajdonság érdemes ismerni, mert meghatározzák, mit tudhat és mit nem a kimenet. A szélek élreplikációval tapadnak, körbezárással vagy fakulással nem, és a súlyok célpixelenként normalizáltak. A kettő együtt azt jelenti, hogy az eredmény sosem cseng fekete alá vagy fehér fölé, tehát a klasszikus Lanczos túllövési haló egy kemény él körül nem jelenik meg kivágott artefaktként a kódolt képben

var
  Pdf: THotPDF;
  Info: THPDFLoadedResourceOptimizationInfo;
  Changed: Integer;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('scanned-contract.pdf');
    Pdf.ImageDownsampleKernel := rkLanczos3;   // állítsa be a hívás előtt
    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;

A MinimumSavingsBytes argumentum, fent 4096, az az őr, amely becsületben tartja a műveletet. Egy már hatékonyan tömörített kép újrakódolása nagyobb streamet adhat, mint az eredeti, és egy minden képet vakon kicserélő kicsinyítő alkanként megnöveli azt a fájlt, amelyet zsugorítani kérték. A küszöb azt mondja: a cserét csak akkor fogadja el, ha legalább ennyi bájtot takarít meg. A PreservedCalibratedImageCount a másik konzervatív döntést jelenti: érintetlenül hagyott képeket, mert kalibrált színteret hordoznak, amelyet az újramintavételezés rontaná

Miért ilyen nehéz észrevenni egy rossz polinomegyütthatót?

Mert egy törött interpolációs kernel nem crashel és nem dob, csak olyan képet ad, amely finoman rosszul néz ki olyan módon, amelyet senki nem tud hozzárendelni semmihez. A Catmull-Rom kernel szakaszonkénti kubikus, és a külső ága beágyazott Horner-formában ((-0.5t + 2.5)t - 4)t + 2. Írja azt a középső együtthatót -4 helyett -5-re, és a függvény továbbra is kiértékelődik, hihető tartományban lévő számokat ad, és továbbra is képet gyárt

A kár úgy mutatkozik meg, hogy a W(1) -1-re értékelődik, ahol nullának kellene lennie. A negatív súlyok felhalmozódnak, az összeg nullánál vágódik, és a látható tünet egy gradiens, amelynek a bal vége feketére megy, és egy lépcsős él, amely elveszíti a köztes tónusait. Semmi a hibában nem mutat polinomra. A másodpercek alatt elkaptó ellenőrzés számtani, nem vizuális: egy interpoláló kernelnek teljesítenie kell a W(0) = 1 és a W(±1) = W(±2) = 0 egyenleteket, és minden kernel, amely lemarad erről a három pontról, együtthatóhibás, és kész. Állítson unit tesztben erre a három értékre, és az elgépelt együttható hibák egész osztálya eltűnik

A HotPDF bicubic Catmull-Rom külső ágának ábrája, amely megmutatja, miért rejtőzik a rossz együttható: az az elírás, amely -4 helyett -5-öt ír a beágyazott Horner-formába, továbbra is kiértékelődik, és a W(1)-et -1-en, a W(2)-t -2-en hagyja ott, ahol nulla a követelmény, tehát a W(0) = 1 állítás a két nulla megszorítással együtt másodpercek alatt elkaptja
Egy törött kernel sosem crashel, csak hihetőnek tűnő számokat ad vissza, ezért a szem nem tud elkapni egy együttható-elírást. A W(0) = 1, nullákkal plusz-mínusz egyen és kettesen, egy háromsoros unit teszt

Floyd-Steinberg dithering, és hol van a helye a folyamatsorban

A dither menet más probléma, mint az újramintavételezés, és a folyamatsor más pontján él. A RenderOutputDither Floyd-Steinberg hibadiffúziót alkalmaz az oldal komponálása után, ami az egyetlen elhelyezés, amely értelmes monokróm nyomtatási előnézethez vagy fax jellegű exporthoz: a művelet arról szól, hogy egy elkészült rasztert pixelenként egy bitre zsugorít, nem arról, hogyan léptették az egyes képeket behúzáskor

Maguk az algoritmus rövid. A fényerő 50 százaléknál küszböleződik, és a kvantálási hiba négy szomszédba diffundál a klasszikus 7/16, 3/16, 5/16 és 1/16 súlyokkal, jobbra, balra le, le és jobbra le. A kimeneti pixel minden csatornában 0 vagy 255. Amit a naiv alternatíva helyette ad, egy kemény küszöb diffúzió nélkül, az a fényképet sziluetté teszi, és minden köztes tónus elveszik, amely a tartalmat hordozta

A HotPDF Floyd-Steinberg dithering elhelyezése a renderelési folyamatsorban: a RenderOutputDither az oldal komponálása után fut az elkészült 24 bites raszteren, 50 százaléknál küszbölezi a fényerőt, és minden kvantálási hibát jobbra és lefelé diffundál 7/16, 3/16, 5/16 és 1/16 súlyokkal egy olyan sorbufferen át, amelynek fel kell halmoznia, egybites monokróm kimenetet gyártva
A dithering a komponálás után való, mert az elkészült rasztert egy bitre zsugorítja, nem azért, ahogy a képeket léptették. A diffúziósúlyok összege egy, és a sorbuffernek halmoznia kell, felülírás helyett
// Renderelésidejű dithering monokróm előnézeti eszközhöz
Pdf.RenderOutputDither := True;

// Vagy alkalmazza ugyanezt a menetet egy már birtokolt bitmapon. A bitmapnek
// pf24bitnek kell lennie; a függvény False-t ad vissza, nem találgat
if not HPDFFloydSteinbergDitherBitmap(Preview) then
  raise Exception.Create('dither expects a 24-bit bitmap');

// Közvetlen kernelhozzáférés, ha a dokumentumfolyamaton kívül mintavételez újra
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
  Small.SaveToFile('thumb.bmp');
finally
  Small.Free;
end;

A hibadiffúzióban van egy implementációs részlet, amely mindenkit egyszer megharap. A sorok közti hibabuffernek fel kell halmoznia. A következő sor minden pixelje hozzájárulást kap az aktuális sor három különböző pixeljétől, a 3/16, 5/16 és 1/16 leolvasásoktól, és ha a kód hozzárendel az összeadás helyett, minden írás eldobja az előző hozzájárulást, és csak az utolsó leolvasás marad fenn. A kép továbbra is dithereltnek tűnik, ami megnehezíti észrevenni, de a textúra rossz, és a tónusreprodukáció sodródik. Az ezt elkaptó teszt kvantitatív: dithereljen egységes középszürke mezőt, és követelje meg, hogy a belső lefedettség 40 és 60 százalék közé érjen

Melyik kombinációt használjon egy méretcsökkentő folyamatsor?

Párosítsa a kernelt ahhoz, ami a képek ténylegesen, és a ditheringet kezelje eszközkérdésnek, tömörítéskérdés helyett. Fénykép szkennelésekhez, amelyeknek átvészerniük kell egy méretkeretet, a rkLanczos3 150 vagy 200 DPI-nél megtartja azt a részletet, amelyet az emberek észrevesznek, miközben a pixelszámot négyszörösével vagy többivel csökkenti. Képernyőképekhez, diagramokhoz és vonalas ábrákhoz a rkHalftone ténylegesen megfelelő és sokkal gyorsabb, mert azok a képek kevés tónusgradienst hordoznak. Vegyes kötegnél, ahol nem tudja megvizsgálni minden képet, a rkBicubic az észszerű középút: jobb, mint a bilineáris, nagyjából a Lanczos3 leolvasásszámának fele

A kicsinyítés az egyik kar a több közül, és nem mindig a legnagyobb. A bilevel szkennelések általában sokkal jobban reagálnak a natív JBIG2 bilevel tömörítés Delphiben cikkben tárgyalt kódolóra, ahol a nyereség szimbólumszótárakból jön, nem pixelszámokból. Mielőtt döntene, segít tudni, mi van ténylegesen a fájlban, erre való a képek és decode szűrőik kinyerése cikk: a képobjektumok és meglévő tömörítésük leltára megmondja, van-e mit nyernie az újramintavételezésnek

Ha az előnézeti felületet építi, amely megmutatja az eredményt, a PDF oldal bitmapre renderelése cikkben dokumentált ugyanaz a renderelési út az, ahol a RenderOutputDither hatni kezd, tehát a ditherelt előnézet és a ditherelt kimenet egy kódútból jön, nem két olyan implementációból, amely szétsodródik

Mindkét funkció mögötti tág elv az, hogy a minőségi beállítások explicitnek és visszavonhatónak kell lenniük. A HotPDF a történelmi viselkedést tartja alapértelmezésnek, így egy meglévő alkalmazás meglepetésváltozás nélkül frissít a kimenetben vagy az időzítésben, és a jobban kinéző, lassabb utakat egy tulajdonság-hozzárendelésre teszi. Mindkettő a HotPDF Delphi PDF komponens része, az erőforrás-optimalizálás és a renderelési gépezet mellett, amelyekre épülnek