0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebP形式の画像をpdfに変換するとファイルサイズが異常に増大する問題について

Posted at

記事の目的

本事象の観測を広く報告すること。

発生している問題

表題の通りの問題が発生します。
具体的な事例としては、同内容の画像ファイル5つで、

jpg WebP
元ファイルサイズ 5,652,041 B 1,437,884 B
変換後サイズ 5,658,594 B 15,395,042 B
増加率 0.11% 970%

となります。
画像のサイズ自体はjpeg-->WebPで減少しているにもかかわらずpdfではその逆が起こることに着目してください。埋め込む画像の数がこれより増加した場合、これに比例して増加量も増大していきます。

原因

結論としては、WebPの画像デコード形式がpdfへの埋め込みに対応していないことが原因だと考察されます。画像はそれぞれ特定の画像デコード方式によって元 (raw) ファイルより圧縮されており、JPEGの場合それは離散コサイン変換 (DCTDecode)、PNGはDeflate (FlateDecode)という方式です。ここで、pdfが受け付けるデコード方式にWebPの方式がどうも含まれていないらしく1、その際可逆 (Lossless)のFlateDecodeに自動で画像が変換されてしまうため、勝手にファイルサイズが増大していると思われます。

すなわち、今回の問題はWebPに限らず、avif, tiff等の特殊な画像形式でも起こりうる問題だということです。

解析

実際どのようにpdfの中に埋め込まれているかを見てみます。jpegが埋め込まれたpdfをテキトーにVSCodeで開き、一枚目の画像 (1200x1600)が埋め込まれてそうな部分を探します。

jpeg-->pdf
<< /BitsPerComponent 8 /ColorSpace [ /ICCBased 20 0 R ] /Filter /DCTDecode /Height 1600 /Subtype /Image /Type /XObject /Width 1200 /Length 1094661 >>

画像のデコードタイプが/DCTDecodeで指定されていることが確認できます。次は、pngの場合です。

png-->pdf
<< /BitsPerComponent 8 /ColorSpace [ /ICCBased 23 0 R ] /DecodeParms << /BitsPerComponent 8 /Colors 3 /Columns 1200 /Predictor 15 >> /Filter /FlateDecode /Height 1600 /Subtype /Image /Type /XObject /Width 1200 /Length 2318605 >>

ここでは、/FlateDecodeが指定されていることが確認できました。では、tiffならどうでしょうか。

tiff-->pdf
<< /BitsPerComponent 8 /ColorSpace [ /ICCBased 23 0 R ] /DecodeParms << /BitsPerComponent 8 /Colors 3 /Columns 1200 /Predictor 15 >> /Filter /FlateDecode /Height 1600 /Subtype /Image /Type /XObject /Width 1200 /Length 2318605 >>

pdf側でtiffファイルを受け付けず、png相当に変換しているので、記述がpngの場合と全く同じであることが明瞭にわかります。

バイト数の面でも、同じ画像ファイルを.tiffや.avifに変換してpdf化すると、生成物のバイト数までpngの場合と一致することが確認できます。

対処法

pdfが対応しており、かつバイト数が小さいjpeg形式に変換してあげれば良いです。例としてPythonで変換します。
先にPillowをターミナルでインストールして下さい。

$ pip install pillow

以下はコード例:

webp2jpg.py
import os
import glob
from PIL import Image
path = r"\pictest\webp" #実際のパスにへんこう

images = [p for p in glob.glob(os.path.join(path, "*.webp")) if os.path.isfile(p)]
for image in images:
    with Image.open(image) as img:
        img = img.convert("RGB")
        img.save(os.path.splitext(image)[0] + ".jpg", "JPEG", quality=100)

注意点

閉じ忘れがないように、withを使って開きます。
ファイル名を元のファイルと同じにするため、os.path.splitextのタプルから最初の要素を取得しています。
画像の保存の際、quality引数を用いての品質指定が可能です。

コメント

個人でファイルを整理していたところ画像をpdfにして保存した方が良い場合があり、その際ぶつかった問題について問題解決プロセスを記事にしてみました。初めての記事なので誤りや至らない所があればご指摘ください。

参考資料

PillowのImageライブラリに関する公式解説

脚注

  1. ISO 32000-1:2008 §8.9 Imagesをざっくり参照; https://pdf-lib.js.org/assets/with_large_page_count.pdf

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?