Hàm PDF là một trong những góc yên tĩnh hơn của thông số kỹ thuật. Hầu hết các nhà phát triển gặp chúng một lần, như thứ mà Type 2 axial shading cần để chuyển mờ giữa hai màu, và không bao giờ xem lại nữa. Điều đó thật đáng tiếc, bởi vì bộ máy hàm là một trình đánh giá đa mục đích nhỏ mà định dạng tái sử dụng cho các shading, hàm truyền (transfer function), hàm điểm nửa tông (halftone spot function), màu pha (separation tint), và đường cong truyền mặt nạ mềm (soft-mask transfer curve). Trong số bốn loại hàm, Type 0 là loại mạnh mẽ nhất và ít được hiểu nhất. Nó là một hàm mẫu (sampled function): một lưới đa chiều của các giá trị đầu ra mà trình đọc nội suy giữa chúng. Bởi vì lưới có thể giữ bất kỳ con số nào bạn đưa vào, một hàm Type 0 có thể biểu thị một ánh xạ phi tuyến tính tùy ý, đó chính là hình dáng chính xác của một bảng tra cứu màu sắc (color lookup table).
Bài viết này đi qua từ điển Type 0 như cách ISO 32000-1 định nghĩa nó trong mục §7.10.2, sau đó trình bày hai trường hợp quan trọng nhất trong một luồng xử lý tài liệu: một LUT hiệu chỉnh màu RGB-sang-RGB ba đầu vào, và một chuyển đổi màu pha (spot-color tint transform) một đầu vào. Cùng một trình xây dựng hàm mẫu phục vụ cả hai, và sự khác biệt giữa chúng hoàn toàn là câu hỏi về việc lưới có bao nhiêu đầu vào.
Hàm mẫu là một lưới mà trình đọc nội suy
Một hàm Type 0 ánh xạ một vectơ đầu vào m sang một vectơ đầu ra n bằng cách lưu trữ các mẫu trên một lưới đều và nội suy giữa chúng. ISO 32000-1 §7.10.2 liệt kê các khóa mô tả lưới đó. /Domain giữ hai số cho mỗi đầu vào, giới hạn dưới và trên của mỗi trục đầu vào. /Range giữ hai số cho mỗi thành phần đầu ra. /Size là một mảng gồm m số nguyên cho biết số lượng mẫu dọc theo mỗi trục đầu vào, vì vậy một lưới có mười hai mẫu trên một cạnh trong không gian ba chiều sẽ có /Size [12 12 12] và lưu trữ 1.728 điểm lưới. /BitsPerSample thiết lập độ chính xác của từng giá trị được lưu trữ; HotPDF chấp nhận 1, 2, 4, 8, 12, 16, 24, và 32 bit, khớp với các giá trị mà Bảng 38 cho phép.
Stream mẫu được đọc theo thứ tự cố định. Chiều đầu vào đầu tiên biến đổi nhanh nhất, sau đó đến chiều thứ hai, v.v., và tại mỗi điểm lưới, n thành phần đầu ra được lưu trữ theo thứ tự. Đối với một bảng RGB-sang-RGB, đó là ba byte trên mỗi điểm lưới ở độ phân giải tám bit, được sắp xếp theo thứ tự đầu ra đỏ (red-output), đầu ra xanh lá (green-output), đầu ra xanh dương (blue-output), quét qua đầu vào đỏ trước. Hai khóa nữa ánh xạ thế giới liên tục lên lưới số nguyên. /Encode ánh xạ từng đầu vào từ khoảng /Domain của nó sang phạm vi chỉ mục mẫu từ 0 đến Size[i] - 1, và /Decode ánh xạ các số nguyên thô được lưu trữ trở lại các khoảng /Range. Khi bạn để chúng ở chế độ mặc định, một đầu vào trải dài trên [0 1] sẽ nằm gọn gàng trên toàn bộ lưới và một byte được lưu trữ có giá trị 255 sẽ được giải mã lên mức cao nhất của phạm vi đầu ra của nó, đó chính là những gì một color LUT chuẩn hóa [0,1] mong muốn.
Order 1 đối chiếu với Order 3
Giữa các điểm lưới, trình đọc phải thực hiện nội suy, và /Order chọn cách thức thực hiện. /Order 1 là nội suy đa tuyến tính (multilinear interpolation): tuyến tính dọc theo một trục, song tuyến tính (bilinear) trên hai trục, tam tuyến tính (trilinear) trên ba trục. Nó nhanh, đó chính xác là những gì phần cứng trong hầu hết các trình xem thực hiện, và đối với một chuyển đổi màu sắc mượt mà, nó thường không thể phân biệt được với bất kỳ phương pháp phức tạp nào khác. /Order 3 yêu cầu nội suy cubic-spline, giúp khớp một đường cong mượt mà hơn qua các mẫu với chi phí tính toán nhiều hơn và một vùng hỗ trợ rộng hơn xung quanh mỗi điểm được đánh giá.
Sự cân nhắc là mật độ lưới so với độ mượt của đường cong. Bậc cubic chứng minh giá trị của mình khi lưới thô và ánh xạ có độ cong rõ rệt, bởi vì một đường thẳng nối giữa hai mẫu ở xa có thể làm phẳng một đường cong tông màu theo cách mà mắt nhận ra trên các gradient. Khi lưới đã dày đặc, các đoạn đủ ngắn để nội suy tuyến tính theo sát đường cong và nội suy cubic mang lại ít giá trị. Một quy tắc thực tế là chỉ tìm đến /Order 3 với các lưới nhỏ hoặc các chuyển đổi dốc, và nếu không hãy để nó ở chế độ mặc định tuyến tính. Lưu ý rằng /Order chỉ áp dụng cho các hàm Type 0, và HotPDF từ chối bất kỳ giá trị nào khác ngoài 1 hoặc 3.
3D LUT: ba đầu vào, ba đầu ra
Hiệu chỉnh màu RGB-sang-RGB là trường hợp kinh điển cho một lưới ba đầu vào, công nghệ 3D LUT cổ điển được sử dụng trong chỉnh màu (color grading) và khớp thiết bị. Mỗi trục của khối lập phương là một kênh đầu vào, mọi điểm lưới lưu trữ bộ ba RGB đã hiệu chỉnh cho tọa độ đầu vào đó, và trình đọc nội suy tam tuyến tính các mẫu góc xung quanh bất kỳ màu nào đi vào. Ba đầu vào là không thể tránh khỏi ở đây vì màu đỏ đã hiệu chỉnh có thể phụ thuộc vào màu xanh lá và xanh dương đầu vào, chứ không chỉ vào màu đỏ đầu vào; một đường cong trên mỗi kênh không thể biểu thị sự nhiễu chéo kênh (channel crosstalk), nhưng một khối lập phương thì có thể.
HotPDF xây dựng stream Type 0 thông qua RegisterSampledFunction, lệnh này nhận trực tiếp các byte /Domain, /Range, /Size, /BitsPerSample, và các byte mẫu và trả về đối tượng hàm. Đối với một khối lập phương chuẩn hóa tiêu chuẩn, bạn truyền các biên [0,1] trên cả ba trục đầu vào và cả ba đầu ra, kích thước N x N x N, và bảng mẫu đã được làm phẳng. Trình xây dựng xác nhận rằng số lượng byte khớp với lưới: đối với độ sâu căn chỉnh byte, nó mong đợi OutputCount x (BitsPerSample div 8) x tích của các kích thước, và sẽ báo lỗi nếu mảng có độ dài sai, do đó một bước sải chân (stride) bị tính toán sai sẽ thất bại rõ ràng tại thời điểm đăng ký thay vì hiển thị dưới dạng rác sau đó.
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;
Tính chính xác về đo màu (colorimetric correctness) của khối lập phương nằm ở cách bạn điền vào nó, chứ không phải ở hàm PDF. Con đường đáng tin cậy là tính toán từng điểm lưới thông qua một chuyển đổi do ICC quản lý, cùng một công cụ thúc đẩy quá trình thử màu trên màn hình (soft-proof), để các con số trong lưới có ý nghĩa so với hồ sơ nguồn và đích được xác định. Đăng ký các hồ sơ ràng buộc chuyển đổi bằng RegisterICCProfile, lệnh này ghi lại một không gian màu ICCBased (1, 3, hoặc 4 thành phần) và trả về một tên tài nguyên mà bạn có thể gắn vào nội dung mà LUT cấp dữ liệu. Hàm Type 0 mang bảng nội suy; hồ sơ ICC mang ý nghĩa của các điểm cuối.
Trường hợp 1D: chuyển đổi màu pha (spot-color tint transform)
Không gian màu Separation dựa trên cùng một cơ chế cho một công việc hoàn toàn khác. Một không gian Separation, được định nghĩa trong ISO 32000-1 §8.6.6.4, đại diện cho một chất tạo màu duy nhất, một mực pha (spot ink) chẳng hạn như màu Pantone hoặc vecni, bằng cách ghép nối một tên gọi với một chuyển đổi sắc thái (tint transform): một hàm ánh xạ giá trị sắc thái một chiều, từ 0 cho không có mực đến 1 cho đầy mực, lên một không gian màu thay thế mà thiết bị thực sự có thể kết xuất, thường là CMYK. Chuyển đổi sắc thái đó thường là một hàm Type 0, và bây giờ lưới có chính xác một trục đầu vào.
Đây là sự tương phản rõ ràng với 3D LUT. Một mực pha có một bậc tự do, vì vậy chuyển đổi sắc thái của nó cần một đầu vào và lưới là một dòng các mẫu, mỗi mẫu chứa giá trị CMYK (hoặc giá trị thay thế khác) ở mức sắc thái đó. Khối lập phương RGB cần ba đầu vào vì miền của nó là ba chiều và các kênh tương tác với nhau. Cùng một loại hàm, cùng các quy tắc nội suy, số chiều khác nhau; thông số kỹ thuật tái sử dụng một bộ đánh giá và để /Size quyết định xem bạn đang đi trên một đường thẳng, một mặt phẳng hay một khối lập phương. HotPDF đóng gói toàn bộ phân tách màu trong RegisterSeparationLUT, lệnh này xây dựng chuyển đổi sắc thái Type 0 một đầu vào từ một mảng byte phẳng bên trong và trả về tên tài nguyên không gian màu.
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;
Số lượng mẫu phải là một số nguyên các điểm lưới: một bội số dương của số thành phần của không gian thay thế, và ít nhất hai điểm để có một đoạn nội suy. Truyền ba byte cho mỗi điểm đối với một không gian thay thế CMYK và lệnh gọi sẽ từ chối nó, cùng một kiểm tra phòng thủ mà trình dựng 3D áp dụng, đây là điều bạn muốn từ một hàm mà nếu không sẽ thất bại một cách âm thầm vào thời điểm in ấn.
Nơi mà cùng một cơ chế hiển thị lại
Một khi bạn coi Type 0 là một bảng nội suy chung, hai tính năng điều khiển thiết bị khác sẽ không còn giống như những trường hợp đặc biệt nữa. Một hàm truyền (transfer function) điều chỉnh các giá trị thành phần trên đường truyền của chúng đến thiết bị đầu ra, và nó chỉ đơn thuần là một hàm cho mỗi kênh; HotPDF đăng ký nó dưới dạng ExtGState thông qua RegisterTransferFunctionState, lệnh này chấp nhận một hàm kết hợp duy nhất hoặc một mảng các hàm cho mỗi kênh. Bởi vì những hàm đó là các đối tượng hàm thông thường, bạn có thể truyền cho nó chính THPDFStreamObject mà RegisterSampledFunction trả về và điều khiển một đường cong truyền từ một bảng mẫu thay vì một công thức.
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;
Quá trình tạo màu đen (black generation) và loại bỏ màu dưới (undercolor removal) nằm trong cùng một họ. Khi một thiết bị chuyển đổi RGB sang CMYK, nó quyết định lượng thành phần màu xám sẽ mang theo dưới dạng mực đen, và thông số kỹ thuật biểu thị quyết định đó dưới dạng một hàm, các mục nhập /BG2 và /UCR2 của từ điển trạng thái đồ họa (graphics-state dictionary), mỗi mục là một đường cong đầu vào đơn từ giá trị màu xám được tính toán sang lượng màu đen. Đó cũng là các hàm Type 0 khi bạn muốn một đường cong đo lường hơn là một đường cong phân tích, được xây dựng theo cùng một cách thông qua RegisterSampledFunction và được đặt trong trạng thái đồ họa. Bài học đáng ghi nhớ là hàm PDF không bao giờ là nơi quản lý màu sắc diễn ra; nó là bảng tra cứu mang theo quyết định bạn đưa ra bằng một công cụ màu thực sự, và Type 0 là loại hàm duy nhất đủ linh hoạt để mang theo bất kỳ quyết định nào.
Để có bức tranh rộng hơn về cách các phông chữ, hình ảnh và tài nguyên màu được xuất ra trong một tài liệu hoàn chỉnh, hãy xem hướng dẫn chi tiết của chúng tôi về đầu ra báo cáo với phông chữ và hình ảnh. Khi đầu ra phải vượt qua kiểm tra trước khi bay để lưu trữ hoặc in ấn (preflight check), các quy tắc không gian màu và ý định đầu ra được đề cập trong hướng dẫn xác thực PDF/A, PDF/X và PDF/UA sẽ chi phối các hàm nào trong số này được phép và cách ghi thẻ màu thiết bị. Tất cả đều đi kèm trong HotPDF Component dành cho Delphi và C++Builder, cùng với các API shading, ICC và separation được xây dựng trên cùng lõi Type 0.