Tekninen artikkeli

HotPDF:n kuvien downsample-ytimet ja tulostuksen dithering

HotPDF paljastaa kolme kuvien downsample-ydintä ImageDownsampleKernel-ominaisuuden kautta ja erillisen Floyd-Steinberg-vaiheen RenderOutputDithern kautta. Ensimmäinen ohjaa, miltä valokuvat näyttävät sen jälkeen, kun kutistit niitä osuaksesi kokobudjettiin, toinen ohjaa, miltä ne näyttävät sen jälkeen, kun sivu on supistettu mustavalkoiseksi. Kumpikaan ei ole päällä oletuksena, ja molemmat ovat opt-in samasta syystä: ne maksavat oikeaa aikaa

Paine, joka johtaa ihmiset tänne, on tuttu. 60 MB:n skannattu sopimus on päästävä läpi sähköpostiyhdyskäytävän, joka hylkää kaiken yli 10 MB:n, tai erä tiliotteita on saatava faksityyliselle monokromille laitteelle, joka renderöi jokaisen harmaan pikselin joko paperiksi tai musteeksi. Molemmat ongelmat ovat uudelleennäytteistysongelmia, ja kummallakin on nopea vastaus, joka näyttää pahalta, ja hidas vastaus, joka näyttää oikealta

Missä kolme ydintä oikeasti eroavat

THPDFResampleKernelilla on kolme arvoa, ja ne istuvat aidosti eri kohdissa nopeuden ja laadun käyrää. rkHalftone delegoi historialliselle GDI:n StretchBlt-polulle HALFTONE-tilalla, joka nimestään huolimatta on bilineaariluokan suodatus: nopea, riittävä viivapiirroksille ja kuvakaappauksille ja altis niille kolhiutuneille reunoille, jotka tunnistat heti pienennetyistä valokuvista. rkBicubic ajaa eroteltavan Catmull-Rom-ytimen, ja rkLanczos3 ajaa eroteltavan ikkunoidun sincin, jolla on kolmen lohken tuki

Molemmat eroteltavat ytimet ajavat kahtena kierroksena, vaaka- sitten pystysuunnassa, 6–12 tapia kohdepikseliä kohden puhtaassa Pascalissa. Tuo on suunnilleen suuruusluokan hitaampaa kuin GDI-polku, mikä on juuri syy, miksi rkHalftone pysyy oletuksena. Yökierroksella tuhansilla sivuilla ero on aikataulutuspäätös, ei mieltymys. Yhdessä dokumentissa, jota käyttäjä odottaa, Lanczos3 on lähes ilmaista ja näkyvästi parempaa

Kolmen HotPDF:n downsample-ytimen painokäyrät: rkHalftone delegoi bilineaariluokan GDI HALFTONE -polulle, jonka tuki on yksi, rkBicubic ajaa eroteltavan Catmull-Rom-kolmannen asteen, jonka tuki on kaksi, ja rkLanczos3 ajaa ikkunoidun sincin, jonka tuki on kolme, vaihtaen suunnilleen suuruusluokan nopeutta näkyvästi parempiin valokuviin
Kolmen ytimen arvot istuvat aidosti eri kohdissa nopeuden ja laadun käyrää: bilineaariluokan GDI-polku, Catmull-Rom-kolmonen ja kolmen lohken ikkunoitu sinc, ja eroteltavat ytimet normalisoivat painot niin, ettei mikään ylikilaha mustan tai valkoisen yli

Kaksi toteutuksen ominaisuutta kannattaa tuntea, koska ne päättävät, mitä tuloste voi ja ei voi. Reunat kiinnittyvät reunojen toistamisella käärimisen tai haalistumisen sijaan, ja painot normalisoidaan kohdepikseliä kohden. Yhdessä nuo kaksi tarkoittavat, ettei tulos koskaan ylikilahda mustan alle tai valkoisen yli, joten klassinen Lanczosin ylityshalo kovan reunan ympärillä ei ilmesty leikatuina artefakteina koodattuun kuvaan

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

