PDF 함수는 사양에서 비교적 잘 알려지지 않은 영역입니다. 대부분의 개발자는 두 색상 사이를 페이드 처리하기 위해 Type 2 축형 셰이딩에 필요한 요소로 한 번 접한 후 다시 검토하지 않습니다. 그러나 이는 다소 아쉬운 부분입니다. 함수 메커니즘은 셰이딩, 트랜스퍼 함수(transfer function), 하프톤 스팟 함수, 별색(separation) 틴트 및 소프트 마스크 트랜스퍼 곡선 등에 포맷이 재사용하는 소형 범용 평가기이기 때문입니다. 네 가지 함수 유형 중에서 Type 0은 가장 강력하면서도 가장 오해받는 유형입니다. 이는 샘플링된 함수(sampled function)로, 리더가 보간을 적용하여 값을 결정하는 다차원 출력값 격자입니다. 격자에는 어떤 숫자든 입력할 수 있으므로 Type 0 함수는 색상 룩업 테이블(color lookup table, LUT)과 같은 임의의 비선형 매핑을 표현할 수 있습니다.
이 글에서는 ISO 32000-1 §7.10.2에 정의된 Type 0 딕셔너리를 자세히 알아보고, 문서 파이프라인에서 가장 중요한 두 가지 사용 사례인 3-입력 RGB-to-RGB 색상 보정 LUT와 1-입력 별색 틴트 변환을 보여줍니다. 동일한 샘플링 함수 빌더가 두 작업을 모두 지원하며, 두 사례의 차이는 격자가 가지는 입력 수에 있습니다.
샘플링된 함수는 리더가 보간하는 그리드
Type 0 함수는 규칙적인 격자에 샘플을 저장하고 이를 보간하여 m-입력 벡터를 n-출력 벡터에 매핑합니다. ISO 32000-1 §7.10.2는 이 격자를 구성하는 키를 나열하고 있습니다. /Domain은 입력당 두 개의 숫자, 즉 각 입력 축의 상한과 하한을 나타냅니다. /Range는 각 출력 구성 요소당 두 개의 숫자를 보관합니다. /Size는 각 입력 축을 따른 샘플 수를 나타내는 m개의 정수 배열로, 3차원에서 한 변이 12개 샘플인 격자는 /Size [12 12 12]가 되며 1,728개의 격자점을 저장합니다. /BitsPerSample은 저장되는 각 값의 정밀도를 설정합니다. HotPDF는 Table 38에서 허용하는 값과 일치하도록 1, 2, 4, 8, 12, 16, 24 및 32비트를 지원합니다.
샘플 스트림은 정해진 순서대로 읽힙니다. 첫 번째 입력 차원이 가장 빠르게 변하고, 이어서 두 번째 차원 순서로 처리되며, 각 격자점에서 n개의 출력 구성 요소가 차례대로 저장됩니다. 8비트 환경에서 작동하는 RGB-to-RGB 테이블의 경우, 격자점당 3바이트로 구성되며 빨간색 출력, 초록색 출력, 파란색 출력 순서로 배치되고 빨간색 입력이 가장 먼저 스캔됩니다. 두 개의 추가 키가 연속적인 데이터를 정수 격자에 매핑합니다. /Encode는 각 입력을 /Domain 간격에서 샘플 인덱스 범위인 0부터 Size[i] - 1까지로 매핑하며, /Decode는 저장된 원시 정수 값을 다시 /Range 간격으로 매핑합니다. 기본값으로 두는 경우, [0 1] 범위의 입력은 전체 격자에 정밀하게 위치하고 저장된 255바이트 값은 출력 범위의 최댓값으로 디코딩됩니다. 이는 [0,1]-정규화된 컬러 LUT에 적합한 설정입니다.
1차 보간 대 3차 보간
격자점 사이에서 리더는 보간을 수행해야 하며, /Order를 통해 보간 방법을 선택합니다. /Order 1은 다중 선형 보간(multilinear interpolation)으로, 한 축을 따라서는 선형(linear), 두 축에 대해서는 이중 선형(bilinear), 세 축에 대해서는 삼중 선형(trilinear)으로 작동합니다. 이는 연산 속도가 빠르고 대부분의 뷰어 하드웨어에서 처리하는 방식이며, 부드러운 색상 변환에서 고급 보간과 차이를 느끼기 어렵습니다. /Order 3은 3차 스플라인(cubic-spline) 보간을 요청하며, 연산 부담이 늘어나는 대신 샘플들 사이에 더 부드러운 곡선을 피팅(fitting)합니다.
격자 밀도와 곡선 부드러움 사이에는 트레이드오프가 존재합니다. 3차 보간은 격자가 성기고 매핑이 가시적인 곡률을 가질 때 효과적입니다. 멀리 떨어진 두 샘플 사이을 직선으로 이으면 그라데이션에서 톤 곡선이 깨지는 현상이 나타날 수 있기 때문입니다. 격자가 밀밀한 경우에는 구간이 짧아 선형 보간만으로도 곡선을 매끄럽게 표현할 수 있어 3차 보간의 메리트가 줄어듭니다. 실무적으로는 작은 격자나 급격한 변환 시에만 /Order 3을 사용하고, 그 외에는 선형 보간 기본값을 유지하는 것이 좋습니다. /Order는 Type 0 함수에만 적용되며, HotPDF는 1 또는 3 이외의 값을 거부합니다.
3D LUT: 세 개의 입력, 세 개의 출력
RGB-to-RGB 색상 보정은 컬러 그레이딩 및 장치 매칭에 사용되는 클래식 3D LUT인 3-입력 격자의 대표적인 사례입니다. 큐브의 각 축은 하나의 입력 채널이고 모든 격자점은 해당 입력 좌표의 보정된 RGB 삼중값을 저장하며, 리더는 입력 색상 주변의 코너 샘플들을 삼중 선형으로 보간합니다. 보정된 빨간색 값이 단순히 빨간색 입력뿐만 아니라 초록색 및 파란색 입력값에도 영향을 받을 수 있으므로 세 개의 입력이 필수적입니다. 채널별 곡선으로는 이러한 채널 간 상호 작용(crosstalk)을 표현할 수 없지만, 큐브 구조는 이를 처리할 수 있습니다.
HotPDF는 /Domain, /Range, /Size, /BitsPerSample 및 샘플 바이트를 직접 수신하여 함수 객체를 반환하는 RegisterSampledFunction을 통해 Type 0 스트림을 빌드합니다. 표준 정규화된 큐브의 경우, 세 개의 입력 축과 세 개의 출력 모두에 대해 [0,1] 범위를 지정하고, N x N x N 크기 및 플랫(flat) 샘플 테이블을 전달합니다. 빌더는 바이트 수가 격자와 일치하는지 검증합니다: 바이트 단위 정렬된 정밀도의 경우, OutputCount x (BitsPerSample div 8) x 크기의 곱을 예상하며, 배열의 길이가 맞지 않으면 예외를 발생시킵니다. 따라서 스트라이드 계산 오류가 등록 시점에 명확히 잡히게 됩니다.
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 함수가 아니라 격자를 어떻게 채우느냐에 달려 있습니다. 가장 표준적인 방법은 소프트 프루프(soft-proof)를 실행하는 엔진과 동일한 ICC 관리 변환을 통해 각 격자점을 계산하는 것입니다. 이를 통해 격자의 수치들이 정의된 소스 및 대상 프로파일에 대해 실질적인 의미를 갖게 됩니다. 변환 범위가 되는 프로파일을 RegisterICCProfile로 등록하면, 이는 ICC Based 컬러 스페이스(1, 3 또는 4가지 구성 요소)를 기록하고 LUT가 공급되는 콘텐츠에 연결할 수 있는 리소스 이름을 반환합니다. Type 0 함수는 보간 테이블을 포함하고, ICC 프로파일은 끝점의 의미 정보를 가집니다.
1차원의 경우: 별색 틴트 변환
별색(Separation) 컬러 스페이스는 완전히 다른 작업에 동일한 메커니즘을 적용합니다. ISO 32000-1 §8.6.6.4에 정의된 별색 스페이스는 이름과 틴트 변환(tint transform)을 페어링하여 팬톤(Pantone)이나 바니시(varnish) 같은 단일 컬러런트(colorant, 스팟 잉크)를 표현합니다. 틴트 변환은 1차원 틴트 값(잉크 없음인 0부터 가득 참인 1까지)을 장치에서 렌더링할 수 있는 대체 컬러 스페이스(일반적으로 CMYK)에 매핑하는 함수입니다. 이 틴트 변환은 종종 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;
샘플 수는 격자점의 정수여야 합니다: 대체 스페이스 구성 요소 수의 양의 배수이며 보간할 구간이 존재해야 하므로 최소 2개 이상의 점이어야 합니다. CMYK 대체 스페이스에 대해 포인트당 3바이트를 전달하면 3D 빌더와 동일한 방어적 검증이 적용되어 호출이 거부됩니다. 이는 나중에 인쇄 시점의 원인 모를 오류를 방지하기 위해 필수적입니다.
동일한 메커니즘이 다시 사용되는 사례
Type 0를 일반 보간 테이블로 이해하면, 장치 제어 기능 중 두 가지가 더 이상 예외 케이스로 보이지 않습니다. 트랜스퍼 함수(transfer function)는 출력 장치로 전달되는 도중 컴포넌트 값을 조정하며, 채널별 단일 함수에 불과합니다. HotPDF는 하나의 통합 함수 또는 채널별 함수 배열을 허용하는 RegisterTransferFunctionState를 통해 이를 ExtGState로 등록합니다. 이 함수들은 일반 함수 객체이므로 RegisterSampledFunction이 반환하는 THPDFStreamObject를 직접 전달하여 수식이 아닌 샘플링된 테이블을 기반으로 트랜스퍼 곡선을 구동할 수 있습니다.
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(BG) 및 Undercolor removal(UCR)도 동일한 제품군에 속합니다. 장치가 RGB를 CMYK로 변환할 때 그레이 컴포넌트 중 얼마만큼을 검은색 잉크로 처리할지 결정하며, 사양은 이 결정을 그래픽 상태 딕셔너리의 /BG2 및 /UCR2 항목에 함수로 기록합니다. 이들은 각각 계산된 그레이 값에서 검은색 양으로 이어지는 단일 입력 곡선입니다. 수식이 아닌 정밀하게 측정된 곡선을 사용하려는 경우 이들 역시 Type 0 함수이며, 동일하게 RegisterSampledFunction을 통해 빌드되고 그래픽 상태에 저장됩니다. 기억해야 할 교훈은 PDF 함수가 실제로 색상 관리를 수행하는 곳이 아니라는 점입니다. PDF 함수는 실제 색상 엔진으로 내린 결정을 전달하는 룩업 테이블이며, Type 0는 그러한 모든 결정을 전달할 수 있을 만큼 유연한 단 하나의 함수 유형입니다.
글꼴, 이미지 및 색상 리소스가 최종 문서에 출력되는 방식에 대한 자세한 내용은 글꼴 및 이미지를 포함한 보고서 출력 가이드를 참조하십시오. 출력물이 아카이브 또는 인쇄 프리플라이트 검사를 거쳐야 하는 경우, PDF/A, PDF/X, PDF/UA 검증 가이드에서 다루는 컬러 스페이스 및 출력 인텐트(output-intent) 규칙에 따라 허용되는 함수 및 장치 색상 태깅 방식이 결정됩니다. 이 모든 기능은 동일한 Type 0 코어를 기반으로 구축된 셰이딩, ICC 및 별색 API와 함께 Delphi 및 C++Builder용 HotPDF 컴포넌트에서 제공됩니다.