複数の画像から印刷用のpdfファイルを作成する(Python, ImageMagick)

複数の画像をまとめて1回の印刷で対応できるような PDF ファイルを作りたい場合にどうするか。

Python上でプログラムによって pdf ファイルを生成する

AWS Lambda Python で PDF 作りたくてどうしようかと思って調べていたけど、Pillow(PIL) と reportlab を使えば Python プログラムで画像連結をしただけのPDFファイルは結構簡単に作れる。

''' 検証環境: virtual env on Python 3.6.5
$ pip install Pillow reportlab
$ pip list
Package    Version
---------- -------
Pillow     5.2.0
pip        10.0.1
reportlab  3.4.0
setuptools 39.2.0
wheel      0.31.1
'''

from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from PIL import Image

# A4 サイズの PDF ファイルを定義する
pdf = canvas.Canvas('output.pdf', pagesize=A4)
pdf.setPageSize((1116, 1560)) # 1 page を何 pixel で表現するかを 2-Tuple で指定

# ページの左下をoriginとして、座標(0, 0) を起点に画像を読み込み現在のページ内に書き込む
pdf.drawInlineImage(Image.open('test001.png'), 0, 0)

# 改ページ
pdf.showPage()

# 次のページにも同様に書き込む
pdf.drawInlineImage(Image.open('test002.png'), 0, 0)

# ファイルを保存
pdf.save()

setPageSize と 描画座標によってページ内のImage配置が結構柔軟にできる。
基本は縦横一杯だが、画像が大きすぎたり、印刷の都合で上下左右の空白を入れたい場合などはわざとサイズと座標をずらすことで細かい調整が可能。

ImageMagick を使う

本当に何でも変換してくれますねこの子。

とりあえず複雑なことしないなら、こっちの方がすごく楽。
大体のOSで*1Package Managerによってダウンロードできるし。

convert -density 150 -geometry 1240x1754 page01.png page02.png output.pdf

A4で印刷することを前提にしたいので、画像全体を紙全体に貼り付けるために解像度と紙サイズを指定する。

  • A4 = 210 x 297 mm
  • 画像dpi想定 = 150
  • 1 inch = 25.4 mm (see: http://kijie.com/compute/manual/dpi/)
  • pixel number := inch x (dot per inch)
  • width : inch(210 mm) x 150 dpi = (210 / 25.4) x 150 (-> 1240)
  • height: inch(297 mm) x 150 dpi = (297 / 25.4) x 150 (-> 1754)

色がうまく出ないときは -colorspace オプションで RGB/CMYK 変換をかけてもよいかと。

同じようなことをまとめてくれている人がいるのでこちらで。

(補足) LambdaでImageMagickつかえるんじゃね?

AWS Lambda で ImageMagick を使うのであれば npm の gm とかを使う方法がネット上の公式ドキュメントには書いてある
ただ、gm の Getting started には imagemagick か graphicsmagick を先にインストールしておけって書いてあるけれどこれがAWS Lambdaの実行環境内にプレインストールされているっていう証跡を記事の記載時点では見つけられなかった。
まあ、世の中の Node Lambda の記事にこれを別途ビルドしてLambda Fucntion内に同時にアップロードするっていう記事が書いていないので、多分node.js用のLambda内部にはインストール済みなんだと思うのだけれど。 あと、Pythonだと PIL での画像処理記事ばかりでるから、このインストールが仮にあったとしても、node.js runtime でしか使えない気がする。

*1:Windowsでも10以降ならWindows Subsystem for Linuxubuntu入るのでWindowsならそれを使える