PDF файл, чието заглавие съдържа преливащ (градиентен) фон в стил Word или Excel, рендиран към изображение, в миналото се показваше с празен бял правоъгълник на мястото, където трябва да бъде преливането на цветовете. Рендиращият модул за страници на HotPDF вече поддържа PDF оператора sh (shading) за осови градиенти от тип 2 и радиални градиенти от тип 3: той изчислява функцията за преливане по оста на градиента и изчертава преливането, докато предишните версии тихомълком пропускаха този оператор и оставяха областта бяла като цвета на хартията. Включени са двата вида преливане, покриващи почти всеки градиент в офис документи; мрежестите (mesh) типове не се поддържат, и тази статия описва ясно къде преминава тази граница
PDF градиентът е векторна структура, а не растерно изображение (bitmap), което визуализаторът може директно да пренесе. Речникът за преливане (ISO 32000-1 §8.7.4.5) описва геометрията – ос или двойка кръгове в масива Coords – плюс функция за цвят, и операторът sh изчертава това преливане върху текущата област за изрязване (clip region). Това е същият графичен модел, който HotPDF предлага, когато чертаете пътеки и запълвания върху платно на страница. Рендиращият модул за страници на HotPDF обхожда операторите в потока от съдържание един по един и всеки оператор, за който няма имплементиран код, се пропуска, така че останалата част от страницата все пак се изчертава. Преди версия 2.335.0 операторът sh беше част от този пропуснат набор: градиентът в заглавието или на цялата страница не добавяше нищо към изходния резултат, така че фонът оставаше бял. Файлът никога не е бил повреден. Визуализаторът просто нямаше обработчик за този конкретен оператор, а бялото поле е точно това, което се вижда при липса на такъв
Защо PDF градиентът се рендира като бяло поле?
Дадено преливане не може да бъде изчертано, докато не бъде изчислена неговата функция, така че тази функционалност трябваше да бъде въведена първа. Осовите градиенти от тип 2 и радиалните от тип 3 съдържат речник /Function, който съпоставя параметричната позиция по градиента към конкретен цвят (ISO 32000-1 §7.10). Модулът за изчисляване на функции на HotPDF идентифицира типа FunctionType и го насочва към правилия път. Експоненциалната интерполация от тип 2 (§7.10.3) изчислява C0 + t^N * (C1 - C0) с ограничаване на областите Domain и Range; дискретизираните функции от тип 0 (§7.10.2) четат мрежа от 8-, 16- или 32-битови проби и избират най-близката чрез съпоставянето Encode – случай, разгледан подробно в нашето ръководство за дискретизирано търсене на цветове от тип 0; комбиниращите (stitching) функции от тип 3 (§7.10.4) избират подфункция чрез масива Bounds и се обръщат рекурсивно към нея. Функциите с PostScript калкулатор от тип 4 (§7.10.5) не се изчисляват – те преминават плавно към състояние на неуспешно изчисление, вместо да дадат грешен цвят, съвпадайки с консервативния подход на HotPDF в целия визуализиращ тракт. Този модул се появи във версия 2.334.0, една версия преди самия оператор, тъй като изчертаването на преливането зависи изцяло от качеството на подлежащата функция
Веригата за изчисляване на функции зад преливането (shading)
HotPDF апроксимира непрекъснатото преливане с краен брой ленти с плътен цвят. Компонентът за изчертаване обхожда оста на градиента, разделя я на до 64 ленти (по-малко, когато оста е къса в пиксели на устройството), изчислява стойността на функцията за параметричната позиция на всяка лента и запълва правоъгълник, перпендикулярен на оста, с плътна четка. Балансът е между броя на лентите и плавността: повече ленти описват преливането по-точно, но изискват повече операции по запълване, като 64 е зададеният лимит. Тъй като броят на лентите зависи от дължината на оста в хардуерни пиксели, разделителната способност е от значение. Рендирането на една и съща страница с по-висок DPI удължава оста, така че къс градиент получава повече ленти и линиите омекват, докато не се достигне лимитът от 64 ленти
// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96); // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300); // up to 64 bands
Как HotPDF превръща непрекъснатия градиент в пиксели?
Публичната точка за достъп остава непроменена: RenderLoadedPageToBitmap приема нулев базиран индекс на страница и стойност на DPI, връща 24-битово растерно изображение (собственост на извикващия код) и връща nil при грешка, вместо да генерира изключение, така че поддръжката на градиенти е напълно прозрачна за съществуващия код. Страница, която преди е показвала празно заглавие с градиент, сега връща същото растерно изображение с нарисувано преливане, като за целта не е нужна промяна в API. Важно е да помните кой притежава обекта: извикващият код трябва да освободи върнатия bitmap. Пълният процес на рендиране – интерпретиране на потока със съдържание, вградени шрифтове и кеширане на страници – е разгледан в ръководството за рендиране на PDF страници към bitmap в Delphi
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
begin
// Page 1 (zero-based) at 150 DPI. A gradient-filled header that
// used to come back blank now carries its color blend.
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
Bmp.SaveToFile('page1.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Лесна проверка срещу регресия на кода може да се направи след същото извикване. Рендирайте страницата, вземете цвят на пиксел в областта на градиента и проверете дали той вече не е бял (цвета на хартията, до който визуализаторът стигаше в миналото) – това е проверка на един ред, която улавя евентуално мълчаливо връщане към старото поведение на прескачане на оператора
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
// True when the sh operator painted; False if the region fell back to white.
HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
Bmp.Free;
end;
Рендиране на страница с градиент към растерно изображение (Bitmap)
Четирите типа мрежести преливания (mesh shadings) не се поддържат и това трябва да се има предвид при работа с документи. Свободните триъгълни мрежи на Gouraud (тип 4), решетъчните мрежи на Gouraud (тип 5), Coons patch мрежите (тип 6) и тензорните пачове (тип 7), дефинирани в ISO 32000-1 §8.7.4.5.5 до §8.7.4.5.8, не се рендира; страница с такива елементи ще се визуализира, но тази конкретна област ще остане непроменена. Два допълнителни детайла си струва да се отбележат. Правоъгълниците на цветните ленти покриват зоната на преливане, без да бъдат изрязвани точно по текущата крива за изрязване (clip path), така че градиент, маскиран в кръгла или неправилна форма, се изчертава като правоъгълна ивица, докато прецизното изрязване не бъде въведено в по-късен етап. HotPDF също така приема, че изходът на функцията е RGB или нива на сивото, така че преливане, създадено в CMYK или друго пространство, се апроксимира, без да се прилага точно управление на цветовете. За документите, които повечето екипи с Delphi и C++Builder обработват – отчети, фактури, извлечения и презентации, експортирани в PDF – осовото и радиалното преливане покриват практически всеки градиент, с който ще се срещнете, докато дизайн проекти с много сложни мрежи следва да се разглеждат само за преглед, а не като цветна проба
Визуализаторът за страници на HotPDF, поддръжката на оператора sh, описана тук, и модулът за изчисляване на функции от тип 0/2/3 се доставят като част от HotPDF Component за Delphi и C++Builder – нативна VCL библиотека без външни DLL зависимости, покриваща генериране, редактиране, извличане на текст и рендиране на PDF страници в един пакет