HotPDF излага три ядра за смъкване на изображения през свойството ImageDownsampleKernel и отделен Floyd-Steinberg пас през RenderOutputDither. Първото контролира как изглеждат фотографиите, след като ги смъкнете, за да уцрите размерен бюджет, второто – как изглеждат, след като страницата е сведена до черно и бяло. Нито едното не е включено по подразбиране, а и двете са opt-in по една и съща причина: струват реално време
Натискът, който завежда хората тук, е познат. 60 MB сканиран договор трябва да излезе през email gateway, отхвърлящ всичко над 10 MB, или партида изявления трябва да кацне на факсоподобно монохромно устройство, рендиращо всеки сив пиксел като хартия или тонер. И двата проблема са проблеми на презамплването, и и двата имат бърз отговор, който изглежда зле, и бавен отговор, който изглежда право
По какво реално се различават трите ядра
THPDFResampleKernel има три стойности, и те седят на истински различни точки по кривата скорост-качество. rkHalftone делегира към историческия GDI StretchBlt път с HALFTONE режим, който въпреки името е билинейно-класово филтриране: бързо, достатъчно за line art и скрийншоти, и податливо на трошливите ръбове, които разпознавате мигновено на смалени фотографии. rkBicubic върви с разделимо Catmull-Rom ядро, а rkLanczos3 – с разделимо windowed sinc с three-lobe обхват
И двете разделими ядра вървят като два паса, хоризонтален после вертикален, с 6 до 12 taps на целеви пиксел в чист Pascal. Това е грубо с порядък по-бавно от GDI пътя, което е точно причината rkHalftone да остава по подразбиране. На нощна партида от хиляди страници разликата е решение за планиране, не предпочитание. На един документ, който потребител чака, Lanczos3 е почти безплатен и видимо по-добър
Две имплементационни свойства си заслужават познание, защото определят какво изходът може и какво не може. Границите clamp-ват чрез копиране на ръба, вместо обгръщане или избледняване, а теглата се нормализират на всеки целеви пиксел. Двете заедно значат, че резултатът никога не звъни под черно или над бяло, така че класическият Lanczos overshoot ореол около твърд ръб не се появява като подрязани артефакти в кодираното изображение
var
Pdf: THotPDF;
Info: THPDFLoadedResourceOptimizationInfo;
Changed: Integer;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('scanned-contract.pdf');
Pdf.ImageDownsampleKernel := rkLanczos3; // задайте преди викането
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 – 4096 по-горе – е guard-ът, пазещ операцията честна. Прекодиране на изображение, вече ефективно компресирано, може да произведе по-голям stream от оригинала, а downsampler, който сляпо заменя всяко изображение, понякога надува файла, когото са го молили да смъкне. Прагът казва: приеми замяната само когато пести поне толкова байта. PreservedCalibratedImageCount докладва другото консервативно решение – изображения, оставени недокоснати, защото носят калибрирано цветово пространство, което презамплването би компрометирало
Защо грешен полиномиален коефициент е толкова труден за забелязване?
Защото счупено интерполационно ядро не гърми и не хвърля, а само произвежда изображение, изглеждащо фино грешно по начин, който никой не може да припише. Catmull-Rom ядрото е парче-кубично, а външният му клон във вложена Horner форма е ((-0.5t + 2.5)t - 4)t + 2. Напишете ли онзи среден коефициент -5 вместо -4, функцията пак се смята, пак връща числа в правдоподобен диапазон и пак произвежда изображение
Щетата се проявява като W(1), смятащ се на -1, където трябва да е 0. Отрицателните тегла се трупат, сумата се подрязва на нула, а видимият симптом е градиент, чиито ляв край почернява, и стъпален ръб, загубил междинните си тонове. Нищо в провала не сочи полином. Проверката, хващаща го за секунди, е аритметична, не визуална: интерполиращо ядро трябва да удовлетвори W(0) = 1 и W(±1) = W(±2) = 0, а всяко ядро, пропусне ли тези три точки, има коефициентна грешка, точка. Утвърдете тези три стойности в unit тест и целият клас типографски дефекти изчезва
Floyd-Steinberg dithering и къде му е мястото в pipeline-а
Dither пасът е различен проблем от презамплването и живее на друго място в pipeline-а. RenderOutputDither прилага Floyd-Steinberg error diffusion след композицията на страницата, което е единственото място, имащо смисъл за монохромен print preview или факсоподобен export: операцията е за смъкването на готов растер до един бит на пиксел, не за това как отделните изображения са скалирани по пътя навътре
Алгоритъмът сам по себе си е кратък. Luminance-ът се подлага на праг от 50 процента, а квантизационната грешка се разпръсква към четири съседа с класическите тегла 7/16, 3/16, 5/16 и 1/16 – надясно, долу-ляво, долу и долу-дясно. Изходният пиксел е 0 или 255 във всеки канал. Наивната алтернатива вместо това – твърд праг без разпръскване – превръща фотография в силует и губи всеки междинен тон, носил съдържанието
// Dithering по време на render за монохромно preview устройство
Pdf.RenderOutputDither := True;
// Или приложете същия пас върху bitmap, който вече притежавате. Bitmap-ът
// трябва да е pf24bit; функцията връща False, вместо да гадае
if not HPDFFloydSteinbergDitherBitmap(Preview) then
raise Exception.Create('dither expects a 24-bit bitmap');
// Директен достъп до ядрото, когато презамплирате извън документния pipeline
Small := HPDFResizeBitmapKernel(Large, 640, 480, rkLanczos3);
try
Small.SaveToFile('thumb.bmp');
finally
Small.Free;
end;
Има един имплементационен детайл в error diffusion, хапнал всеки по веднъж. Буферът за грешка ред-до-ред трябва да акумулира. Всеки пиксел в следващия ред получава приноси от три различни пиксела в текущия ред – tap-овете 3/16, 5/16 и 1/16 – и ако кодът присвоява вместо да събира, всяко записване изхвърля предишния принос и оцелява само последният tap. Изображението пак изглежда dither-нато, което го прави трудно за забелязване, но текстурата е грешна и тоналната репродукция се отмества. Тестът, който го хваща, е количествен: dither-нете униформено средно сиво поле и изисквайте вътрешното покритие да падне между 40 и 60 процента
Коя комбинация трябва да ползва pipeline за смъкване на размер?
Напаснете ядрото с това какво реално са изображенията, а dithering-а третирайте като грижа за устройството, не за компресията. За фотографични сканирания, които трябва да оцелеят размерен бюджет, rkLanczos3 на 150 или 200 DPI пази детайла, който хората забелязват, докато реже броя пиксели четирикратно или повече. За скрийншоти, диаграми и line art rkHalftone е истински достатъчен и много по-бърз, защото тези изображения имат малко тонални градиенти за пазене. За смесена партида, в която не можете да огледате всяко изображение, rkBicubic е разумната среда: по-добър от билинейния, грубо половината tap брой на Lanczos3
Смъкването е една от няколко lever-и, и не винаги най-голямата. Двустепенните сканирания обикновено отговарят далеч по-добре на енкодера, обхванат в нативна JBIG2 bilevel компресия в Delphi, където печалбата идва от символни речници, а не от брой пиксели. Преди да решите, помага да знаете какво реално има във файла, за което служи извличането на изображения и техните decode филтри: опис на image обектите и съществуващата им компресия ви казва дали презамплването има какво да спечели
Ако строите preview повърхността, показваща резултата, същият render път, документиран в рендиране на PDF страница в bitmap, е мястото, където RenderOutputDither влиза в действие, така че dither-натият preview и dither-натият изход идват от един кодов път, а не от две имплементации, които се разминават
Широкият принцип зад двете възможности е, че настройките за качество трябва да са изрични и обратими. HotPDF пази историческото поведение по подразбиране, така че съществуващо приложение се ъпгрейдва без изненадваща промяна в изхода или времето, и слага по-красивите, по-бавни пътища на едно задаване на свойство разстояние. И двете са част от HotPDF Delphi PDF компонента, редом с machinery-то за ресурсна оптимизация и рендиране, върху което градят