Chuyện gì thực sự xảy ra khi bạn nén PDF
PDF123 Compress dùng qpdf để nén lại luồng và đóng gói object stream, không giảm mẫu ảnh, không mã hóa lại bitmap sang JPEG chất lượng thấp hơn và không cắt bớt font. Linearization hầu như không đổi kích thước tệp.

Hai tệp PDF có thể trông y hệt nhau trên màn hình mà kích thước lệch nhau tới ba bậc: 50 KB so với 50 MB. Khoảng cách này hầu như không nằm ở các toán tử văn bản. Trong một hợp đồng 20 trang, chúng thường chỉ chiếm vài chục kilobyte; phần còn lại là mẫu ảnh, một chương trình font được nhúng trọn vẹn, và mức độ chặt của cách đóng gói luồng cùng đối tượng.
Điều đó dẫn tới một hệ quả nên nói ngay từ đầu: "nén PDF" không phải một hành động mà là bốn. Bốn việc này thu nhỏ những thứ khác nhau và có cái giá khác nhau; gộp chúng làm một sẽ tạo ra trải nghiệm mâu thuẫn: tệp đã nén mà không nhỏ hơn, hoặc nhỏ hơn nhưng trang bị mất nét.
Kích thước đến từ đâu
Phần lớn trường hợp "tệp PDF này sao mà lớn thế" bắt đầu từ một bản scan hay ảnh độ phân giải cao vẫn được nhúng nguyên ở kích thước lúc chụp. Con số này đáng để tính một lần: một trang Letter 8,5 × 11 inch quét ở 300 DPI cho ra khoảng 2550 × 3300 pixel, và với ba byte mỗi pixel thì đó là khoảng 25 MB chưa nén. Hai mươi trang như vậy thường chạm 60 đến 80 MB trước khi ai đó động tới chuyện nén.
Nguồn thứ hai là font. Một tệp PDF có thể nhúng cả một chương trình font để bất kỳ máy nào cũng hiển thị văn bản giống hệt nhau, và cái giá đó được tính theo kích thước bảng glyph chứ không theo lượng văn bản thực sự được đọc. Đó là lý do cắt bớt font là một đòn bẩy kích thước riêng.
Nguồn thứ ba là chính việc đóng gói. Cùng một nội dung có thể được lưu với thiết lập nén lãng phí, hoặc các đối tượng của nó nằm rải rác khắp tệp, mỗi đối tượng mang theo phần sổ sách riêng. Không thứ nào trong đó thay đổi một pixel hay một glyph, và đây chính là phần mà việc nén lại luồng có thể chạm tới.
"Nén" là bốn việc khác nhau
Có bốn đòn bẩy tác động lên kích thước, chúng hành động ở những tầng khác nhau, và cái giá của chúng hầu như không chồng lên nhau. Chọn sai đòn bẩy là lý do phổ biến nhất khiến một lần nén có vẻ như không làm gì cả.
| Đòn bẩy | Tác động tới | Lợi về kích thước | Cái giá |
|---|---|---|---|
| Nén lại luồng và object stream | Cách luồng nội dung được nén, cách đối tượng được lưu và đóng gói | Tùy mức lỏng của tệp gốc | Hình dạng trang không đổi |
| Giảm mẫu ảnh | Số pixel, tức độ phân giải | Lớn | Độ phân giải giảm vĩnh viễn |
| Mã hóa lại ảnh có mất mát | Cách biểu diễn byte của bitmap | Lớn | Chất lượng ảnh giảm |
| Cắt bớt font | Bảng glyph được nhúng | Vừa | Glyph không dùng không còn sửa được |
| Linearization | Thứ tự các đối tượng | Gần bằng không | Đổi lấy thời gian tải trang đầu |
Bốn hàng đầu đều được gọi chung là "nén" một cách thoáng, nhưng chỉ hàng đầu để nguyên nội dung. Đây cũng là hàng dễ bị đánh giá sai nhất về lợi ích: một bản scan có kích thước chủ yếu là mẫu ảnh thô thì còn rất ít dữ liệu dư để loại bỏ, và những đòn bẩy có thể cắt nó đáng kể là giảm mẫu ảnh và mã hóa lại có mất mát, với cái giá là mất vĩnh viễn độ phân giải và chất lượng đó.
Trong bốn việc đó, PDF123 Compress làm việc nào
Nén PDF (POST /api/v1/misc/compress-pdf) chỉ làm hàng đầu tiên. Nó chạy qpdf với việc nén các luồng chưa nén (--compress-streams=y), một lượt nữa trên các luồng đã nén bằng Flate (--recompress-flate), và đóng gói đối tượng vào object stream (--object-streams=generate).
Nó không giảm mẫu ảnh, không mã hóa lại bitmap sang JPEG chất lượng thấp hơn, và không cắt bớt font. Trang phải trông như cũ, và phần tiết kiệm đến từ nén lại Flate cùng đóng gói object stream.
Điều kiện thất bại cũng cần được nói rõ như vậy. Khi kích thước tệp chủ yếu là dữ liệu ảnh đã nén sẵn dưới dạng JPEG, Flate không còn gì để ép, vì các byte ảnh đó nằm ngoài phạm vi mà ba công tắc trên chạm tới. Đó là lý do một gói scan có thể chỉ nhỏ đi vài phần trăm, trong khi một tệp PDF nhiều văn bản có kích thước tương đương lại được lợi rõ rệt hơn.
Đường ngược lại là Giải nén PDF, mở rộng luồng để kiểm tra (--qdf, tắt object stream) và cũng không thay đổi hình dạng trang.
Khi nào đường khác mới là lựa chọn đúng
| Bạn cần gì | Nên dùng đường nào |
|---|---|
| Hình dạng y hệt, chỉ bỏ phần đóng gói dư thừa | Nén |
| Gói scan thực sự quá lớn và chấp nhận mất chất lượng | Giảm mẫu ảnh hoặc mã hóa lại có mất mát, không phải Compress này |
| Vẫn còn sửa được, nhưng ký tự tiếp theo không gõ ra | Thiết lập xuất khác hoặc tệp nguồn khác, xem cắt bớt font |
| Muốn trình duyệt thấy trang đầu sớm hơn | Linearization giải quyết lần vẽ đầu, không giải quyết kích thước |
| Tệp không mở được chút nào | Sửa chữa, đó là vấn đề cấu trúc chứ không phải kích thước |
Có một cái bẫy ở hàng cuối: Linearize PDF không phải một bản triển khai riêng ở đây mà là bí danh của Compress. Cả hai cùng trỏ tới một thao tác, id chuẩn là misc/compress-pdf còn linearize-pdf chỉ là bí danh, portal luôn gửi linearize=true và optimizeLevel=1 cho công cụ đó, máy chủ không đọc trường nào trong hai trường ấy, và qpdf không bao giờ nhận --linearize. Thao tác thực sự linearize tệp là Bảo vệ, khi nó mã hóa.
Vậy nếu điều bạn muốn là hình dạng y hệt trong một tệp nhỏ hơn thì Nén là câu trả lời trọn vẹn. Nếu bạn muốn thu nhỏ ảnh có mất mát hoặc cắt bớt font thì đường này là sai đòn bẩy. Tệp được trả về trực tiếp, không cần tài khoản. Muốn thấy đối tượng, luồng và bảng cross-reference thực sự nằm ở đâu, hãy đọc tiếp Bên trong PDF có gì.