Technical Article

Трехмерные таблицы LUT цвета в PDF с помощью функций выборки Type 0

Функции PDF (PDF Functions) представляют собой малозаметную область спецификации. Большинство разработчиков сталкиваются с ними лишь раз, когда осевому затенению типа 2 (Type 2 axial shading) требуется плавный переход между двумя цветами, и больше к ним не возвращаются. Это упущение, так как механизм функций представляет собой универсальный вычислитель, используемый форматом для затенений, функций передачи, полутоновых функций, плашечных цветов и кривых передачи мягких масок. Из четырех типов функций тип 0 (Type 0) является наиболее мощным и наименее понятным. Это функция выборки (sampled function), то есть многомерная сетка выходных значений, между которыми программа просмотра выполняет интерполяцию. Поскольку в сетку можно поместить любые числа, функция Type 0 может выражать произвольное нелинейное отображение, что в точности соответствует структуре таблицы поиска цвета (LUT).

В этой статье рассматривается словарь Type 0 в соответствии с разделом §7.10.2 стандарта ISO 32000-1, а также приводятся два наиболее важных сценария в процессах обработки документов: трехканальная таблица LUT для цветокоррекции RGB-в-RGB и одноканальное преобразование плашечного цвета. В обоих случаях используется один и тот же построитель функций выборки, а разница заключается исключительно в количестве входов сетки.

Функция выборки как интерполируемая сетка значений

Функция Type 0 отображает вектор из m входов в вектор из n выходов путем хранения выборок в регулярной сетке и интерполяции между ними. В разделе §7.10.2 стандарта ISO 32000-1 перечислены ключи, описывающие эту сетку. Ключ /Domain содержит по два числа на каждый вход, задавая нижнюю и верхнюю границы каждой входной оси. Ключ /Range содержит по два числа для каждого выходного компонента. Ключ /Size представляет собой массив из m целых чисел, задающих количество выборок вдоль каждой входной оси. Например, трехмерная сетка с двенадцатью выборками на сторону имеет размер /Size [12 12 12] и содержит 1728 точек сетки. Ключ /BitsPerSample определяет точность каждого сохраненного значения; HotPDF поддерживает 1, 2, 4, 8, 12, 16, 24 и 32 бита, что соответствует значениям из таблицы 38.

Поток выборок считывается в строго определенном порядке. Быстрее всего меняется первое входное измерение, затем второе и так далее, а в каждой точке сетки по порядку сохраняются n выходных компонентов. Для таблицы преобразования RGB-в-RGB это означает три байта на каждую точку сетки при 8-битной точности (выход красного, выход зеленого, выход синего с первоначальным изменением по входу красного). Еще два ключа связывают непрерывные значения с целочисленной сеткой. Ключ /Encode сопоставляет каждый вход из интервала /Domain с диапазоном индексов выборок от 0 до Size[i] - 1, а /Decode преобразует исходные сохраненные целые числа обратно в интервалы /Range. При значениях по умолчанию входной диапазон [0 1] точно накладывается на сетку, а сохраненный байт со значением 255 декодируется в верхнюю границу выходного диапазона, что идеально подходит для нормализованной в диапазоне [0,1] таблицы LUT цвета.

Порядок 1 против Порядка 3

Для расчета значений между точками сетки выполняется интерполяция, и ключ /Order определяет ее алгоритм. Значение /Order 1 задает мультилинейную интерполяцию: линейную по одной оси, билинейную по двум и трилинейную по трем осям. Это быстрый алгоритм, используемый большинством программ просмотра, и для плавного изменения цвета он визуально неотличим от более сложных методов. Значение /Order 3 задействует интерполяцию кубическими сплайнами, которая строит более плавную кривую по точкам за счет увеличения объема вычислений и расширения области опорных точек вокруг рассчитываемого значения.

Выбор здесь сводится к балансу между плотностью сетки и плавностью кривой. Кубический порядок полезен при разреженной сетке и заметной кривизне отображения, так как прямая линия между отдаленными точками может сгладить тональную кривую так, что глаз заметит это на градиентах. Если же сетка достаточно плотная, сегменты становятся короткими, и линейная интерполяция отлично следует изгибам кривой, сводя к минимуму преимущества кубической. На практике рекомендуется выбирать /Order 3 только для небольших сеток или резких переходов, а в остальных случаях оставлять линейную интерполяцию по умолчанию. Учтите, что ключ /Order применим только к функциям Type 0, и HotPDF отклоняет любые значения, кроме 1 и 3.

3D LUT: три входа и три выхода