MinimumSavingsBytes-argumentti, yllä 4096, on vahdi, joka pitää operaation rehellisenä. Jo tehokkaasti pakatun kuvan uudelleenkoodaus voi tuottaa suuremman virran kuin alkuperäinen, ja sokea jokaisen kuvan korvaava pienentäjä kasvattaa silloin tällöin tiedostoa, jota pyydettiin pienentämään. Kynnys sanoo: vahvista korvaus vain, kun se säästää vähintään näin monta tavua. PreservedCalibratedImageCount raportoi toisen konservatiivisen päätöksen, koskematta jätetyt kuvat, koska ne kantavat kalibroitua väriavaruutta, jota uudelleennäytteistys vaarantaisi

Miksi väärä polynomikerroin on niin vaikea huomata?

Koska rikkinäinen interpolointiydin ei kaadu eikä nosta, se vain tuottaa kuvan, joka näyttää hienovaraisesti väärältä tavalla, jota kukaan ei voi atribuoida. Catmull-Rom-ydin on paloittain kolmas aste, ja sen ulompi haara sisäkkäisessä Horner-muodossa on ((-0.5t + 2.5)t - 4)t + 2. Kirjoita se keskikerroin -5 -4:n sijaan, ja funktio yhä evaluoituu, yhä palauttaa lukuja uskottavalla alueella ja yhä tuottaa kuvan

Vahinko ilmestyy W(1):nä, joka evaluoituu -1:ksi, kun sen on oltava 0. Negatiiviset painot kertyvät, summa leikkautuu nollaan, ja näkyvä oire on gradientti, jonka vasen pää menee mustaksi, ja porrasreuna, joka menettää välisävyensä. Mikään vikassa ei osoita polynomiin. Sekunteissa sen nappaava tarkistus on aritmetiikkaa eikä visuaalista: interpoloivan ytimen on täytettävä W(0) = 1 ja W(±1) = W(±2) = 0, ja jokainen ydin, joka ohittaa ne kolme pistettä, kantaa kertoinvirhettä, ja siinä se. Väitä kyseiset kolme arvoa yksikkötestissä, ja koko kirjoitusvirhedefektien luokka katoaa

HotPDF:n bicubic Catmull-Rom -ulomman haaran kuvaaja, joka osoittaa, miksi väärä kerroin kätkeytyy: kirjoitusvirhe, joka kirjoittaa -5 -4:n sijaan sisäkkäisessä Horner-muodossa, yhä evaluoituu ja jättää W(1):n arvoon -1 ja W(2):n arvoon -2, missä nolla vaaditaan, joten W(0) = 1 -väittämä plus kaksi nollaehtoa nappaa sen sekunneissa
Rikkinäinen ydin ei koskaan kaadu, se vain palauttaa lukuja, jotka näyttävät uskottavilta, minkä takia silmä ei napata kertoimen kirjoitusvirhettä. W(0) = 1 nollilla plus- ja miinusykkösessä ja -kakkosessa on kolmen rivin yksikkötesti

Floyd-Steinberg-dithering ja sen paikka putkessa

Dither-vaihe on eri ongelma kuin uudelleennäytteistys ja asuu eri kohdassa putkea. RenderOutputDither soveltaa Floyd-Steinberg-virhelevitystä sivun koostamisen jälkeen, mikä on ainoa sijoitus, joka tekee juurta monokromille tulostusesikatselulle tai faksityyliselle viennille: operaatio koskee valmiin rasterin supistamista yhteen bittiin pikseliä kohden, eikä sitä, miten yksittäiset kuvat skaalattiin matkalla sisään

Algoritmi itsessään on lyhyt. Luminanssi kynnystetään 50 prosentissa, ja kvantointivirhe levitetään neljälle naapurille klassisilla 7/16-, 3/16-, 5/16- ja 1/16-painoilla, menemällä oikealle, alas-vasemmalle, alas ja alas-oikealle. Tulostepikseli on 0 tai 255 jokaisessa kanavassa. Se, mitä naiivi vaihtoehto antaa sinulle sen sijaan, kova kynnys ilman levitystä, muuttaa valokuvan varjokuvaksi ja menettää jokaisen välisävyn, joka kantoi sisällön

