Gitで整理!画像を200KB圧縮+コピーライト追加【第2回:圧縮モジュール】

当ページのリンクには広告が含まれています。

前回の記事では、Pythonで作成した画像加工スクリプトをGitで管理するために、まずはリポジトリの構成をどう設計するかを紹介しました。

そのため今回は、その続編として、スクリプトの中核を担う「圧縮処理」部分にフォーカスします。
具体的には、画像を横幅1200pxにリサイズし、さらに200KB以下になるように圧縮する処理を行う compress.py モジュールの内容を、関数単位で丁寧に解説していきます。

この処理は、ブログなどに画像をアップロードする際にとても便利です。今回、初めてGit管理にチャレンジしています。機能別に.pyを分けてモジュール、関数単位で管理しておくことで、今後の拡張や修正もスムーズになると思います。

同様の内容は、下記記事にもありますが、Git管理用にモジュールの一部としたため、本記事では改めて整理して紹介します。


目次

プログラム全体説明:画像を200KB圧縮+コピーライト追加

当連載で最終的に作成するプログラムについて説明します。
当記事の内容は、STEP2における①〜③の箇所に使用するモジュールとなります。

プログラムの目的

前提条件

  • 入力ファイル名は、基本的に “YYYY年MM月DD日_任意の文字列.拡張子” の形式で撮影日が含まれていることを想定しています。
  • 日付が含まれない場合は、現在日付(実行日)を “YYYY年MM月DD日” 形式で返します。

JPEG画像を以下の処理で一括加工し、ブログ用に最適化された画像を作成する:
• 横幅を1200pxにリサイズ
• 目標サイズ(200KB)以下に圧縮
• ファイル名から日付を取得し、コピーライト付きテキストを画像に追加

プログラムの動作(処理の流れ)

STEP
指定フォルダ内の .jpeg 画像をすべて取得
STEP
各画像について以下を実行
  • ファイル名を取得して、保存用の出力パスを作成
  • 横幅を1200pxにリサイズし、一時保存
  • 200KB以下になるように品質を調整して圧縮保存
  • 「日付+©ふくゆー」のテキストを画像右下に追加(黒背景+白文字)
STEP
加工済み画像を「compress_元のファイル名.jpg」の形式でoutput_imagesフォルダに保存

main.py

当プログラムのmain.py全文です。:

import os
from utils.compress import compress_and_resize_jpeg, compress_image_to_target_size
from utils.add_text import add_text_with_background
from utils.date_utils import extract_photo_date_from_filename
from config.config import quality, width, target_size_kb, image_file_dir, save_dir, font_path  # ← 設定をインポート

# 出力ディレクトリがなければ作成
os.makedirs(save_dir, exist_ok=True)

# 入力フォルダ内のJPEG画像を順に処理
for filename in os.listdir(image_file_dir):
    if filename.lower().endswith((".jpg", ".jpeg")):
        input_path = os.path.join(image_file_dir, filename)
        print(f"処理対象: {filename}")

        base_name = os.path.splitext(filename)[0]
        output_filename = f"compress_{base_name}.jpg"
        output_path = os.path.join(save_dir, output_filename)

        # Step 1: リサイズ+Exif除去処理(品質95で一時保存)
        temp_path = output_path + ".temp.jpg"
        print("▶ Step 1: リサイズ+Exif除去")
        compress_and_resize_jpeg(input_path, temp_path, quality=95, width=width)

        if os.path.exists(temp_path):
            size_kb = os.path.getsize(temp_path) / 1024
            print(f"初期サイズ: {size_kb:.2f} KB")

        # Step 2: 目標サイズ以下に再圧縮
        print("▶ Step 2: サイズ調整(目標: {} KB)".format(target_size_kb))
        compress_image_to_target_size(temp_path, output_path, target_size_kb=target_size_kb)

        # Step 3: 画像に日付+著作権テキストを追加
        if os.path.exists(output_path):
            photo_date = extract_photo_date_from_filename(filename)
            text = f"{photo_date} ©ふくゆー"
            print("▶ Step 3: テキスト追加")
            add_text_with_background(output_path, output_path, text, font_path)

            final_size_kb = os.path.getsize(output_path) / 1024
            print(f"最終サイズ: {final_size_kb:.2f} KB")
            print("-" * 40)

        # Step 4: 一時ファイルを削除
        if os.path.exists(temp_path):
            os.remove(temp_path)

print("✅ 全処理完了")

当記事では、main.pyにおけるSTEP1内の関数:compress_and_resize_jpeg(input_path, temp_path, quality=95, width=width)とSTEP2内の関数:compress_image_to_target_size(temp_path, output_path, target_size_kb=target_size_kb)について解説しています。


compress.pyモジュールについて説明

compress.py モジュールの構成

このモジュールは、以下の2つの主な関数で構成されています:

関数名役割
compress_and_resize_jpeg()リサイズ+JPEG圧縮(Exif削除も含む)
compress_image_to_target_size()サイズが200KB以下になるまでループ圧縮

