DockerとGhostscriptでPDFを高品質に圧縮する方法

PDFのファイルサイズが大きくて困ったことはありませんか?
印刷会社から入手したカタログPDFや、Adobeアプリケーションで書き出したPDFは数十MB以上になることも珍しくありません。
メールやWebへのアップロードには大きすぎて困るシーンは多いはずです。

この記事では、DockerとGhostscriptを使ってPDFを高品質に保ちながら圧縮する方法を解説します。
また、圧縮後のPDFが「プレビューには見えるのに開けない」という問題への対処法も合わせて紹介します。

なぜDockerを使うのか?

GhostscriptをMacやWindowsに直接インストールすることもできますが、Dockerを使うことで以下のメリットがあります。

  • ローカル環境を汚さない: ツールのインストール・アンインストールが不要
  • どの環境でも同じ動作が保証される: チームで共有しやすい
  • 後片付けが簡単: コンテナを削除すれば元通り

環境・使用ツール

ツール 役割
Docker + Docker Compose コンテナの管理
Alpine Linux 軽量なベースイメージ
Ghostscript(gs PDFの圧縮・変換
qpdf PDFの構造診断・修復(エラー対処用)

Ghostscript はオープンソースのPDF/PostScript処理ツールです。品質設定を細かく指定しながらPDFの再構築・圧縮ができ、業界でも広く使われています。

セキュリティ注意: Ghostscriptには過去に深刻な脆弱性が複数報告されており、リリースごとにセキュリティ修正が含まれています。ベースイメージのタグを固定すると意図しないバージョン変動を防ぎ再現性は上がりますが、固定したまま放置すると脆弱な版が残り続けるリスクもあります。「タグを固定する、かつ定期的に再ビルドして最新のパッチを取り込む」の両立が重要です。定期的に以下を実行して最新状態に更新してください。

docker compose build --no-cache

1. Docker構成ファイル

同じ環境を再現できるように、使用している構成ファイルを掲載します。

Dockerfile

FROM alpine:3.20

RUN apk add --no-cache \
      ghostscript \
      bash \
      qpdf

WORKDIR /images

CMD ["bash"]

補足: ベースイメージを alpine:3.20 のように固定することで、環境の再現性が高まり、意図しないパッケージ更新を防げます。qpdf をあらかじめ含めることで、エラー対処の場面でもすぐに使えます。

この記事ではPDF圧縮に絞ってImageMagick・optipng・pngquantは含めていません。画像最適化も行いたい場合は apk add imagemagick optipng pngquant を追加してください。

docker-compose.yml

services:
  pdf:
    build: .
    volumes:
      - ./images:/images

version: キーは Docker Compose v2 以降では不要になり、記載するとツールによっては警告が出るため省略しています。

サービス名を pdf にすることで、記事の主題(PDF圧縮)と一致した構成になります。
volumes の設定により、ホスト側の ./images フォルダがコンテナ内の /images にマウントされます。
圧縮したいPDFは必ずこのフォルダに置いてください。 コンテナ内で処理した結果も同じフォルダに出力されます。

2. コンテナを起動してシェルに入る

プロジェクトのルートディレクトリで以下を実行し、コンテナ内のシェルに入ります。

docker compose run --rm pdf bash

pdfdocker-compose.ymlservices に定義したサービス名です。
--rm オプションを付けることで、シェルを抜けた後にコンテナが自動的に削除されます。
コンテナ内に入ると、作業ディレクトリは /images(=ホストの ./images フォルダ)になります。

入ったら念のため作業ディレクトリを確認してください。

pwd
# /images と表示されれば問題ありません
# /images 以外が表示された場合は以下で移動します
cd /images

docker compose up -d で常駐させる必要はありません。PDF圧縮はその都度コンテナを起動して処理するだけで十分です。

シェルに入らずホストから直接ワンライナーで実行することもできます。

docker compose run --rm pdf gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -o output_high.pdf input.pdf

この形式は1回だけ圧縮したい場合に便利です。

3. Ghostscriptでシンプルに圧縮する

以下のコマンド例では入力ファイルを input.pdf、出力ファイルを output.pdf としています。実際のファイル名に置き換えてから実行してください。

基本的な圧縮コマンドは以下です。

gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -o output_high.pdf input.pdf

オプションの説明

オプション 説明
-dSAFER ファイルシステムへの不正アクセスを防ぐ安全モード。基本的に付けておくことを推奨。問題が出た場合はまず入力PDFのパスや出力先が正しいか確認する。どうしても解消しない場合は -dNOSAFER で無効化できるが、信頼できるファイルに限定し使用は非推奨
-dNOPAUSE 各ページ処理後に一時停止しない(バッチ処理に必要)
-dBATCH 全ページ処理後に自動終了する(対話モードへの落下を防ぐ)
-sDEVICE=pdfwrite PDF形式で出力する
-dPDFSETTINGS= 品質プリセットを指定する(後述)
-o output.pdf 出力ファイル名を指定する
input.pdf 圧縮したいPDFファイル名

-dNOPAUSE-dBATCH を省略すると、処理の途中で対話入力待ちになることがあります。バッチ処理では必ず両方付けてください。

-dPDFSETTINGS の品質プリセット一覧

Ghostscriptには品質と圧縮率のバランスを一括で指定できる便利なプリセットがあります。
これらは単純にdpiを変えるだけでなく、画像のダウンサンプル方法・圧縮アルゴリズム・カラープロファイルなど複数の設定を組み合わせた「Distillerパラメータのプリセット」です。
以下の解像度はあくまで画像ダウンサンプルの目安であり、元のPDF内容によって実際のファイルサイズや品質への影響は異なります。

設定値 画像ダウンサンプル目安 主な用途 ファイルサイズ
/prepress 〜300ppi 印刷用・最高品質 大きめ
/printer 〜300ppi 一般プリンター向け やや大きめ
/ebook 〜150ppi 画面閲覧・Web配布用 中程度
/screen 〜72ppi Web用・最小サイズ 小さい

画質を重視するなら /prepress、ファイルサイズを小さくしたいなら /ebook または /screen を選びます。

高品質(印刷用レベル)で圧縮する例

gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -o output_high.pdf input.pdf

標準的な高品質(プリンター向け)で圧縮する例

gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/printer -o output_std.pdf input.pdf

実行すると Processing pages 1 through N. と各ページを処理するログが出て、完了すると /images に出力ファイルが生成されます。

圧縮後のファイルサイズについて

実際に crafree_product_catalog_vol3.pdf(55ページのカタログPDF・46.5 MB)で計測した結果は以下の通りです。
(画像の比較は記事の最後に掲載)

設定値 圧縮前 圧縮後 削減率
/prepress 46.5 MB 38.7 MB 約17%減
/printer 46.5 MB 37.2 MB 約20%減
/ebook 46.5 MB 22.4 MB 約52%減

/prepress/printer の削減率が小さいのは、元のPDFがすでにある程度圧縮済みである場合に起こります。この設定は画像品質を維持するため、元から低解像度の場合はさらなる間引きが発生しません。サイズ削減を優先するなら /ebook が効果的です。

なお今回の処理では以下の警告が表示されましたが、出力ファイルは正常に開くことができました。

warning: ignoring zlib error: incorrect data check

この警告はPDF内部の一部ストリーム展開で整合性エラーが検出された可能性を示します。出力が開けても、画像の欠けや文字化けがないか目視で確認してください。問題があればセクション4のqpdfによる正規化を行った上で再実行してください。

実際に試した結果はコンテナ内で確認できます。

ls -lh *.pdf

出力品質の目視確認

Ghostscriptは内部でPDFを再構築するため、圧縮後は以下の点を目視で確認することを推奨します。

  • 文字の縁が滲んでいない
  • 写真にブロックノイズが増えていない
  • 透明効果やグラデーションが破綻していない

特に /ebook/screen を選んだ場合は画像の間引きが大きくなるため、印刷用途には向きません。用途に合った設定値を選んでください。

4. エラーが出て開けない場合の対処法

一部のPDFを処理すると、以下のようなエラーログが出ることがあります。

error executing PDF token
Invalid /Length supplied in Encryption dictionary.
 This file had errors that were repaired or ignored.
 The file was produced by:
 >>>> Adobe PDF library 17.00(Macintosh) <<<<

このエラーが出ると、処理自体は完了してファイルが生成されますが、プレビューには表示されるのに開こうとするとエラーになるという症状が発生します。

原因

このエラーは、PDFの内部構造(特に暗号化情報 Encryption dictionary)が厳密なPDF仕様から外れているケースで起きることがあります。
Ghostscriptはエラーを検知しても処理を中断せず「修復して続行」しますが、この修復が不完全なため、出力されたPDFの内部構造が壊れてしまうことがあります。結果として、ファイルは存在するが開けないという状態になります。

Adobe製PDFに限らず、様々なアプリケーションで作成したPDFでも同様の症状が起きる場合があります。

解決策:qpdfで「診断 → 修復 → 圧縮」の順で対処する

qpdf はPDFの内部構造を解析・再構築するコマンドラインツールです。
まずPDFの状態を診断し、問題があれば修復してからGhostscriptで圧縮する、という流れが確実です。

ステップ1:PDFの状態を診断する

# PDFの構造に問題がないか確認する
qpdf --check input.pdf

正常なPDFの場合は No errors found. と表示されます。
問題がある場合はエラー内容が表示されるので、次のステップに進みます。

--check で「問題なし」と表示されても、ストリーム内容レベルの非準拠が残っている場合があります(qpdf公式ドキュメント参照)。最終的には出力PDFの目視確認を行うことを推奨します。

ステップ2:PDFの構造を正規化する

qpdf --check の結果に応じて使い分けます。

暗号化辞書系のエラー(Invalid /Length supplied in Encryption dictionary など)が出ている場合:

# 暗号化構造を取り除いて通常のPDFとして再出力する
qpdf --decrypt input.pdf fixed.pdf

--decrypt は暗号化構造(Encryption dictionary)を除去して正規化するオプションです。
暗号化辞書系のエラーへの対処として有効ですが、暗号化されていないPDFや別種のエラーには効果がない場合があります。

パスワードが設定されているPDFの場合は復号に失敗するため、--password を併用します。

# パスワード付きPDFの場合
qpdf --decrypt --password=yourpassword input.pdf fixed.pdf

暗号化以外の構造上の問題がある場合:

暗号化辞書系以外の構造問題には、まず引数なしの再書き出しを試みるのがシンプルで確実です。
qpdfは入力PDFを解析して再構築した上で出力するため、軽微な構造異常を正規化できることがあります。

# 最もシンプルな再出力(構造異常の正規化を試みる)
qpdf input.pdf fixed.pdf

それでも解消しない場合は、線形化(Webアクセス最適化)を行いながら再構築する方法も試せます。
ただし --linearize は万能な修復コマンドではなく、すべての構造問題に対処できるわけではありません。

# 再構築しながら再出力する(あくまで手段の一例)
qpdf --linearize input.pdf fixed.pdf

ステップ3:修復したPDFをGhostscriptで圧縮する

gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -o output_high.pdf fixed.pdf

古いPDFビューアで開けない場合: -dCompatibilityLevel=1.4 を追加すると、PDF 1.4形式(Acrobat 5相当)で出力され、古いビューアとの互換性が上がることがあります。

gs -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress -o output_high.pdf fixed.pdf

ステップ4:中間ファイルを削除する

rm fixed.pdf

まとめ

状況 解決策
通常のPDF圧縮 gs -dSAFER -dNOPAUSE -dBATCH -dPDFSETTINGS=/prepress -o output.pdf input.pdf
エラーが出て開けない qpdf --check で診断 → qpdf --decrypt で正規化 → gs で圧縮
画質より軽さを優先したい -dPDFSETTINGS=/ebook または /screen を使う
パスワード付きPDFを処理したい qpdf --decrypt --password=xxx でパスワードを指定して正規化

DockerとAlpineを使えば、ローカル環境を汚さずにPDF処理が行えます。
PDFでエラーが出た場合は、まず qpdf --check で診断し、問題があれば qpdf --decrypt で正規化してから gs で圧縮する手順を試してみてください。

画像比較

天前智矢

天前智矢

企画開発部 マネージャー 愛犬ファーストのエンジニア

関連記事