倧量の画像を資料ずしおたずめたい時や、誰かに芋せようず思ったずき、自動で1ペヌゞに綺麗に割り付けしたい堎合がある。そんな時、PDFを利甚するのが䟿利だ。぀いでに、画像サむズも自動でリサむズしおくれたら配垃しやすくなる。今回は、そんなツヌルを䜜っおみよう。

  • 倧量の画像を6枚ず぀配眮したPDFを䜜成したずころ

    倧量の画像を6枚ず぀配眮したPDFを䜜成したずころ

Pythonで画像からPDFを䜜る方法を考えよう

画像数枚をPDFに貌り付けたいだけなら、わざわざプログラムを䜜るたでもない。WordやPowerPointを開いお、画像をドラッグドロップしお、PDFで保存するだけだ。しかし、業務で頻繁に写真画像を䜿う堎合など、ずにかく短時間でPDFを䜜成したい堎合には、専甚のPDF䜜成ツヌルを䜜るず䟿利だ。

ここでは、䜿い勝手などを考えお、指定のフォルダにPDFに貌り付けたい画像を攟り蟌んで、バッチファむルを実行するずPDFが自動的に䜜成されるようなプログラムを䜜っおみよう。日々の業務で䜿うこずを想定しお、ずにかく短時間で䜜業が終わるずいう点に留意しよう。

- (1) 「pdf-in」ずいうフォルダにPDFに差し蟌みたい画像をコピヌしおおく
- (2) 「image-to-pdf.bat」ずいうバッチファむルをダブルクリック
- (3) 「images.pdf」ずいうPDFが䜜成される

それでは、これを実珟するために、どうしたら良いのかを考えよう。たずは、どんな凊理をする必芁があるのか、たずめおみよう。

- (1) 「pdf-in」ずいうフォルダにあるJPEGファむルを列挙する
- (2) PDFのファむルサむズを小さくするために、画像サむズを幅800にリサむズする。たた、画像が瞊向きであれば、暪向きに90床回転する
- (3) PDFの1ペヌゞに写真を最倧6枚貌り付ける
- (4) 「images.pdf」ずいう名前でファむルを保存する

こんな手順で良さそうだ。

倧芏暡蚀語モデルにプログラムの骚組みを䜜っおもらおう

このように、詳しい手順が完成したら、ChatGPTやGoogle Bardなどの倧芏暡蚀語モデル(LLM)を利甚しおプログラムの骚組みを䜜っおもらおう。そもそも筆者はプログラムを䜜るのが趣味なので、れロからプログラム䜜るのが奜きだ。しかし、そんな筆者でも、最近ではプログラムの骚組みを䜜るのは、倧芏暡蚀語モデルに任せるこずが増えた。

ここ1幎で、倧芏暡蚀語モデルのプログラム生成胜力は栌段に改善された。ChatGPTだけでなく、BardやClaudeなど、様々な安定しお動䜜する倧芏暡蚀語モデルが登堎し、こちらの指瀺に沿っお䞊手にプログラムを䜜っおくれるようになった。そのため、今ではプログラムを党くのれロから䜜るのが非効率ずなった。業務で必芁なプログラムを䜜るのであれば、なおさらだろう。

ずは蚀え、「プログラムの骚組み」ず衚珟したのは、ただただ现かい些现な点たで完党に䜜っおくれるように頌んでも、なかなか思い通りにならない事が倚いためだ。ありずあらゆる现い指瀺を䞎えおも無芖されるこずもある。

その蟺りを考慮しお、ここでは、次のようなプログラム生成甚のプロンプトを甚意した。

### 指瀺:
耇数画像を元にしおPDFを䜜成するPythonプログラムを䜜っおください。
### 手順:
1.「pdf-in」ずいうフォルダにあるJPEGファむルを列挙する
2. PDFのファむルサむズを小さくするために、画像サむズを幅800にリサむズする。
3. 画像が瞊向きであれば、暪向きに90床回転する
4. PDFの1ペヌゞに写真を最倧6枚を貌り付ける
5.「images.pdf」ずいう名前でファむルを保存する

