Technical Article

Nén Ảnh Hai Màu JBIG2 Gốc trong PDF Delphi

Một hợp đồng được quét là vài trăm chấm mỗi inch mực đen trên giấy trắng. Được lưu dưới dạng bitmap một bit mỗi pixel, nó đã nhỏ, nhưng một trăm trang như vậy vẫn làm phình một PDF quá lớn để gửi email. Bộ lọc phù hợp thay đổi phép tính. JBIG2 là nén tỷ lệ cao nhất mà ISO 32000-1 định nghĩa cho hình ảnh hai màu, và trên một chồng văn bản được quét, nó thường xuyên giảm một nửa so với CCITT Group 4. Đây là bộ lọc cần dùng khi đầu vào là fax, quét, hoặc được giảm xuống còn hai màu, và HotPDF có thể ghi nó trực tiếp vào PDF

Định dạng đạt được tỷ lệ với hai ý tưởng mà một codec hình ảnh chung không có. Nó mô hình hóa cách các nét đen nằm trên nền trắng, và nó nhận ra rằng một trang được quét chủ yếu là cùng một vài trăm hình dạng glyph được lặp lại hàng nghìn lần. Hiểu cả hai cho phép bạn chọn các tùy chọn mã hóa có chủ ý thay vì đoán mò

Vị trí của JBIG2 trong thông số PDF

ISO 32000-1 liệt kê JBIG2Decode trong các bộ lọc luồng ở §7.4.7, có sẵn từ PDF 1.4 trở đi. Nó chỉ áp dụng cho một nơi: các image XObject có /BitsPerComponent là 1 và không gian màu giải quyết thành một kênh duy nhất. Đó là toàn bộ điểm. JBIG2 là codec hai màu, vì vậy nó không bao giờ cạnh tranh với DCT hay JPXDecode trên ảnh chụp. Nó cạnh tranh với CCITTFaxDecode, các bộ lọc fax Group 3 và Group 4, chính xác trên loại trang hai màu mà máy quét tài liệu tạo ra

Bộ giải mã sử dụng tổ chức JBIG2 nhúng mà tiêu chuẩn gọi là hồ sơ PDF, nơi mỗi luồng hình ảnh chứa một chuỗi các đoạn thay vì một bitstream thuần túy. Một luồng /JBIG2Globals tùy chọn mang các đoạn được chia sẻ trên nhiều hình ảnh trong cùng một tài liệu, đây là cơ chế cho phép nội dung lặp lại được lưu trữ một lần cho toàn bộ tệp thay vì mỗi trang một lần. HotPDF phát ra luồng mỗi hình ảnh theo mặc định và giữ kênh globals trống trừ khi một backend yêu cầu nó

Kiến trúc mã hóa backend-first

Một bộ mã hóa JBIG2 hoàn chỉnh là một phần mềm lớn, và các phần tích cực nhất của nó trong lịch sử bị ràng buộc bởi các bằng sáng chế và được phân phối theo các giấy phép không phù hợp với mọi sản phẩm. HotPDF giải quyết căng thẳng đó bằng cách tách interface khỏi engine. Unit HPDFJBIG2 định nghĩa các lệnh gọi mà phần còn lại của thư viện thực hiện, và nó đi kèm với một bộ mã hóa tích hợp khiêm tốn để JBIG2 hoạt động ngay lập tức. Khi bạn cần tỷ lệ cấp sản xuất, bạn đăng ký một engine mạnh hơn và thư viện ủy thác cho nó, không có thay đổi nào đối với mã gọi của bạn

Việc chuyển đổi là một lệnh gọi đăng ký duy nhất. Không có backend nào được đăng ký, bộ mã hóa quay trở lại đường dẫn tích hợp của nó. Đăng ký một cái và mọi lần mã hóa tiếp theo chạy qua nó

uses
  HPDFJBIG2;

// Truy vấn xem cái gì đang hoạt động, sau đó có thể cài đặt tùy chọn một cỗ máy (engine) mạnh hơn.
if not IsJBIG2EncoderBackendAvailable then
  // Phụ trợ cấp sản xuất (Production backend) không hiện diện: HotPDF sử dụng luồng MMR tích hợp sẵn của nó.
  RegisterJBIG2EncoderBackend(MyVendorJBIG2Encode);

// Sau đó, để quay trở lại hành vi mặc định (built-in behaviour):
// ClearJBIG2Backends;