HotPDF:n Floyd-Steinberg-ditheringin sijoitus renderöintiputkessa: RenderOutputDither ajaa sivun koostamisen jälkeen valmiilla 24-bittisellä rasterilla, kynnystää luminanssin 50 prosentissa ja levittää jokaisen kvantointivirheen oikealle ja alas 7/16-, 3/16-, 5/16- ja 1/16-painoilla rivipuskurin läpi, jonka on kerrytettävä, tuottaen yhden bitin monokromitulosteen
Dithering kuuluu koostamisen jälkeen, koska se supistaa valmiin rasterin yhteen bittiin, ei siksi, miten kuvat skaalattiin. Levityspainot summautuvat yhteen, ja rivipuskurin on kerrytettävä eikä ylikirjoitettava
// Renderöintiaikainen dithering monokromille esikatselulaitteelle
Pdf.RenderOutputDither := True;

// Tai sovella sama vaihe bittikarttaan, jonka jo omistat. Bittikartan on
// oltava pf24bit; funktio palauttaa Falsen arvaamisen sijaan
if not HPDFFloydSteinbergDitherBitmap(Preview) then
  raise Exception.Create('dither expects a 24-bit bitmap');

// Suora ydinpääsy, kun uudelleennäytteistät dokumenttiputken ulkopuolella
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
  Small.SaveToFile('thumb.bmp');
finally
  Small.Free;
end;

Virhelevityksessä on yksi toteutuksen yksityiskohta, joka puree jokaista kerran. Riviltä riville -virhepuskurin on kerrytettävä. Jokainen pikseli seuraavalla rivillä saa panoksia kolmelta eri pikseliltä nykyisellä rivillä, 3/16-, 5/16- ja 1/16-tapeilta, ja jos koodi sijoittaa lisäämisen sijaan, jokainen kirjoitus hylkää edellisen panoksen ja vain viimeinen tapi selviää. Kuva näyttää yhä ditheröidyltä, mikä tekee siitä vaikean huomata, mutta tekstuuri on väärä ja sävytoisto ajautuu. Sitä nappaava testi on kvantitatiivinen: ditheröi tasainen keskiharmaa kenttä ja vaadi sisäosan peiton osuvan 40:n ja 60:n prosentin väliin

Mitä yhdistelmää kokoa pienentävän putken pitäisi käyttää?

Sovita ydin siihen, mitä kuvat oikeasti ovat, ja kohtele ditheringiä laiteasiana eikä pakkausasiana. Valokuvaskannauksille, joiden on selättävä kokobudjetti, rkLanczos3 150 tai 200 DPI:llä säilyttää yksityiskohdat, joita ihmiset huomaavat, leikatessaan pikselimäärän neljäsosaan tai alle. Kuvakaappauksille, kaavioille ja viivapiirroksille rkHalftone on aidosti ihan hyvä ja paljon nopeampi, koska niissä kuvissa on vähän sävygradientteja säilytettäväksi. Sekalaille, jossa et voi tarkastaa jokaista kuvaa, rkBicubic on järkevä keskitie: parempi kuin bilineaari, suunnilleen puolet Lanczos3:n tapimäärästä

Downsampling on yksi vipu monesta, eikä se ole aina suurin. Bilevel-skannaukset reagoivat yleensä paljon paremmin natiiviin JBIG2-bilevel-pakkaukseen Delphissä käsiteltyyn enkooderiin, jossa voitto tulee symbolisanakirjoista eikä pikselimääristä. Ennen kuin päätät, auttaa tietää, mitä tiedostossa oikeasti on, ja siihen on kuvien ja niiden dekoodaussuodattimien purkaminen: kuvien inventaario ja niiden olemassa oleva pakkaus kertoo, onko uudelleennäytteistyksellä mitään saatavaa

Jos rakennat esikatselupintaa, joka näyttää tuloksen, sama renderöintipolku, jonka artikkeli PDF-sivun renderöinti bittikartaksi dokumentoi, on se, jossa RenderOutputDither vaikuttaa, joten ditheröity esikatselu ja ditheröity tuloste tulevat yhdestä koodipolusta eikä kahdesta toteutuksesta, jotka ajautuvat erilleen

Laaja periaate molempien ominaisuuksien takana on, että laatualustusten pitää olla eksplisiittisiä ja peruutettavia. HotPDF pitää historiallisen käytöksen oletuksena, joten olemassa oleva sovellus päivittyy ilman yllätysmuutosta tulosteessa tai ajoituksessa, ja pane paremmin näyttävät, hitaammat polut yhden ominaisuussijoituksen päähän. Molemmat ovat osa HotPDF Delphi PDF -komponenttia rinnalla niiden resurssioptimointi- ja renderöintikoneiston kanssa, jolle ne rakentuvat