Skip to content

PDF 圧縮

DocumentEditor::save_with_options() は、ストリームの再圧縮・孤立オブジェクトのガベージコレクション・Fast Web View 用のリニア化を一度の処理でまとめて実行できます。この 3 つをもっとも手軽に適用する方法が、単一コマンドでラップした pdf-oxide compress CLI です。

バインディング対応状況。 compress / garbage_collect / linearize を含む完全な SaveOptions は、Rust (editor.save_with_options(path, opts)) と Python(バインドされている環境では doc.save(..., compress=True, ...))で公開されています。Node・WASM・Go・C# からは、CLI (pdf-oxide compress input.pdf -o out.pdf) をサブプロセスまたはビルド手順として実行してください。SaveOptions が各 FFI に配線されるまで、CLI がこれらのバインディングで共有される安定したインターフェースです。

CLI(全プラットフォーム)

# 基本: input_compressed.pdf を出力
pdf-oxide compress input.pdf

# 出力ファイル名を明示
pdf-oxide compress input.pdf -o smaller.pdf

# サイズ比較を表示
pdf-oxide compress report.pdf
# → Compressed report.pdf -> report_compressed.pdf (3412901 -> 1847200 bytes)

CLI はデフォルトで compress: truegarbage_collect: truelinearize: true を有効にします — ISO 32000 に準拠した最小サイズのファイルを生成する組み合わせです。

Rust API

use pdf_oxide::editor::{DocumentEditor, EditableDocument, SaveOptions};

let mut editor = DocumentEditor::open("input.pdf")?;

editor.save_with_options("output.pdf", SaveOptions {
    compress: true,         // 未圧縮ストリームに FlateDecode を適用
    garbage_collect: true,  // 孤立オブジェクトを削除
    linearize: true,        // Fast Web View 用にリニア化
    ..Default::default()
})?;

SaveOptions のフィールド

フィールド 既定値 効果
compress CLI では true / 既定では false 未圧縮で保存されたストリームに FlateDecode を適用
garbage_collect CLI では true トレーラーから到達できない間接オブジェクトを削除
linearize CLI では true Linearized(「Fast Web View」)レイアウトで出力し、全体がダウンロードされる前にビューアーが 1 ページ目を描画可能にする
encryption None EncryptionConfig を付与して暗号化保存 — 暗号化とセキュリティ を参照

各オプションの実際の動作

  • compress — すべてのコンテンツストリーム・Form XObject・ToUnicode CMap・メタデータストリームを走査し、フィルターが無いものや未知のフィルターのストリームを FlateDecode で再ラップします。既に圧縮されているストリーム(JBIG2 画像・CCITT テーブル・既存の Flate)はそのまま残します。
  • garbage_collect/Root/Info を起点に到達可能性を走査し、生きている間接オブジェクトだけに印を付けて、出力 xref にそれらのみを書き出します。remove_pageflatten_formserase_region のような大幅な編集で孤立オブジェクトが生じた後に有用です。
  • linearize — 最初のページのコンテンツストリームとそのリソース依存をファイル先頭に配置し、リニア化辞書とヒントストリームを追加するようにオブジェクトを並び替えます。PDF リーダーはファイルを順に読み込み、全体のダウンロードを待たずに 1 ページ目を描画します。CDN から配信される PDF でユーザーが最も実感しやすい恩恵です。

圧縮すべきタイミング

  • 一括編集の後flatten_formsflatten_all_annotationsapply_all_redactions を実行したり大量のページを削除したりした場合、GC と再圧縮でファイルサイズが通常 30〜60% 減少します。
  • 配布やメール送信の前 — エンドユーザーはファイルサイズを気にしますし、Linearize によって低速回線でも 1 ページ目が瞬時に表示される体感になります。
  • ETL パイプラインの最終ステップとして — 抽出と再生成の後、パイプラインの最後で 1 度だけ圧縮しましょう。変換のたびに展開と再圧縮を繰り返さないこと。

圧縮すべきでないタイミング

  • 頻繁な増分編集の途中 — 全面書き換えは xref ストリームとオブジェクトストリームを失い、増分追記を小さく保つ仕組みが失われます。対話的な編集ループでは SaveOptions::incremental() を使い、圧縮は最終パスに残しましょう。
  • 既に強く圧縮されている PDF — ストリームが良い predictor を伴う FlateDecode フィルターで既に圧縮されている場合、削減幅は数%にとどまることもあります。パイプラインに組み込む前に pdf-oxide compress を 1 度実行して効果を計測してください。

期待できるサイズ削減

実ワールドの PDF における典型的な削減量(3,830 ファイルのテストコーパスで計測):

種別 圧縮前 圧縮後 削減率
スキャンされた請求書(未圧縮ストリーム) 2.4 MB 0.8 MB 約 66%
LaTeX の研究論文 1.1 MB 0.95 MB 約 14%
政府フォーム(flatten 後) 890 KB 240 KB 約 73%
既に最適化されたマーケティング PDF 1.8 MB 1.75 MB 約 3%

一括編集後のファイルや flatten 後のフォームがもっとも効果を発揮します。既に最適化されたファイルではリニア化分だけの穏やかな削減に留まります。

先に復号・認証する

DocumentEditor は現時点でパスワード認証の呼び出しを持たないため、暗号化された PDF はまず復号する必要があります。PdfDocument.open_with_password() で読み込み、暗号化されていないコピーを保存してから、そのコピーをエディターで開いてください。

use pdf_oxide::api::Pdf;
use pdf_oxide::editor::{DocumentEditor, EditableDocument, SaveOptions};

let doc = Pdf::open_with_password("protected.pdf", "pw")?;
doc.save("temp-unencrypted.pdf")?;

let mut editor = DocumentEditor::open("temp-unencrypted.pdf")?;
editor.save_with_options("compressed.pdf", SaveOptions {
    compress: true,
    garbage_collect: true,
    linearize: true,
    ..Default::default()
})?;

Python でも同じパターンで、PdfDocument(path, password="pw") + save() + CLI の組み合わせが使えます。

関連ページ