2021/08/06

【Python】複数画像をPDFに変換する方法の比較

以前も、複数画像をPDFに変換する方法に関して、img2pdfの紹介記事を書いたのですが、img2pdfやそれ以外の手法での実行時間やファイルサイズなどを比較してみました。

本記事では、img2pdfを用いてpdfにする方法と、reportlabとPillowを組み合わせる方法、Pillowのみを使う方法の三種類を比較した結果を紹介します。

実行時間は、実行環境などで変わるため、あくまで目安です。計測に関しても、Jupyter Lab上で、実行した結果であり、複数回測って平均をとるというような厳密なことはしておりません。

実行環境は、以下の通りです。

MacBook Pro 13-inch (2017)
------
Python 3.8.11
img2pdf 0.4.1
reportlab 3.3.0
Pillow 8.1.0

下記のスクリプトは、いずれも書籍をスキャンしたpngファイル(連番ファイル名)を、pdfに変換することを想定しています。

Method1 : img2pdfを使う

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Method2 : reportlabとPillowを組み合わせる

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Method3 : Pillowだけを使う

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

10個の異なるpng画像ファイル群での実行時間と出力ファイルサイズの比較は、以下の通りです。


img2pdfを用いた方法は、実行時間(変換にかかる時間)が特に短いです。 出力されたpdfファイルサイズは、pngファイルの合計サイズよりとほぼ同じサイズになっており、pngファイルを複雑に処理していないことが伺われます。 img2pdfに関して、残念なのはアルファチャンネルのある透過pngに対応していない点です。事前に処理しておいてね、という仕様となっています。


reportlabとPillowを組み合わせる方法ですが、実行時間が特に長く、画像のみのpdfを作るのであれば、reportlabを組み合わせる必要はないかなと感じました。


Pillowだけを用いる方法は、入力ファイルによって結果がばらついていますが、基本的にはファイルサイズが圧縮されています。リサンプリングしているため実行時間が伸びますが、この方法では、qualityの値を調整することでファイルサイズをさらに圧縮することも可能なので、ファイルサイズを調整したい時には良い方法だと思います。
ただし、img2pdfのように、見開きの設定など複雑なことはできないようなので、割り切って使うか他のツールと組み合わせる必要があります。


追記:2022/12/09
PyMuPDFを使って、変換する方法が分かったので追加しました。実行速度などは測っていません。

Method4 : PyMuPDFを使う

import os
import fitz
file_dir = '(画像ファイルが入っているフォルダのパス)'
file_ext = '.png'
img_files = sorted([os.path.join(file_dir, _) for _ in os.listdir(file_dir) if _.endswith(file_ext)])
# PDFの新規作成
doc = fitz.open()
# PDFにPNG画像を書き込む
for file in img_files:
# 画像を読み込む
with fitz.open(file) as img:
rect = img[0].rect
pdfbytes = img.convert_to_pdf()
# 新しいページを追加
page = doc.new_page(width=rect.width, height=rect.height)
page.show_pdf_page(rect, fitz.open('pdf', pdfbytes), 0)
# PDFを保存
doc.save('output4.pdf')
参考:

Method5 : borbを使う

borbを使って変換することも出来ましたが、v2.1.7では画像をPDFにする際に自動でOCR処理をするようで変換処理が遅いです。OCR処理をスキップ指定できる方法が分かれば更新します。基本的には余白が自動で入る設計で、このような変換は想定していないと思われます。
import os
import borb
from PIL import Image
file_dir = '(画像ファイルが入っているフォルダのパス)'
file_ext = '.png'
img_files = sorted([os.path.join(file_dir, _) for _ in os.listdir(file_dir) if _.endswith(file_ext)])
doc = borb.pdf.Document()
for file in img_files:
img = Image.open(file)
page = borb.pdf.Page(width=img.width, height=img.height)
doc.add_page(page)
page_layout = borb.pdf.SingleColumnLayoutWithOverflow(page, horizontal_margin=0, vertical_margin=0)
page_layout.add(borb.pdf.Image(img, width=img.width, height=img.height, margin_bottom=0, margin_left=0, margin_right=0, margin_top=0, border_width=0))
with open('output5.pdf', 'wb') as pdf_file_handle:
borb.pdf.PDF.dumps(pdf_file_handle, doc)
view raw borb_png_pdf.py hosted with ❤ by GitHub

続き