この2つの関数を使用して、指定した横幅にリサイズし、200KB以下に圧縮された.jpg画像を出力するのが目的です。compress_and_resize_jpeg() のみでは、200KB以下に圧縮された画像が安定して圧縮できず、画像によっては圧縮が不十分であることがありました。そのため、後処理として確実に200KB以下になるまでファイルサイズを圧縮するcompress_image_to_target_size()を追加し、処理を2つに分けています。

使用するライブラリ

今回のスクリプトでは、以下の2つのPythonモジュールを使用しています。

この2つのモジュールを組み合わせることで、「画像を読み込み → リサイズ&Exif削除 → JPEGとして保存 → ファイルサイズを確認しながら圧縮」といった処理を柔軟に構成できます。

Pillow(PIL)

当プログラムにおける用途

画像の読み込み・リサイズ・JPEG保存などを行うために使用しています。

インストール要否

Python標準ライブラリには含まれていないため、インストールが必要です。

インストール方法(Pip使用):

pip install pillow
主な用途
用途関数・メソッド
画像の読み込みimage.opnen( )
画像の変換convert( )
画像のリサイズ.resize( )
メタデータ削除(新規イメージファイル作成+貼り付け)Image.new ( ) + putdata( )
画像保存.save( )

os

当プログラムにおける用途

ファイルサイズの取得など、ファイルパス操作のために使用しています。  

インストール要否

このライブラリは、Pythonに標準で付属しているため、インストール不要です。

主な用途
用途関数・メソッド
ファイルサイズの取得(KB単位に変換)os.path.getsize()

スクリプト全文

以下が compress.py のスクリプト全文です。:

from PIL import Image
import os

def compress_and_resize_jpeg(input_path, output_path, quality, width):
    # 元画像を開き、RGBに変換(JPEG形式に対応)
    img = Image.open(input_path).convert("RGB")

    # アスペクト比を保持しながらリサイズ
    aspect_ratio = img.height / img.width
    
    # 指定した横幅に合わせて、高さを計算
    height = int(width * aspect_ratio)

    # 高品質なリサンプリング(LANCZOS)でリサイズ
    img = img.resize((width, height), Image.Resampling.LANCZOS)

    # Exifなどのメタデータを完全に削除するため、新しい画像に貼り付ける
    clean_img = Image.new(img.mode, img.size)
    clean_img.putdata(list(img.getdata()))

    # JPEGで保存(optimizeオプション付き)
    clean_img.save(output_path, "JPEG", quality=quality, optimize=True)

    print(f"Saved {output_path} (Exif removed, quality={quality}, size=({width}x{height}))")

def compress_image_to_target_size(input_path, output_path, target_size_kb, initial_quality=85, step=5):
    # 画像を開く
    img = Image.open(input_path)
    
    quality = initial_quality
    while True:
        # 一時的に画像を保存してサイズを確認
        img.save(output_path, "JPEG", quality=quality)
        
        # ファイルサイズを取得(KBに変換)
        file_size_kb = os.path.getsize(output_path) / 1024
        
        # ファイルサイズが目標以下になったら終了
        if file_size_kb <= target_size_kb or quality <= 5:
            print(f"Image compressed to {file_size_kb:.2f} KB with quality={quality}")
            break
        
        # 品質を下げて再度圧縮
        quality -= step

関数説明

それぞれの関数について解説していきます。

compress_and_resize_jpeg(input_path, output_path, quality, width)

目的

画像を引数で指定した横幅 width で縦横比を保ちリサイズし、指定品質でJPEG保存。Exifデータ削除も行う。

引数
  • input_path: 入力画像のパス
  • output_path: 出力ファイルのパス
  • quality: JPEG保存時の品質(例:85)
  • width: リサイズ後の横幅(px)
動作概要
  • 高品質なリサイズとなるようにImage.Resampling.LANCZOS を使用して、画像の横幅を指定したwidthに縦横比を保ちリサイズする。
  • Exif情報を確実に削除するために新しい画像を生成しデータをコピー

compress_image_to_target_size(input_path, output_path, target_size_kb, initial_quality=85, step=5)

目的

画像を200KB以下に圧縮するために quality を変化させながら試行

引数
  • input_path: 入力画像のパス
  • output_path: 出力ファイルのパス
  • target_kb: 目標サイズ(KB)
  • initial_quality: 初期の品質設定。初期値は、85に設定
  • step:目標サイズに到達しなかった場合に”quality”をどの程度下げるかを設定。初期値は5に設定。
動作概要
  • 対象画像を保存して、ファイルサイズ確認
  • quality=85 から圧縮開始し、qualitystep設定値で設定した値で下げてループし、圧縮を繰り返します。
  • 圧縮は、下記条件で終了します。
    • target_kb(目標サイズ)に到達
    • qualityが5以下

4.まとめ

今回紹介した圧縮モジュールは、画像を効率的に軽量化できるだけでなく、処理を関数ごとにモジュールとして分けることで、コード全体の見通しや管理のしやすさが大きく向上したと感じています。

Git上でも変更履歴を追いやすくなり、今後の機能追加や修正もスムーズに行えそうです。

次回は、画像にコピーライト(著作権情報)を自動的に挿入する処理について解説する予定です。引き続き、ブログ画像の運用を効率化していくステップをご紹介していきます。

目次