Функциите на PDF са едно от по-тихите кътчета на спецификацията. Повечето разработчици ги срещат веднъж, като нещо, от което се нуждае аксиалното засенчване от Тип 2, за да избледнее между два цвята, и никога повече не поглеждат назад. Това е срамота, тъй като машината за функции е малък модул за оценяване с общо предназначение, който форматът използва повторно за засенчвания, трансферни функции, полутонови точкови функции, сепарационни нюанси (separation tints) и криви на пренос на меки маски. От четирите типа функции, Тип 0 е най-мощният и най-малко разбираният. Тя е дискретизирана функция (sampled function): многоизмерна мрежа от изходни стойности, между които четецът интерполира. Тъй като мрежата може да съдържа всякакви числа, които въведете в нея, функция от Тип 0 може да изрази произволно нелинейно съпоставяне, което е точната форма на таблица за търсене на цветове (color lookup table - LUT).
Тази статия разглежда речника от Тип 0, както го дефинира ISO 32000-1 в §7.10.2, а след това показва двата случая, които имат най-голямо значение в конвейера за документи: LUT за корекция на цветовете с три входа RGB-към-RGB и трансформация на нюанси на плашков цвят (spot-color tint transform) с един вход. Един и същ конструктор за дискретизирани функции обслужва и двата случая, а разликата между тях е изцяло въпрос на това колко входа има мрежата.
Дискретизираната функция е мрежа, която четецът интерполира
Функция от Тип 0 съпоставя m-входен вектор към n-изходен вектор чрез съхраняване на проби върху правилна мрежа и интерполиране между тях. ISO 32000-1 §7.10.2 изброява ключовете, които описват тази мрежа. /Domain съдържа две числа за всеки вход, долната и горната граница на всяка входна ос. /Range съдържа две числа за всеки изходен компонент. /Size е масив от m цели числа, показващи броя на пробите по протежение на всяка входна ос, така че мрежа, която има дванадесет проби на страна в три измерения, има /Size [12 12 12] и съхранява 1728 точки от мрежата. /BitsPerSample задава точността на всяка съхранена стойност; HotPDF приема 1, 2, 4, 8, 12, 16, 24 и 32 бита, съответствайки на стойностите, които Таблица 38 позволява.
Потокът от проби се чете в фиксиран ред. Първото входно измерение варира най-бързо, след това второто и т.н., а при всяка точка от мрежата n-те изходни компонента се съхраняват подред. За RGB-към-RGB таблица това са три байта на точка от мрежата при осем бита, подредени по изход за червено, изход за зелено, изход за синьо, преминали първо през червения вход. Още два ключа съпоставят непрекъснатия свят върху целочислената мрежа. /Encode съпоставя всеки вход от неговия интервал /Domain към диапазона на индекса на пробата 0 до Size[i] - 1, а /Decode съпоставя обратно съхранените сурови цели числа към интервалите /Range. Когато ги оставите по подразбиране, вход с обхват [0 1] попада чисто върху цялата мрежа, а съхранен байт със стойност 255 се декодира до най-горната граница на изходния диапазон, което е точно това, което иска една [0,1]-нормиран цветен LUT.
Ред 1 спрямо Ред 3
Между точките на мрежата четецът трябва да интерполира, а /Order избира как. /Order 1 е мултилинейна интерполация: линейна по една ос, билинейна по две, трилинейна по три. Тя е бърза, точно това прави хардуерът в повечето четци и за плавна трансформация на цветовете обикновено е неразличима от нещо по-сложно. /Order 3 изисква интерполация на кубичен сплайн (cubic-spline interpolation), която напасва по-гладка крива през пробите за сметка на повече работа и по-широка област на поддръжка около всяка оценена точка.
Компромисът е плътността на мрежата спрямо гладкостта на кривата. Кубичният ред си заслужава усилията, когато мрежата е груба и картографирането има видима кривина, защото права линия между две отдалечени проби може да изравни тоналната крива по начин, който окото улавя в градиентите. След като мрежата е плътна, сегментите са достатъчно къси, така че линейната интерполация проследява кривата отблизо и кубичната носи малко полза. Практическо правило е да посягате към /Order 3 само при малки мрежи или стръмни трансформации, а в противен случай да го оставите на линейната стойност по подразбиране. Имената на функциите и пропъртитата остават на латиница, а HotPDF отхвърля всяка стойност, различна от 1 или 3.
3D LUT: три входа, три изхода
Корекцията на цветовете RGB-към-RGB е класически пример за мрежа с три входа - традиционната 3D LUT, използвана при цветово градиране (color grading) и съвпадение на устройства. Всяка ос на куба е един входен канал, всяка точка от мрежата съхранява коригираната тройка RGB за тази входна координата, а четецът трилинейно интерполира ъгловите проби около всеки входящ цвят. Три входа са неизбежни тук, тъй като коригираното червено може да зависи от входното зелено и синьо, а не само от входното червено; кривата за отделен канал не може да изрази взаимното влияние на каналите (crosstalk), но кубът може.
HotPDF изгражда потока от Тип 0 чрез RegisterSampledFunction, който приема директно /Domain, /Range, /Size, /BitsPerSample и байтовете с проби и връща обекта на функцията. За стандартен нормиран куб предавате граници [0,1] на трите входни оси и трите изхода, размер N x N x N и плоската таблица с проби. Конструкторът валидира, че броят на байтовете съответства на мрежата: за байтово подравнена дълбочина той очаква OutputCount x (BitsPerSample div 8) x произведението на размерите, и повдига изключение, ако масивът е с грешна дължина, така че грешно изчислената стъпка (stride) се проваля шумно при регистрацията, вместо да се рендерира като боклук по-късно.
const
N = 17; // 17 x 17 x 17 cube, the common ICC LUT resolution
var
LutFn: THPDFStreamObject;
Samples: TBytes;
begin
// Fill Samples with N*N*N grid points, 3 bytes each (R,G,B output),
// red input varying fastest. Build the corrected triple for each
// grid coordinate with your ICC-managed conversion, then store it.
SetLength(Samples, N * N * N * 3);
BuildCorrectedCube(Samples, N); // your color-managed fill
LutFn := Pdf.RegisterSampledFunction(
[0,1, 0,1, 0,1], // /Domain: three input axes on [0,1]
[0,1, 0,1, 0,1], // /Range: three output channels on [0,1]
[N, N, N], // /Size: the cube resolution per axis
8, // /BitsPerSample
Samples,
1); // /Order 1 = trilinear
end;
Колориметричната коректност на куба живее в това как го попълвате, а не в функцията на PDF. Правилният път е да изчислите всяка точка от мрежата чрез ICC-управлявана конверсия - същата машина, която управлява софтуерната проба (soft-proof), така че числата в мрежата да означават нещо спрямо дефиниран изходен и целеви профил. Регистрирайте профилите, които ограничават конверсията, с RegisterICCProfile, който записва цветово пространство ICCBased (1, 3 или 4 компонента) и връща име на ресурс, което можете да прикачите към съдържанието, захранвано от LUT. Функцията от Тип 0 носи таблицата за интерполация; профилът на ICC носи значението на крайните точки.
1D случаят: трансформация на нюанси на плашков цвят
Сепарационните цветови пространства (Separation color spaces) се опират на същата машина за съвсем различна задача. Пространството Separation, дефинирано в ISO 32000-1 §8.6.6.4, представлява един оцветител, плашкова боя (spot ink) като Pantone или лак, като сдвоява име с трансформация на нюанс (tint transform): функция, която съпоставя едноизмерната стойност на нюанса (0 за липса на мастило до 1 за пълно мастило) към алтернативно цветово пространство, което устройството действително може да рендерира, обикновено CMYK. Тази трансформация на нюанс често е функция от Тип 0, като сега мрежата има точно една входна ос.
Това е ясният контраст с 3D LUT. Плашковата боя има една степен на свобода, така че нейната трансформация на нюанс се нуждае от един вход, а мрежата е линия от проби, всяка от които съдържа стойността на CMYK (или друга алтернатива) при това ниво на нюанс. Кубът RGB се нуждае от три входа, тъй като неговият домейн е триизмерен и каналите си взаимодействат. Същият тип функция, същите правила за интерполация, различна размерност; спецификацията използва повторно един оценител и оставя /Size да реши дали вървите по линия, равнина или куб. HotPDF обвива цялата сепарация в RegisterSeparationLUT, който изгражда вътрешно едноходната трансформация на нюанс от Тип 0 от плосък байтов масив и връща името на ресурса на цветовото пространство.
var
SpotCS: AnsiString;
begin
// Four CMYK output bytes per tint grid point, tint domain [0..1].
// Here 0% ink -> all zero, 100% ink -> a rich spot build,
// with two interior steps; the tint transform interpolates between.
SpotCS := Pdf.RegisterSeparationLUT(
'PANTONE 286 C', // colorant name
'DeviceCMYK', // alternate color space
[ 0, 0, 0, 0, // tint 0.00 -> 0,0,0,0
90, 60, 0, 0, // tint 0.33
100, 80, 0, 10, // tint 0.66
100, 72, 0, 18]); // tint 1.00 -> full ink build
// Use SpotCS with SetFillColorSpace / SetFillColor on a page.
end;
Броят на пробите трябва да бъде цяло число от точки на мрежата: положително кратно на броя на компонентите на алтернативното пространство и поне две точки, за да има сегмент за интерполиране. Предайте три байта на точка срещу алтернатива на CMYK и извикването я отхвърля - същата защитна валидация, която прилага 3D конструкторът, което е точно това, което искате от функция, която в противен случай ще се провали мълчаливо по време на печат.
Къде се появява отново същата машина
След като погледнете на Тип 0 като на обща таблица за интерполация, още две функции за управление на устройства спират да изглеждат като специални случаи. Трансферната функция регулира стойностите на компонентите по пътя им към изходното устройство и тя е просто функция за всеки канал; HotPDF я регистрира като ExtGState чрез RegisterTransferFunctionState, който приема или една комбинирана функция, или масив от функции за всеки канал. Тъй като тези функции са обикновени обекти на функции, можете да му предадете самия THPDFStreamObject, който RegisterSampledFunction връща, и да управлявате трансферната крива от таблица с проби, вместо от формула.
var
ToneFn: THPDFStreamObject;
GsName: AnsiString;
begin
// A single-input, single-output sampled tone curve on [0,1].
ToneFn := Pdf.RegisterSampledFunction(
[0,1], [0,1], [256], 8, ToneCurveBytes, 1);
// Apply it to all channels as a combined /TR2 transfer function.
GsName := Pdf.RegisterTransferFunctionState(ToneFn, []);
// Select GsName on the page before drawing the affected content.
end;
Генерирането на черно (Black generation) и премахването на подцветова подложка (undercolor removal) се намират в същото семейство. Когато дадено устройство преобразува RGB в CMYK, то решава каква част от сивия компонент да носи като черно мастило, а спецификацията изразява това решение като функция - записите /BG2 и /UCR2 на речника за графично състояние, всеки от които е крива с единичен вход от изчисленото сиво към количество черно. Те също са функции от Тип 0, когато искате измерена крива вместо аналитична такава, изградени по същия начин чрез RegisterSampledFunction и поставени в графичното състояние. Урокът, който си струва да се запомни, е че функцията на PDF никога не е мястото, където се извършва управлението на цветовете; тя е таблицата за търсене, която пренася решение, взето с истинска машина за управление на цветовете, а Тип 0 е единственият тип функция, достатъчно гъвкав, за да пренесе всяко решение.
За по-широката картина на това как шрифтовете, изображенията и цветовите ресурси се извеждат в завършен документ, вижте нашето ръководство за отчети с шрифтове и изображения. Когато изходът трябва да преживее проверка за архивност или предпечатен контрол, правилата за цветови пространства и изходни намерения (output intent), обхванати в ръководството за валидиране на PDF/A, PDF/X и PDF/UA, указват кои от тези функции са разрешени и как трябва да се маркира цветът на устройството. Всичко това се доставя в HotPDF Component за Delphi и C++Builder, заедно с API за засенчване, ICC и сепарации, изградени върху същото ядро от Тип 0.