Las funciones PDF son uno de los rincones menos frecuentados de la especificación. La mayoría de los desarrolladores las encuentran una vez, como el recurso que un sombreado axial de Tipo 2 necesita para desvanecerse entre dos colores, y nunca las vuelven a mirar. Es una pena, porque el mecanismo de funciones es un pequeño evaluador de propósito general que el formato reutiliza para sombreados, funciones de transferencia, funciones de punto de trama de medio tono, tintas de separación y curvas de transferencia de máscara suave. De los cuatro tipos de funciones, el Tipo 0 es el más potente y el menos comprendido. Se trata de una función muestreada: una cuadrícula multidimensional de valores de salida entre los cuales el lector realiza una interpolación. Dado que la cuadrícula puede contener cualquier número que se ingrese en ella, una función de Tipo 0 puede expresar una asignación no lineal arbitraria, que es la forma exacta de una tabla de búsqueda de colores (color lookup table).
Este artículo recorre el diccionario de Tipo 0 tal como lo define la norma ISO 32000-1 en §7.10.2, y luego muestra los dos casos que más importan en un flujo de trabajo de documentos: una LUT de corrección de color de RGB a RGB de tres entradas y una transformación de tinta de color directo de una entrada. El mismo generador de funciones muestreadas sirve para ambos, y la diferencia entre ellos es enteramente una cuestión de cuántas entradas tiene la cuadrícula.
Una función muestreada es una cuadrícula que el lector interpola
Una función de Tipo 0 mapea un vector de m entradas a un vector de n salidas almacenando muestras en una cuadrícula regular e interpolando entre ellas. ISO 32000-1 §7.10.2 enumera las claves que describen esa cuadrícula. /Domain contiene dos números por entrada, el límite inferior y superior de cada eje de entrada. /Range contiene dos números por componente de salida. /Size es un arreglo de m enteros que indica el número de muestras a lo largo de cada eje de entrada, de modo que una cuadrícula que tiene doce muestras por lado en tres dimensiones tiene /Size [12 12 12] y almacena 1,728 puntos de cuadrícula. /BitsPerSample establece la precisión de cada valor almacenado; HotPDF acepta 1, 2, 4, 8, 12, 16, 24 y 32 bits, coincidiendo con los valores que permite la Tabla 38.
El flujo de muestras se lee en un orden fijo. La primera dimensión de entrada varía más rápido, luego la segunda, y así sucesivamente, y en cada punto de la cuadrícula los n componentes de salida se almacenan en orden. Para una tabla de RGB a RGB, eso representa tres bytes por punto de cuadrícula a ocho bits, dispuestos como salida-rojo, salida-verde, salida-azul, recorriendo primero la entrada de rojo. Dos claves adicionales mapean el mundo continuo a la cuadrícula de enteros. /Encode mapea cada entrada desde su intervalo /Domain al rango de índice de muestra de 0 a Size[i] - 1, y /Decode mapea de vuelta los enteros crudos almacenados a los intervalos /Range. Al dejarlos en sus valores predeterminados, una entrada que abarca [0 1] encaja limpiamente en toda la cuadrícula y un byte almacenado de 255 se decodifica en el límite superior de su rango de salida, que es lo que requiere una LUT de color normalizada en [0,1].
Orden 1 frente a Orden 3
Entre los puntos de la cuadrícula, el lector debe interpolar, y /Order elige cómo hacerlo. /Order 1 es una interpolación multilineal: lineal a lo largo de un eje, bilineal en dos dimensiones y trilineal en tres. Es rápida, es exactamente lo que hace el hardware de la mayoría de los visores y, para una transformación de color suave, suele ser indistinguible de métodos más complejos. /Order 3 solicita una interpolación de spline cúbica, que ajusta una curva más suave a través de las muestras a costa de un mayor procesamiento y una región de soporte más amplia alrededor de cada punto evaluado.
El equilibrio radica en la densidad de la cuadrícula frente a la suavidad de la curva. El orden cúbico demuestra su valor cuando la cuadrícula es gruesa y el mapeo tiene una curvatura visible, debido a que una línea recta entre dos muestras distantes puede aplanar una curva de tono de una manera que el ojo detecta fácilmente en los degradados. Una vez que la cuadrícula es densa, los segmentos son lo suficientemente cortos como para que la interpolación lineal siga la curva de cerca y el orden cúbico aporte muy poco. Una regla práctica es recurrir a /Order 3 únicamente con cuadrículas pequeñas o transformaciones pronunciadas, y de lo contrario mantener el valor predeterminado lineal. Tenga en cuenta que /Order se aplica solo a funciones de Tipo 0, y HotPDF rechaza cualquier valor distinto de 1 o 3.
La LUT 3D: tres entradas, tres salidas
Una corrección de color de RGB a RGB es el caso típico para una cuadrícula de tres entradas, la clásica LUT 3D utilizada en la gradación de color y el emparejamiento de dispositivos. Cada eje del cubo es un canal de entrada, cada punto de la cuadrícula almacena el triplete RGB corregido para esa coordenada de entrada, y el lector realiza una interpolación trilineal de las muestras de las esquinas alrededor de cualquier color entrante. Tres entradas son inevitables aquí porque el rojo corregido puede depender del verde y azul de entrada, no solo del rojo de entrada; una curva por canal no puede expresar la diafonía entre canales, pero un cubo sí.
HotPDF construye el flujo de Tipo 0 mediante RegisterSampledFunction, que recibe directamente /Domain, /Range, /Size, /BitsPerSample y los bytes de muestra, y devuelve el objeto de función. Para un cubo normalizado estándar, se pasan límites [0,1] en los tres ejes de entrada y en las tres salidas, un tamaño de N x N x N y la tabla de muestras aplanada. El generador valida que la cantidad de bytes coincida con la cuadrícula: para una profundidad alineada a bytes, espera OutputCount x (BitsPerSample div 8) x el producto de los tamaños, y genera una excepción si el arreglo tiene una longitud incorrecta, de modo que un paso mal calculado falla notoriamente en el momento del registro en lugar de renderizarse como basura más tarde.
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;
La precisión colorimétrica del cubo reside en cómo se llena, no en la función PDF. El camino correcto consiste en calcular cada punto de la cuadrícula mediante una conversión gestionada por ICC, el mismo motor que controla una prueba en pantalla (soft-proof), para que los números de la cuadrícula tengan significado frente a un perfil de origen y destino definido. Registre los perfiles que limitan la conversión con RegisterICCProfile, que registra un espacio de color ICCBased (1, 3 o 4 componentes) y devuelve un nombre de recurso que puede adjuntar al contenido que alimenta la LUT. La función de Tipo 0 contiene la tabla de interpolación; el perfil ICC aporta el significado de los extremos.
El caso 1D: una transformación de tono de color directo
Los espacios de color de separación (Separation) se apoyan en el mismo mecanismo para un trabajo completamente diferente. Un espacio de separación, definido en ISO 32000-1 §8.6.6.4, representa un único colorante, una tinta directa como Pantone o un barniz, emparejando un nombre con una transformación de tono: una función que mapea el valor de tono unidimensional, de 0 para ausencia de tinta a 1 para tinta completa, en un espacio de color alternativo que el dispositivo realmente pueda renderizar, normalmente CMYK. Esa transformación de tono es frecuentemente una función de Tipo 0, y en este caso la cuadrícula tiene exactamente un eje de entrada.
Este es el contraste claro con la LUT 3D. Una tinta directa representa un único grado de libertad, por lo que su transformación de tono necesita una entrada y la cuadrícula es una línea de muestras, cada una de las cuales contiene el valor CMYK (u otro alternativo) en ese nivel de tono. El cubo RGB necesita tres entradas debido a que su dominio es tridimensional y los canales interactúan. Mismo tipo de función, mismas reglas de interpolación, diferente dimensionalidad; la especificación reutiliza un único evaluador y permite que /Size decida si se está recorriendo una línea, un plano o un cubo. HotPDF envuelve toda la separación en RegisterSeparationLUT, que construye internamente la transformación de tono de Tipo 0 de una entrada a partir de un arreglo plano de bytes y devuelve el nombre del recurso de espacio de color.
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;
El conteo de muestras debe ser un número entero de puntos de cuadrícula: un múltiplo positivo del conteo de componentes del espacio alternativo, y al menos dos puntos para que exista un segmento a interpolar. Si pasa tres bytes por punto frente a un espacio alternativo CMYK, la llamada los rechazará; se trata de la misma validación defensiva que aplica el generador 3D, que es lo que se espera de una función que de otro modo fallaría silenciosamente al momento de imprimir.
Dónde vuelve a aparecer el mismo mecanismo
Una vez que se percibe el Tipo 0 como una tabla de interpolación genérica, otras dos características de control de dispositivos dejan de parecer casos especiales. Una función de transferencia ajusta los valores de los componentes en su camino hacia el dispositivo de salida, y es simplemente una función por canal; HotPDF la registra como un ExtGState a través de RegisterTransferFunctionState, que acepta una función combinada o un arreglo de funciones por canal. Debido a que esas funciones son objetos de función comunes, se les puede pasar el mismo THPDFStreamObject que devuelve RegisterSampledFunction y controlar una curva de transferencia desde una tabla muestreada en lugar de usar una fórmula.
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;
La generación de negro y la eliminación de subcolor se encuentran en la misma familia. Cuando un dispositivo convierte RGB a CMYK, decide qué proporción del componente gris se convertirá en tinta negra, y la especificación expresa esa decisión como una función, mediante las entradas /BG2 y /UCR2 de un diccionario de estado gráfico, siendo cada una una curva de una sola entrada desde el gris calculado hasta una cantidad de negro. Esas también son funciones de Tipo 0 cuando se requiere una curva medida en lugar de una analítica, creadas de la misma manera a través de RegisterSampledFunction y colocadas en el estado gráfico. La lección que se debe conservar es que la función PDF nunca es el lugar donde ocurre la gestión del color; es la tabla de búsqueda que lleva una decisión que usted tomó con un motor de color real, y el Tipo 0 es el único tipo de función lo suficientemente flexible como para contener cualquier decisión.
Para obtener una perspectiva más amplia sobre cómo se emiten las fuentes, las imágenes y los recursos de color en un documento final, consulte nuestro recorrido sobre la salida de informes con fuentes e imágenes. Cuando la salida debe superar una verificación de preflight de impresión o archivo, las reglas de espacio de color e intento de salida cubiertas en la guía de validación de PDF/A, PDF/X y PDF/UA gobiernan cuáles de estas funciones están permitidas y cómo se debe etiquetar el color del dispositivo. Todo esto se incluye en el HotPDF Component para Delphi y C++Builder, junto con las API de sombreado, ICC y separación que se basan en el mismo núcleo de Tipo 0.