Hook tương tự tồn tại cho việc giải mã qua RegisterJBIG2DecoderBackend, với IsJBIG2DecoderBackendAvailable để thăm dò nó. Đây là lý do tại sao một thư viện đi kèm với đường dẫn tích hợp nhỏ cộng với seam backend thay vì một bộ mã hóa nguyên khối. Đường dẫn tích hợp giữ nhị phân gọn nhẹ và không bị ràng buộc giấy phép, trong khi seam cho phép một nhóm đã cấp phép bộ mã hóa đầy đủ kết nối nó vào mà không cần chạm vào lớp ghi PDF chút nào

Những gì các tùy chọn mã hóa thực sự đánh đổi

Mã hóa được cấu hình qua TJBIG2EncodeOptions, một record với các trường Lossless, UseGlobalSegments, UseSymbolDictionary, và LossyLevel. Wrapper thân thiện với component THPDFJBIG2Options xuất bản Lossless, UseSymbolDictionary, và LossyLevel để chúng có thể được đặt từ Object Inspector, và nó chuyển đổi sang record bên trong. Ba ý định điều khiển các cài đặt

Tái tạo không mất mát giữ nguyên từng pixel. Đặt Lossless thành True và để LossyLevel ở không, và bitmap được giải mã giống hệt bit với đầu vào. Đây là lựa chọn an toàn duy nhất cho nghệ thuật đường nét, bản vẽ kỹ thuật, và bất kỳ trang nào mà một pixel bị bỏ có thể thay đổi ý nghĩa, chẳng hạn như chữ ký hoặc con dấu. Mã hóa từ điển ký hiệu bật khử trùng lặp nhận biết văn bản và là tùy chọn phân tách JBIG2 khỏi các bộ lọc fax. Mức lossy, một số nguyên từ 0 đến 9, cho phép một backend có khả năng đánh đổi độ trung thực để có kích thước nhỏ hơn bằng cách coi các dấu gần giống nhau là cùng một ký hiệu. Không có nghĩa là không mất mát. Bộ mã hóa tích hợp chỉ tôn trọng đường dẫn không mất mát và bỏ qua bất kỳ mức lossy nào khác không, vì vậy các mức cao hơn chỉ có hiệu lực khi backend triển khai chúng được đăng ký

var
  Options: TJBIG2EncodeOptions;
begin
  Options := DefaultJBIG2EncodeOptions;   // Lossless True, sử dụng symbol dictionary
  Options.Lossless := True;
  Options.LossyLevel := 0;                // 0 để giữ lại mọi pixel
  Options.UseSymbolDictionary := True;    // dedupe (loại bỏ trùng lặp) các ký tự (glyph) lặp lại
  // Chuyển Options cho backend, hoặc để THPDFJBIG2Options mang chúng.
end;

Từ điển ký hiệu và tại sao các lần quét văn bản thắng

Một trang văn bản được quét không thực sự là hình ảnh của các từ. Đó là cùng một chữ cái e được in vài trăm lần, cùng chữ t, cùng dấu phẩy, mỗi trường hợp là một bản sao hơi nhiễu của một hình dạng cơ bản. Một từ điển ký hiệu nắm bắt cấu trúc đó. Bộ mã hóa thu thập các dấu phân biệt trên trang vào một từ điển, lưu trữ mỗi hình dạng một lần, và sau đó ghi lại trang dưới dạng danh sách các vị trí tham chiếu đến các mục từ điển. Một nghìn lần xuất hiện của cùng một glyph tốn một bitmap được lưu trữ cộng với một nghìn vị trí rẻ

Đây chính xác là nơi JBIG2 vượt trội so với CCITT Group 4. Group 4 mã hóa từng dòng quét so với dòng phía trên nó mà không có khái niệm về glyph, vì vậy nó trả toàn bộ chi phí của mỗi chữ cái mỗi khi chữ cái xuất hiện. JBIG2 trả một lần. Khi cùng một từ điển được thăng lên luồng globals cấp tài liệu, tiết kiệm nhân lên qua một lần quét nhiều trang, vì các hình dạng được chia sẻ từ trang này sang trang khác được lưu trữ một lần duy nhất cho toàn bộ tệp. Trên văn bản dày đặc, sự khác biệt không phải là nhỏ. Đó là lý do tại sao JBIG2 tồn tại

Vùng chung và MMR cho mọi thứ khác