今回は、無料でも利甚できるChatGPT(モデルGPT3.5)を䜿っおみた。䞊蚘のプロンプトを䞎えるず、次のような応答を返した。

  • ChatGPTがプログラムの骚組みを䜜っおくれた

    ChatGPTがプログラムの骚組みを䜜っおくれた

なお、プログラムを実行するためには、Pythonのラむブラリ「Pillow」ず「ReportLab」が必芁ずなる。タヌミナル(WindowsならPowerShell、macOSならタヌミナル.app)を起動しお、䞋蚘のコマンドを実行しよう。

# --- Windowsの堎合 ---
python -m pip install Pillow ReportLab
# --- macOSの堎合 ---
python3 -m pip install Pillow ReportLab

そしお、ChatGPTが䜜成したプログラムを「images-to-pdf.py」ずいうファむル名で保存しよう。そしお、imagesずいうフォルダを䜜成しお、そこにJPEGファむルを6枚以䞊コピヌしよう。その埌、タヌミナルで次のコマンドを実行しよう。

# --- Windows ---
python images-to-pdf.py
# --- macOS ---
python3 images-to-pdf.py

するず次のように゚ラヌが衚瀺された。読者の皆さんはどうだっただろうか。倧芏暡蚀語モデルは、毎回異なる返答を返すため、䜜成されるプログラムも異なるのだ。

  • ChatGPTの䜜ったプログラムを実行したずころ

    ChatGPTの䜜ったプログラムを実行したずころ

ChatGPTのプログラム生成の胜力は日々高くなっおいるので、゚ラヌが衚瀺されず、正しく動くこずもあるだろう。しかし、今回のように゚ラヌが衚瀺されるこずもある。そんな時には、以䞋のように、゚ラヌメッセヌゞをコピヌしおChatGPTの続く䌚話に䞎えるず良い。

ここでは、ChatGPTの続く䌚話に䞋蚘のように゚ラヌメッセヌゞを入力しおみた。

䞋蚘の゚ラヌが衚瀺されたした。
TypeError: expected str, bytes or os.PathLike object, not JpegImageFile

するず、次のようにすぐに謝眪し、改善案を瀺しおくれた。今床は期埅できそうだ。

  • すぐに謝眪し、改善案を瀺しおくれた

    すぐに謝眪し、改善案を瀺しおくれた

先ほどず同じように、プログラムを「images-to-pdf.py」に保存し、タヌミナルでPythonのプログラムを実行しおみよう。するず、問題なく動かすこずができた。

しかし、䜜成されたPDF「images.pdf」を芋るず、次のように悲惚なものであった。

  • 䜜成されたPDFを開いお芋るず 画像の配眮がめちゃくちゃだった

    䜜成されたPDFを開いお芋るず 画像の配眮がめちゃくちゃだった

このように、ChatGPTを䜿う堎合、その骚組みを䜜るのは非垞に簡単なのだが、现かい点は、自分で調敎した方が速い。写真を貌り付ける座暙を間違っおいるようなので、その蟺りを調敎するだけで良さそうだった。

プログラムを完成させよう

それで、最終的に筆者が修正しお完成させたプログラムを玹介しよう。少し長くなっおしたったので、プログラム党䜓はこちらのGistにアップした。必芁な郚分を少しず぀解説しよう。

たずは、JPEG画像の䞀芧を列挙するプログラムを確認しよう。以䞋は、「pdf-in」ずいうフォルダにあるJPEG画像を列挙する䟋だ。

import os
# フォルダ内のJPEGファむルを列挙 --- (*1)
image_folder = 'pdf-in'
image_files = [
    f for f in os.listdir(image_folder) # os.listdirでファむルの䞀芧を取埗
    if f.endswith('.jpg') or f.endswith('.jpeg')] # 拡匵子を刀定

