jpgからパワポスライド作成ツール

![SS 192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png) 画像の束からプレゼン用スライド


## やること
jpgやpngの入ったフォルダを指定すると、そこから１ページに１枚写真が入ったパワポスライドを作成してくれるツールです。
旅行の土産話はもちろん、トレードショーや学会などに視察を行った時の報告書づくりに使えます。
またpdfをjpg化した際にもまとめてパワポに貼り直せます。

## コード
ひょっとするとパワポ本来の機能でもできそうな気がしますが、pythonのコードにしました。
(制作はChatGPTに手伝ってもらってます。)



``` python:jpg2pptx.py

import os
import tkinter as tk
from tkinter import filedialog
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from PIL import Image, ExifTags
import pyheif

# フォルダ選択のためのダイアログを表示する関数


def select_folder():
    root = tk.Tk()
    root.withdraw()
    folder_selected = filedialog.askdirectory()
    return folder_selected

# フォルダ内の対応する画像ファイルを取得し、番号順にソートする関数


def get_sorted_image_files(folder_path):
    supported_formats = ('.png', '.jpg', '.jpeg', '.gif', '.heic')
    files = [f for f in os.listdir(folder_path) if os.path.splitext(f)[
        1].lower() in supported_formats]
    files.sort(key=lambda f: int(''.join(filter(str.isdigit, f)))
               if ''.join(filter(str.isdigit, f)) else float('inf'))
    return files

# HEICファイルをPILイメージに変換する関数


def load_heic_image(heic_path):
    heif_file = pyheif.read(heic_path)
    image = Image.frombytes(
        heif_file.mode,
        heif_file.size,
        heif_file.data,
        "raw",
        heif_file.mode,
        heif_file.stride,
    )
    return image

# 画像の向きをExifデータに基づいて修正する関数


def correct_image_orientation(image):
    try:
        for orientation in ExifTags.TAGS.keys():
            if ExifTags.TAGS[orientation] == 'Orientation':
                break
        exif = image._getexif()
        if exif is not None:
            orientation = exif.get(orientation)
            if orientation == 3:
                image = image.transpose(Image.ROTATE_180)
            elif orientation == 6:
                image = image.transpose(Image.ROTATE_270)
            elif orientation == 8:
                image = image.transpose(Image.ROTATE_90)
    except (AttributeError, KeyError, IndexError):
        pass
    return image

# 重複しないファイル名を生成する関数


def generate_unique_filename(directory, filename):
    base, ext = os.path.splitext(filename)
    counter = 1
    unique_filename = filename
    while os.path.exists(os.path.join(directory, unique_filename)):
        unique_filename = f"{base}_{counter}{ext}"
        counter += 1
    return unique_filename

# PowerPointファイルを作成する関数


def create_ppt_from_images(image_folder):
    ppt = Presentation()

    # スライドサイズを1920x1080ピクセルに設定
    ppt.slide_width = Inches(1920 / 96)  # 96 DPI
    ppt.slide_height = Inches(1080 / 96)  # 96 DPI

    # スライドマスターのクリアと背景設定
    slide_master = ppt.slide_master
    for layout in slide_master.slide_layouts:
        for shape in layout.shapes:
            if shape.has_text_frame:
                sp = shape
                sp.text = ""
            sp = layout.shapes._spTree.remove(sp._element)
        layout.background.fill.solid()
        layout.background.fill.fore_color.rgb = RGBColor(0, 0, 0)

    image_files = get_sorted_image_files(image_folder)

    for image_file in image_files:
        img_path = os.path.join(image_folder, image_file)
        slide = ppt.slides.add_slide(ppt.slide_layouts[5])  # 白紙スライドを追加

        # スライドの背景色を黒に設定
        slide.background.fill.solid()
        slide.background.fill.fore_color.rgb = RGBColor(0, 0, 0)

        if os.path.splitext(img_path)[1].lower() == '.heic':
            img = load_heic_image(img_path)
        else:
            img = Image.open(img_path)

        img = correct_image_orientation(img)
        img_width, img_height = img.size

        # スライドサイズ (1920x1080ピクセル)
        slide_width = ppt.slide_width.inches * 96  # ピクセル単位
        slide_height = ppt.slide_height.inches * 96  # ピクセル単位

        # 画像の縦横比を維持して、スライドの高さに収まるように縮小拡大
        scale_ratio = slide_height / img_height

        width = img_width * scale_ratio
        height = img_height * scale_ratio

        left = (slide_width - width) / 2  # 横方向の余白はスライドの中央に配置
        top = 0  # 縦方向は上下にぴったり合わせる

        # 回転後の画像を保存してから貼り付ける
        temp_img_path = os.path.join(image_folder, f"temp_{image_file}")
        img.save(temp_img_path)

        slide.shapes.add_picture(temp_img_path, Inches(
            left / 96), Inches(top / 96), Inches(width / 96), Inches(height / 96))

        # 一時ファイルを削除
        os.remove(temp_img_path)

    # 出力ファイルを選択したディレクトリと同じ階層に保存
    parent_folder = os.path.dirname(image_folder)
    output_filename = generate_unique_filename(
        parent_folder, "ReportSlider.pptx")
    output_path = os.path.join(parent_folder, output_filename)
    ppt.save(output_path)
    print(f"PowerPointファイルが作成されました: {output_path}")


# メイン処理
if __name__ == "__main__":
    image_folder = select_folder()
    if image_folder:
        create_ppt_from_images(image_folder)
    else:
        print("フォルダが選択されませんでした。")

```

## 使い方

ターミナルで
```
python jpg2pptx.py 
```
を実行し、ダイアログボックスでjpgやpngが入ったフォルダを選択します。
そのフォルダと同じ階層に、"ReportSlider.pptx"というファイルが生成されます。
パワポでファイルを開くと、写真が１ページに１枚ずつ、上下もしくは左右にフィットする形で中央配置されています。デフォルトは黒背景です。

## 最後に

もし動かなかったらすみません。
必要なライブラリなどちょっとまとめます。
(HEIC対応しようとしてちょっと不具合出てます。)