Không phải mọi hình ảnh hai màu đều là văn bản. Bản đồ, sơ đồ, bản vẽ kỹ thuật, và các trang hỗn hợp có nghệ thuật đường nét mà không từ điển nào có thể tóm tắt. Đối với những thứ đó, JBIG2 mã hóa một vùng chung, một hình chữ nhật các pixel được nén trực tiếp mà không có bất kỳ đào tạo ký hiệu nào. Tiêu chuẩn cho phép một vùng chung sử dụng MMR, mã hóa READ sửa đổi mà fax Group 4 đã sử dụng, mô hình hóa từng hàng pixel so với hàng phía trên nó

Đây là đường dẫn HotPDF đi kèm trong bộ mã hóa tích hợp. Khi không có backend nào được đăng ký và yêu cầu là không mất mát, thư viện nén bitmap dưới dạng một vùng MMR chung duy nhất và bọc nó trong cấu trúc đoạn JBIG2 mà hồ sơ PDF yêu cầu. Nó không cần từ điển, không cần lượt đào tạo, và không cần hình ảnh thứ hai để tham chiếu, vì vậy đây là mặc định đáng tin cậy cho nghệ thuật đường nét và nội dung hai màu hỗn hợp. Nó sẽ không khớp với bộ mã hóa từ điển ký hiệu đầy đủ trên văn bản thuần túy, nhưng nó luôn đúng, luôn không mất mát, và luôn có mặt. Bề mặt mã hóa cho nó là một lệnh gọi

var
  Encoder: THPDFJBIG2Encoder;
  ImageData: TJBIG2ByteArray;
  Scanlines: TJBIG2ScanlineArray;  // một mảng byte cho mỗi hàng, dạng MSB-first
  W, H: Integer;
begin
  // Scanlines, W và H mô tả một trang 1-bit; mỗi hàng (row) có dung lượng là (W + 7) div 8 byte.
  Encoder := THPDFJBIG2Encoder.Create;
  try
    if Encoder.EncodeToByteArray(Scanlines, W, H, ImageData) then
      // ImageData giờ đã chứa một luồng JBIG2 sẵn sàng chờ /JBIG2Decode XObject đón nhận.
      ;
  finally
    Encoder.Free;
  end;
end;

Bật nó khi bạn xây dựng tài liệu

Để sử dụng hàng ngày, bạn không chạm vào lớp mã hóa trực tiếp. HotPDF hiển thị JBIG2 như một lựa chọn nén hình ảnh trên tài liệu. Enum THPDFImageCompressionType bao gồm icJBIG2 bên cạnh các tùy chọn Flate, JPEG, và CCITT, và tài liệu mang một thuộc tính JBIG2Options kiểu THPDFJBIG2Options giữ các cài đặt được sử dụng khi nén đó được chọn. Cấu hình cả hai trước khi bạn thêm các hình ảnh hai màu bạn muốn nén theo cách này

var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.ImageCompressionType := icJBIG2;      // dẫn các hình ảnh 1-bit qua JBIG2
    Pdf.JBIG2Options.Lossless := True;        // giữ lại từng điểm pixel một
    Pdf.JBIG2Options.UseSymbolDictionary := True;
    Pdf.JBIG2Options.LossyLevel := 0;
    // Thêm các trang và đặt các hình ảnh 1-bit được quét của bạn ở đây.
  finally
    Pdf.Free;
  end;
end;

Một tiện lợi đáng chú ý là add-on DBGridHotPDFExport, kết xuất một TDBGrid thẳng sang PDF. Đầu ra của nó chủ yếu là các đường và văn bản hai màu, vì vậy một tài liệu được cấu hình cho JBIG2 giữ cho các xuất đó nhỏ gọn mà không cần bất kỳ xử lý thêm nào từ phía bạn. Hai chủ đề liên quan trên blog này đi sâu hơn vào quy trình làm việc xung quanh. Để biết cách hình ảnh và phông chữ được đặt xuống khi bạn xây dựng báo cáo, xem đầu ra báo cáo với phông chữ và hình ảnh trong Delphi. Khi một tài liệu nén phải đáp ứng một hồ sơ lưu trữ, các quy tắc trong xác nhận PDF/A, PDF/X, và PDF/UA trong Delphi cho bạn biết bộ lọc nào một mức tuân thủ nhất định chấp nhận. JBIG2 đi kèm như một phần của HotPDF Component cho Delphi và C++Builder, bên cạnh các API tải, chỉnh sửa, và mã hóa được đề cập ở nơi khác đây