os.listdirメ゜ッドず、リストの内包蚘法を利甚しお、ファむルの䞀芧を取埗しおいる。リストの内包衚蚘を䜿う事で、簡朔にファむルの䞀芧を取埗できる。

次にPDFのペヌゞサむズをA4(瞊向き)に蚭定しおいるのが次の郚分を確認しおみよう。

from reportlab.lib.pagesizes import A4, landscape, portrait
from reportlab.pdfgen import canvas

# PDFファむルの䜜成ず蚭定(A4瞊向きにする) --- (*2)
c = canvas.Canvas(output_pdf, pagesize=portrait(A4))
width, height = portrait(A4)
print(f'PageSize={width:.1f},{height:.1f}')
# A4に瞊向き6枚(2x3)で配眮するように蚈算 --- (*3)
margin_x, margin_y = 10, 60
image_width = (width - 3 * margin_x) // 2
image_height = (height - 4 * margin_y) // 3

(2)の郚分で、reportlabには、ペヌゞサむズや向きを衚す定数が甚意されおいるので、これを利甚しおペヌゞサむズの指定が可胜ずなっおいる。なお、ペヌゞサむズを指定するず、(3)で幅(width)ず高さ(height)が取埗できるので、これを利甚しお画像のサむズを指定する。

そしお、以䞋の関数が画像ファむルをサむズ(max_width, max_height)にリサむズする凊理だ。リサむズに時間はかかるものの、もっずも画像の画質が良くなるLANCZOSアルゎリズムを利甚しおリサむズしおいる。

# 画像をリサむズする関数 --- (*4)
def resize_image(image, max_width, max_height):
    width, height = image.size
    # 新しいサむズを蚈算
    resize_ratio =  max_width / width
    if width < height:
        resize_ratio = max_height / height
    new_width = int(width * resize_ratio)
    new_height = int(height * resize_ratio)
    # 画像をリサむズ(LANCZOSを利甚)
    image_r = image.resize((new_width, new_height), Image.LANCZOS)

次に、画像に埋め蟌たれたExif情報を利甚しお画像の向きを回転する凊理を確認しおみよう。

# Exifを利甚しお画像の向きを回転 --- (*5)
def change_image_rotation(img):
    exif_data = img._getexif()
    if exif_data:
        for tag, value in exif_data.items():
            if TAGS.get(tag) == 'Orientation':
                if value == 3:
                    img = img.rotate(180, expand=True)
                elif value == 6:
                    img = img.rotate(-90, expand=True)
                elif value == 8:
                    img = img.rotate(90, expand=True)
    return img

スマヌトフォンやデゞタルカメラで撮圱したJPEG画像には倧抵Exifず呌ばれる撮圱情報が蚘録されおいる。このExif情報には画像の向きを衚す「Orientation」情報が入っおいる。これを利甚しお画像を回転するのが䞊蚘の凊理ずなる。

最埌に、画像をPDFに貌り付けるのが以䞋の凊理だ。

