Bài viết Kỹ thuật

Kết xuất Chuyển sắc PDF trong Delphi: Hướng trục và Hướng tâm

Một tệp PDF có phần đầu trang (header) mang nền chuyển sắc kiểu Word hoặc Excel, khi kết xuất ra một hình ảnh, từng bị trả về với một hình chữ nhật màu trắng trống trải ở nơi đáng lẽ là sự pha trộn màu sắc. Bộ kết xuất trang của HotPDF giờ đây đã tuân thủ toán tử sh (shading) của PDF đối với các gradient hướng trục Type 2 và hướng tâm Type 3: nó đánh giá hàm của shading dọc theo trục chuyển sắc và vẽ sự pha trộn màu, trong khi các phiên bản trước đó âm thầm bỏ qua toán tử này và để lại vùng đó trắng trơn như giấy. Hai loại shading bao phủ hầu hết mọi chuyển sắc trong tài liệu văn phòng đã được hỗ trợ; các loại lưới (mesh) thì chưa, và bài viết này sẽ chỉ rõ ranh giới đó nằm ở đâu

Tại sao một chuyển sắc PDF lại kết xuất thành một hộp màu trắng?

Một chuyển sắc PDF là một cấu trúc vectơ, chứ không phải một ảnh bitmap mà bộ kết xuất có thể vẽ (blit). Một từ điển shading (ISO 32000-1 §8.7.4.5) mô tả hình học — một trục hoặc một cặp vòng tròn trong mảng Coords — cộng với một hàm màu sắc, và toán tử sh sẽ vẽ shading đó trên vùng cắt hiện tại, cùng một mô hình đồ họa mà HotPDF cung cấp khi bạn vẽ các đường dẫn và vùng tô lên canvas trang. Bộ kết xuất trang của HotPDF duyệt qua luồng nội dung theo từng toán tử, và bất kỳ toán tử nào không có đường dẫn mã xử lý sẽ bị bỏ qua để phần còn lại của trang vẫn kết xuất bình thường. Trước phiên bản 2.335.0, sh nằm trong tập hợp bị bỏ qua đó: một đầu trang hoặc một chuyển sắc toàn trang không đóng góp gì cho đầu ra, vì thế phần nền hiển thị xuyên qua dưới dạng màu trắng. Tệp dữ liệu không bao giờ bị hỏng. Bộ kết xuất đơn giản là không có trình xử lý cho toán tử đó, và một hộp màu trắng chính xác là những gì một trình xử lý bị thiếu biểu hiện

Chuỗi đánh giá hàm đằng sau một shading

Một shading không thể được vẽ cho đến khi hàm của nó được đánh giá, vì thế hệ thống máy móc đó phải được triển khai trước tiên. Cả shading hướng trục Type 2 và hướng tâm Type 3 đều mang theo một /Function ánh xạ một vị trí tham số dọc theo chuyển sắc thành một màu sắc (ISO 32000-1 §7.10), và bộ đánh giá hàm của HotPDF sẽ phân tích FunctionType rồi điều phối trên đó. Phép nội suy mũ Type 2 (§7.10.3) tính toán C0 + t^N * (C1 - C0) với việc kẹp giới hạn DomainRange; các hàm lấy mẫu Type 0 (§7.10.2) đọc một lưới các mẫu 8, 16 hoặc 32-bit và chọn mẫu gần nhất thông qua bản đồ Encode, trường hợp được đề cập chuyên sâu trong bài viết hướng dẫn của chúng tôi về tra cứu màu lấy mẫu Type 0; các hàm ghép nối Type 3 (§7.10.4) lựa chọn một hàm con bằng mảng Bounds và đệ quy vào đó. Các hàm máy tính PostScript Type 4 (§7.10.5) không được đánh giá — chúng tự động giảm cấp xuống một kết quả đánh giá thất bại thay vì đưa ra sai màu, khớp với chính sách thận trọng mà HotPDF áp dụng trên đường dẫn kết xuất. Bộ đánh giá này đã được phát hành trong phiên bản 2.334.0, trước một phiên bản so với bản thân toán tử, bởi vì trình vẽ shading chỉ tốt tương đương với hàm cơ sở bên dưới nó

HotPDF chuyển đổi một chuyển sắc liên tục thành các điểm ảnh như thế nào?

HotPDF xấp xỉ sự pha trộn liên tục bằng một lượt chạy hữu hạn các dải màu đặc. Trình vẽ shading duyệt dọc theo trục chuyển sắc, chia nó thành tối đa 64 dải — ít hơn khi trục ngắn theo các điểm ảnh thiết bị — đánh giá hàm tại vị trí tham số của mỗi dải, và tô một hình chữ nhật vuông góc với trục bằng một chổi cọ đặc (solid brush). Sự đánh đổi ở đây là số lượng dải so với độ mịn: nhiều dải hơn sẽ theo sát sự pha trộn màu sắc chặt chẽ hơn nhưng tốn nhiều lượt tô hơn, và 64 là giới hạn tối đa được xác định sẵn. Bởi vì số lượng dải cũng tỷ lệ với chiều dài trục theo các điểm ảnh thiết bị, nên độ phân giải rất quan trọng. Việc kết xuất cùng một trang ở độ phân giải DPI cao hơn sẽ kéo dài trục đó, do đó một chuyển sắc ngắn sẽ có thêm các dải màu và các sọc của nó trở nên mịn hơn cho đến khi đạt tới giới hạn 64 dải

// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96);   // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300);  // up to 64 bands

Kết xuất một trang có shading thành một ảnh bitmap

Điểm truy cập công khai không đổi: RenderLoadedPageToBitmap nhận một chỉ mục trang bắt đầu từ 0 và một giá trị DPI, trả về một ảnh bitmap 24-bit thuộc sở hữu của người gọi, và đưa lại nil khi thất bại thay vì nâng lỗi, do đó sự hỗ trợ shading là minh bạch đối với mã nguồn bạn đã có sẵn. Một trang từng kết xuất đầu trang chuyển sắc trống trơn giờ đây trả về cùng một ảnh bitmap với sự pha trộn màu được tô vẽ, và không cần thay đổi API nào để có được nó. Một điều đáng ghi nhớ là quyền sở hữu: người gọi phải giải phóng ảnh bitmap được trả về. Toàn bộ quy trình kết xuất — thông dịch luồng nội dung, các ký tự (glyph) nhúng, và bộ nhớ đệm trang — được đề cập trong hướng dẫn kết xuất các trang PDF thành bitmap trong Delphi

var
  Pdf: THotPDF;
  Bmp: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
    begin
      // Page 1 (zero-based) at 150 DPI. A gradient-filled header that
      // used to come back blank now carries its color blend.
      Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
      if Assigned(Bmp) then
      try
        Bmp.SaveToFile('page1.bmp');
      finally
        Bmp.Free;
      end;
    end;
  finally
    Pdf.Free;
  end;
end;

Một biện pháp bảo vệ chống hồi quy (regression) đơn giản có được từ cùng cuộc gọi đó. Hãy kết xuất trang, lấy mẫu một điểm ảnh tại nơi thuộc về dải chuyển sắc, và xác nhận rằng nó không còn là màu trắng trơn như giấy mà bộ kết xuất từng quay về trước đây — một dòng kiểm tra giúp phát hiện việc âm thầm quay lại hành vi không hoạt động cũ

Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
  // True when the sh operator painted; False if the region fell back to white.
  HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
  Bmp.Free;
end;

Những gì HotPDF không vẽ: shading dạng lưới và các cạnh cắt

Bốn loại shading dạng lưới (mesh shading) nằm ngoài phạm vi hỗ trợ, và một tài liệu nên biết trước điều đó khi xử lý. Các lưới tam giác Gouraud dạng tự do (Type 4), lưới Gouraud dạng mạng tinh thể (Type 5), lưới mảng Coons (Type 6) và lưới mảng tích tensor (Type 7), được định nghĩa trong ISO 32000-1 §8.7.4.5.5 đến §8.7.4.5.8, đều không được kết xuất; một trang sử dụng chúng vẫn kết xuất bình thường, chỉ riêng vùng đó được để nguyên trạng. Hai điểm giới hạn khác cũng cần được nêu rõ. Các hình chữ nhật dải màu sẽ bao phủ sọc của shading thay vì được cắt chính xác theo đường dẫn cắt hiện tại, do đó một chuyển sắc được che mặt nạ thành một hình tròn hoặc hình dạng bất thường sẽ được vẽ dưới dạng sọc ranh giới của nó cho đến khi tính năng cắt vùng chính xác được triển khai trong các phiên bản sau. HotPDF cũng giả định đầu ra của hàm là RGB hoặc thang độ xám (grayscale), vì vậy một shading được tạo bằng CMYK hoặc một không gian màu đặc biệt khác sẽ được xấp xỉ giá trị thay vì được quản lý màu sắc đầy đủ. Đối với các tài liệu mà hầu hết các nhóm Delphi và C++Builder thực sự xử lý — các báo cáo, hóa đơn, sao kê và các tệp trang trình bày xuất sang PDF — dải màu hướng trục và hướng tâm bao phủ hầu như mọi chuyển sắc bạn sẽ gặp, còn các bản thiết kế thử nghiệm nặng về dạng lưới là trường hợp nên được xử lý dưới dạng xem trước thay vì bản in thử nghiệm so màu

Bộ kết xuất trang của HotPDF, sự hỗ trợ toán tử sh được mô tả ở đây, và bộ đánh giá hàm Type 0/2/3 bên dưới nó đi kèm như một phần của HotPDF Component dành cho Delphi và C++Builder — một thư viện VCL gốc không có sự phụ thuộc vào DLL bên ngoài, bao trùm việc tạo, chỉnh sửa, trích xuất văn bản và kết xuất trang trong cùng một gói phần mềm