Цветокоррекция RGB-в-RGB служит классическим примером использования трехмерной сетки. Это стандартная таблица 3D LUT, применяемая для настройки цветов и калибровки оборудования. Каждая ось куба представляет собой один входной канал, каждая точка сетки хранит скорректированную тройку RGB для соответствующих входных координат, а программа просмотра выполняет трилинейную интерполяцию угловых значений вокруг любого входящего цвета. Наличие трех входов здесь обязательно, так как скорректированное значение красного цвета может зависеть от входных уровней зеленого и синего цветов, а не только от красного. Поканальная кривая не способна отразить взаимное влияние каналов, тогда как кубическая таблица справляется с этим отлично.

HotPDF создает поток Type 0 с помощью метода RegisterSampledFunction, который принимает параметры /Domain, /Range, /Size, /BitsPerSample и массив байтов выборок напрямую, возвращая объект функции. Для стандартного нормализованного куба вы передаете границы [0,1] для всех трех входных осей и трех выходов, размер N x N x N и плоскую таблицу выборок. Построитель проверяет соответствие количества байтов размеру сетки: при побайтовом выравнивании он ожидает длину, равную OutputCount * (BitsPerSample div 8) * произведение размеров осей, и генерирует исключение при несовпадении. Благодаря этому ошибки в расчете шага выявляются на этапе регистрации, а не приводят к выводу некорректного изображения в дальнейшем.

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 (аналогично цветопробе), чтобы числа в сетке соответствовали заданным профилям источника и назначения. Вы можете зарегистрировать профили конвертации с помощью метода RegisterICCProfile, который создает цветовое пространство ICCBased (1, 3 или 4 компонента) и возвращает имя ресурса, которое можно привязать к содержимому, использующему таблицу LUT. Функция Type 0 содержит таблицу интерполяции, тогда как профиль ICC определяет значение конечных точек.

Одномерный случай: преобразование оттенка плашечного цвета

Плашечные цветовые пространства (Separation color spaces) используют тот же механизм для решения совсем другой задачи. Пространство Separation, определенное в разделе §8.6.6.4 стандарта ISO 32000-1, представляет один краситель (например, краску Pantone или лак), связывая ее имя с функцией преобразования оттенка (tint transform). Эта функция сопоставляет одномерное значение оттенка (от 0 для отсутствия краски до 1 для полной заливки) с альтернативным цветовым пространством, которое устройство может воспроизвести (обычно это CMYK). Такое преобразование оттенка часто реализуется в виде функции Type 0, у которой сетка имеет ровно одну входную ось.

В этом и заключается различие с трехмерной таблицей 3D LUT. Плашечный цвет имеет одну степень свободы, поэтому его преобразование оттенка требует одного входа, а сетка представляет собой простую линию выборок, каждая из которых хранит значения CMYK (или другого альтернативного пространства) для конкретного уровня оттенка. Кубу RGB требуются три входа из-за трехмерной области определения и взаимосвязи каналов. Тот же тип функции, те же правила интерполяции, но другая размерность; спецификация задействует один и тот же вычислитель, а ключ /Size определяет, работаем мы с линией, плоскостью или кубом. HotPDF инкапсулирует все операции разделения цветов в методе RegisterSeparationLUT, который во внутреннем представлении создает одномерное преобразование оттенка Type 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-построителе, что позволяет выявить некорректные данные на этапе сборки, не допуская скрытых сбоев при печати.

Другие области применения этого механизма

Если рассматривать Type 0 как универсальную таблицу интерполяции, то еще два механизма управления устройствами перестают казаться частными случаями. Функция передачи (transfer function) корректирует значения компонентов перед их отправкой на устройство вывода и представляет собой отдельную функцию для каждого канала. 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 словаря графического состояния. Каждая из них представляет собой кривую с одним входом от уровня серого к объему черного цвета. Это также могут быть функции Type 0, если вместо аналитической формулы требуется использовать измеренную кривую, создаваемую через RegisterSampledFunction и помещаемую в графическое состояние. Главный вывод состоит в том, что функция PDF не является местом управления цветом; она представляет собой лишь таблицу поиска, содержащую решение, принятое в специализированном цветовом движке, а тип Type 0 представляет собой единственный формат функции, достаточно гибкий для сохранения любого такого решения.

Общую информацию о выводе шрифтов, изображений и ресурсов цвета в готовый документ можно найти в нашем руководстве по подготовке отчетов со шрифтами и изображениями. Если готовый документ должен успешно проходить проверку на соответствие стандартам печати или архивирования, правила работы с цветовыми пространствами и целями вывода (output intent), описанные в руководстве по валидации PDF/A, PDF/X и PDF/UA, определяют допустимость использования этих функций и правила разметки цветов. Все эти функции входят в состав компонента HotPDF Component для Delphi и C++Builder наряду с API для затенения, работы с профилями ICC и разделением цветов на базе ядра Type 0.