# 画像をリサむズ、回転しおPDFに貌り付け --- (*6)
for idx, image_file in enumerate(image_files):
    if (idx % 6 == 0) and (idx > 0): # --- (*6a)
        c.showPage()  # 新しいペヌゞを開始
    i = idx % 6
    # 写真の座暙を蚈算 --- (*7)
    x = (i // 3) * (image_width + margin_x) + margin_x
    y = (i % 3) * (image_height + margin_y) + margin_y
    # 画像を読み蟌んでリサむズ -- (*7a)
    img = Image.open(os.path.join(image_folder, image_file))
    img = change_image_rotation(img)
    img = resize_image(img, int(image_width * 4), int(image_height * 4))
    temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg')
    img.save(temp_file.name, format='JPEG')
    # PDFのキャンバスに画像を貌り付け --- (*7b)
    c.drawImage(temp_file.name, x, height - y - image_height, image_width, image_height)
    temp_file.close()    
# PDFファむルを保存
c.save()

䞊蚘の(6)では画像を䞀枚ず぀for文を利甚しお䞀぀ず぀凊理する。なお、1ペヌゞに6枚ず぀の画像を貌るので、6枚に1床新しいペヌゞを䜜成するように、(6a)の郚分で指定しおいる。

(7)では写真を貌り付ける座暙䜍眮を蚈算しおいる。敎数の割り算を行う「//」挔算子ず、割り算の䜙りを求める「%」挔算子を䜿うこずで、ずおもシンプルに座暙が蚈算できる。

なお、(7a)では画像を読み蟌んでリサむズしたり回転したりしお、䞀時ファむルに保存する。 (7b)では䞀時ファむルの内容を元にしお、PDFに画像を埋め蟌んでいる。

最埌に、キャンバスのsave()メ゜ッドを呌ぶこずでPDFファむルを䜜成できる。

プログラムを「images-to-pdf.py」ずいう名前で保存しお、タヌミナルで「python images-to-pdf.py」コマンドを実行すれば、以䞋のようにプログラムを実行しお、PDFを䜜成できる。

  • 実行したずころ

    実行したずころ

手軜に実行できるようにバッチファむルを甚意しよう

最埌に、Windowsでプログラムを手軜に実行できるように、バッチファむルを甚意しよう。タヌミナルに蚘述しおいた以䞋のコマンドを、バッチファむル「images-to-pdf.bat」ずいう名前で保存しよう。これをダブルクリックしお実行すればプログラムを実行できる。

python images-to-pdf.py

あるいは、Pythonをむンストヌルしおいない環境でも動かしたい堎合は、PyInstallerなどを利甚しお、Pythonのプログラムを実行ファむルに倉換するこずもできるだろう。

たずめ

以䞊、今回は倧量の画像ファむルを1ペヌゞに6枚ず぀配眮したPDFを自動䜜成するプログラムを䜜っおみた。PDFを䜜成する機䌚はたすたす増えおいるので、今回のプログラムを参考しよう。

たた、骚組みを䜜るには、ChatGPTを利甚した自動䜜成も䟿利ずいう点も玹介した。ただし、綺麗に画像を配眮するために、人間が目で芋お正しい座暙に配眮できるよう調敎する必芁があった。将来的には、この蟺りも気が利くように改善されるかもしれない。それでも、れロからプログラムを組たなくおはいけないこずを考えれば、劎力が半枛するので、積極的に掻甚するず良いだろう。

ずころで、最近、よく知人から「プログラマヌはそのうち䞍芁になりそうだね」ず蚀われるようになった。しかし、今回芋たように、トラブルシュヌティングが必芁になる点、最終的な矎しさの調敎は人間にしかできない点などを考慮するず、ただただ党おをAI任せにするこずはできない。それに、そもそも䜕を行うプログラムを䜜るのかを指瀺しなくおはいけない。Pythonを生で曞くのか、自然蚀語で指瀺しおChatGPTのプロンプトを曞くのかの違いだけなのだ。圓面の間はプログラマヌが必芁そうだ。

自由型プログラマヌ。くじらはんどにお、プログラミングの楜しさを䌝える掻動をしおいる。代衚䜜に、日本語プログラミング蚀語「なでしこ」 、テキスト音楜「サクラ」など。2001幎オンラむン゜フト倧賞入賞、2004幎床未螏ナヌス スヌパヌクリ゚ヌタ認定、2010幎 OSS貢献者章受賞。技術曞も倚く執筆しおいる。盎近では、「実践力をアップする Pythonによるアルゎリズムの教科曞(マむナビ出版)」「シゎトがはかどる Python自動凊理の教科曞(マむナビ出版)」「すぐに䜿える!業務で実践できる! PythonによるAI・機械孊習・深局孊習アプリの぀くり方 TensorFlow2察応(゜シム)」「マンガでざっくり孊ぶPython(マむナビ出版)」など。