働く 2025-12-05

【Python】ブログ画像を一括リサイズ!10枚を4秒で処理する便利スクリプト

ブログ記事を書くとき、画像のリサイズって面倒ですよね。

1枚ずつ画像編集ソフトで開いて、サイズを調整して、保存して…。 10枚の画像を手作業でリサイズするのに、約4分40秒もかかってしまいます。

そこで作ったのが、画像を自動でリサイズしてくれるPythonスクリプトです。

同じ10枚の画像が、わずか4秒で完了します。約99%の時間短縮です!

フォルダに画像を入れて実行するだけで、すべての画像を幅1000pxに統一してくれます。

今回は、このスクリプトのコードを一行目から詳しく解説します!


どれだけ時間短縮できる?

手作業でのリサイズ時間

画像編集ソフトで1枚ずつリサイズする場合、以下のような作業が必要です:

作業 時間
ソフトを開く 5秒
画像を開く 3秒
サイズ確認・調整 10秒
保存 5秒
ファイル名変更 5秒
合計(1枚あたり) 約28秒

実際の処理時間の比較

Before/After比較:手作業 vs 自動化 - 画像リサイズの時間短縮効果を視覚化

画像枚数 手作業 スクリプト 短縮時間 短縮率
10枚 4分40秒 4秒 4分36秒 約99%短縮
20枚 9分20秒 8秒 9分12秒 約99%短縮
50枚 23分20秒 20秒 23分 約99%短縮

結論: 画像が多ければ多いほど、時間短縮効果が大きくなります!

手作業だと集中力も切れてきますが、スクリプトなら一瞬で完了します。


完全なコード

まず、スクリプト全体を見てみましょう。

"""
画像リサイズスクリプト
- 記事内画像:幅1000px(高さは比率維持)
"""

from PIL import Image
import os

def process_content_image(input_path, output_path):
    """記事内画像処理(幅1000px)"""
    img = Image.open(input_path)

    # 幅1000pxにリサイズ(高さは比率維持)
    if img.width > 1000:
        ratio = 1000 / img.width
        new_height = int(img.height * ratio)
        img = img.resize((1000, new_height), Image.Resampling.LANCZOS)

    img.save(output_path, quality=85, optimize=True)
    print(f"  サイズ: {img.width}×{img.height}px")

def main():
    input_folder = 'images/shinshiro-park-ninja'
    output_folder = 'images/shinshiro-park-ninja/processed'

    # 出力フォルダ作成
    os.makedirs(output_folder, exist_ok=True)

    print("=" * 60)
    print("画像リサイズスクリプト")
    print("=" * 60)
    print("\n【記事内画像】 → 幅1000px")
    print("=" * 60)

    # 記事内画像(すべて)
    for filename in sorted(os.listdir(input_folder)):
        if filename.endswith('.jpg'):
            print(f"\n処理中: {filename}")
            try:
                process_content_image(
                    os.path.join(input_folder, filename),
                    os.path.join(output_folder, filename)
                )
            except Exception as e:
                print(f"  ⚠ エラー: {e}")

    print("\n" + "=" * 60)
    print("✅ 処理完了!")
    print(f"出力先: {output_folder}")
    print("=" * 60)

if __name__ == "__main__":
    main()

それでは、このコードを一行目から順番に詳しく解説していきます!


コード解説:1行目から順番に

コードの各部分を詳しく解説していきます。初心者の方でも理解できるよう、丁寧に説明します。

ドキュメンテーション文字列(1-4行目)

"""
画像リサイズスクリプト
- 記事内画像:幅1000px(高さは比率維持)
"""

解説:

  • Pythonのドキュメンテーション文字列(docstring)です
  • スクリプトの目的を説明しています
  • 三重引用符"""で囲むことで、複数行のコメントを書けます
  • このスクリプトが何をするものかを一目で理解できるようにしています

ライブラリのインポート(6-7行目)

from PIL import Image
import os

解説:

from PIL import Image

  • PIL(Python Imaging Library)の後継であるPillowからImageモジュールをインポート
  • 画像の読み込み、リサイズ、保存などの画像処理機能を提供します
  • Pillowはpip install Pillowでインストールできます

import os

  • Pythonの標準ライブラリosをインポート
  • ファイルやディレクトリの操作に使用します
  • 具体的には:
    • os.makedirs():ディレクトリの作成
    • os.listdir():ディレクトリ内のファイル一覧取得
    • os.path.join():パスの結合

画像処理関数の定義(9-20行目)

def process_content_image(input_path, output_path):
    """記事内画像処理(幅1000px)"""
    img = Image.open(input_path)

    # 幅1000pxにリサイズ(高さは比率維持)
    if img.width > 1000:
        ratio = 1000 / img.width
        new_height = int(img.height * ratio)
        img = img.resize((1000, new_height), Image.Resampling.LANCZOS)

    img.save(output_path, quality=85, optimize=True)
    print(f"  サイズ: {img.width}×{img.height}px")

9行目:関数の定義

def process_content_image(input_path, output_path):
  • process_content_imageという名前の関数を定義
  • 2つの引数を受け取ります:
    • input_path:処理する元画像のパス
    • output_path:保存先のパス

10行目:関数のdocstring

    """記事内画像処理(幅1000px)"""
  • この関数が何をするかを説明
  • 関数の目的を明確にしています

11行目:画像を開く

    img = Image.open(input_path)
  • Image.open()で画像ファイルを読み込みます
  • 読み込んだ画像オブジェクトを変数imgに格納
  • この時点で画像の幅(img.width)や高さ(img.height)にアクセスできるようになります

14行目:リサイズが必要かチェック

    if img.width > 1000:
  • 画像の幅が1000pxより大きい場合のみリサイズを実行
  • なぜこの条件が必要?
    • 1000px以下の画像を拡大すると画質が劣化するため
    • 小さい画像はそのまま保存する方が良い

15行目:縮小比率の計算

        ratio = 1000 / img.width
  • 幅を1000pxにするための縮小比率を計算
  • 例: 3000pxの画像の場合
    • ratio = 1000 / 3000 = 0.333...
    • つまり、元のサイズの約33.3%に縮小

16行目:新しい高さの計算

        new_height = int(img.height * ratio)
  • 元の高さに縮小比率を掛けて、新しい高さを計算
  • int()で整数に変換(ピクセル数は整数でなければならない)
  • 例: 高さ2000pxの画像の場合
    • new_height = int(2000 * 0.333...) = 666
  • これによりアスペクト比(縦横比)が維持されます

17行目:画像のリサイズ

        img = img.resize((1000, new_height), Image.Resampling.LANCZOS)
  • resize()メソッドで画像をリサイズ
  • 第1引数:新しいサイズ(幅, 高さ)のタプル
  • 第2引数:リサンプリングアルゴリズム
    • Image.Resampling.LANCZOS:高品質なリサイズアルゴリズム
    • 画像を縮小する際に最も美しい結果が得られます
    • 他の選択肢:NEAREST(速いが低品質)、BILINEARBICUBIC

19行目:画像の保存

    img.save(output_path, quality=85, optimize=True)
  • リサイズした画像を保存
  • quality=85:JPEG品質を85%に設定
    • 100が最高品質ですが、ファイルサイズが大きくなります
    • 85は品質とファイルサイズのバランスが良い値
  • optimize=True:ファイルサイズを最適化
    • 画質を保ちながら、より効率的に圧縮します

20行目:処理結果の表示

    print(f"  サイズ: {img.width}×{img.height}px")
  • 処理後の画像サイズをコンソールに表示
  • f-string(フォーマット済み文字列リテラル)を使用
  • ユーザーに処理結果を確認させるための情報出力

メイン処理関数(22-50行目)

def main():
    input_folder = 'images/shinshiro-park-ninja'
    output_folder = 'images/shinshiro-park-ninja/processed'

    # 出力フォルダ作成
    os.makedirs(output_folder, exist_ok=True)

    print("=" * 60)
    print("画像リサイズスクリプト")
    print("=" * 60)
    print("\n【記事内画像】 → 幅1000px")
    print("=" * 60)

    # 記事内画像(すべて)
    for filename in sorted(os.listdir(input_folder)):
        if filename.endswith('.jpg'):
            print(f"\n処理中: {filename}")
            try:
                process_content_image(
                    os.path.join(input_folder, filename),
                    os.path.join(output_folder, filename)
                )
            except Exception as e:
                print(f"  ⚠ エラー: {e}")

    print("\n" + "=" * 60)
    print("✅ 処理完了!")
    print(f"出力先: {output_folder}")
    print("=" * 60)

22行目:メイン関数の定義

def main():
  • プログラムのメイン処理をまとめた関数
  • スクリプト実行時に呼び出されます

23-24行目:フォルダパスの設定

    input_folder = 'images/shinshiro-park-ninja'
    output_folder = 'images/shinshiro-park-ninja/processed'
  • input_folder:処理する画像が入っているフォルダ
  • output_folder:処理後の画像を保存するフォルダ
  • カスタマイズポイント: ここを変更すれば別のフォルダで使えます

27行目:出力フォルダの作成

    os.makedirs(output_folder, exist_ok=True)
  • os.makedirs():ディレクトリを作成
  • exist_ok=True:既にフォルダが存在してもエラーにしない
    • このオプションがないと、2回目の実行時にエラーが発生します
  • 必要に応じて親ディレクトリも自動的に作成されます

29-33行目:ヘッダーの表示

    print("=" * 60)
    print("画像リサイズスクリプト")
    print("=" * 60)
    print("\n【記事内画像】 → 幅1000px")
    print("=" * 60)
  • "=" * 60=を60個繰り返して区切り線を作成
  • スクリプトの実行開始を視覚的にわかりやすく表示
  • \n:改行文字

36行目:ファイル一覧の取得とループ

    for filename in sorted(os.listdir(input_folder)):
  • os.listdir(input_folder):指定フォルダ内のすべてのファイル名を取得
  • sorted():ファイル名をアルファベット順にソート
    • 処理順序を予測可能にするため
  • for filename in ...:各ファイルに対してループ処理

37行目:JPEGファイルのみ処理

        if filename.endswith('.jpg'):
  • .jpgで終わるファイル名のみ処理
  • カスタマイズ例: PNGも処理したい場合
    if filename.endswith(('.jpg', '.jpeg', '.png')):

38行目:処理中のファイル名を表示

            print(f"\n処理中: {filename}")
  • 現在処理しているファイル名を表示
  • 進捗状況を確認できるようにしています

39-43行目:エラーハンドリング付き処理

            try:
                process_content_image(
                    os.path.join(input_folder, filename),
                    os.path.join(output_folder, filename)
                )
  • tryブロック:エラーが発生する可能性のある処理を囲む
  • process_content_image()を呼び出して画像を処理
  • os.path.join():パスを正しく結合
    • Windows: images\shinshiro-park-ninja\photo1.jpg
    • Mac/Linux: images/shinshiro-park-ninja/photo1.jpg
    • OSに応じて適切な区切り文字を使用してくれます

44-45行目:エラー処理

            except Exception as e:
                print(f"  ⚠ エラー: {e}")
  • 画像処理中にエラーが発生した場合の処理
  • エラーメッセージを表示して、次のファイルの処理を続行
  • なぜ重要?
    • 1つのファイルでエラーが出ても、他のファイルは処理できる
    • 壊れた画像ファイルがあってもスクリプトが停止しない

47-50行目:完了メッセージ

    print("\n" + "=" * 60)
    print("✅ 処理完了!")
    print(f"出力先: {output_folder}")
    print("=" * 60)
  • すべての処理が完了したことを表示
  • 処理済み画像の保存先を確認できます

スクリプトの実行(52-53行目)

if __name__ == "__main__":
    main()

解説:

if __name__ == "__main__":

  • このスクリプトが直接実行された場合のみmain()を呼び出す
  • 他のスクリプトからimportされた場合は実行されない
  • Pythonのベストプラクティスです

なぜこの書き方をするのか?

  • 直接実行時: python resize_images.py
    • __name__"__main__"になる → main()が実行される
  • インポート時: from resize_images import process_content_image
    • __name__はモジュール名になる → main()は実行されない
    • 関数だけを再利用できる

実際の使い方

1. 必要なライブラリのインストール

pip install Pillow

2. フォルダ構成

images/
└── shinshiro-park-ninja/
    ├── photo1.jpg
    ├── photo2.jpg
    └── photo3.jpg

3. スクリプトの実行

python resize_images.py

4. 出力結果

images/
└── shinshiro-park-ninja/
    ├── processed/
    │   ├── photo1.jpg  # 幅1000px
    │   ├── photo2.jpg  # 幅1000px
    │   └── photo3.jpg  # 幅1000px
    ├── photo1.jpg  # 元画像(保持される)
    ├── photo2.jpg
    └── photo3.jpg

カスタマイズ方法

異なるフォルダで使用する

input_folder = 'images/your-article-folder'
output_folder = 'images/your-article-folder/processed'

画像の幅を変更する

# 幅800pxに変更
if img.width > 800:
    ratio = 800 / img.width
    new_height = int(img.height * ratio)
    img = img.resize((800, new_height), Image.Resampling.LANCZOS)

画質を変更する

img.save(output_path, quality=90, optimize=True)  # 高品質
img.save(output_path, quality=75, optimize=True)  # 小サイズ

PNG画像も処理する

if filename.endswith(('.jpg', '.jpeg', '.png')):

具体的な活用方法

このスクリプトの最大のメリットは、ブログ記事のパフォーマンス向上です。

私の場合: ブログ記事が重いと良くないので、一括でリサイズできるのが最高です!記事を公開する前に、必ずこのスクリプトで画像を最適化しています。

主な効果

  • ページ読み込み速度が向上:1000px幅に統一することで、ファイルサイズが約94%削減されます
  • SEOスコアの改善:GoogleのPageSpeed Insightsで高評価を獲得しやすくなります
  • ストレージ容量の削減:10枚の画像で約25MB → 約1.5MBに削減

これだけで、記事の読み込み速度が劇的に改善します!


よくある質問(FAQ)

Q1: なぜ1000pxなのですか?

A: 1000pxは、多くのブログテーマで最適な幅です。これより小さいと画質が劣化し、大きいとファイルサイズが増えて読み込みが遅くなります。必要に応じて、カスタマイズ方法のセクションで幅を変更できます。

Q2: PNG画像も処理できますか?

A: はい、可能です。カスタマイズ方法のセクションで、PNG画像も処理する方法を紹介しています。ただし、PNGは透過画像やロゴなどに適しており、写真の場合はJPEGの方がファイルサイズが小さくなります。

Q3: 元画像は削除されますか?

A: いいえ、元画像はそのまま保持されます。processedフォルダにリサイズ後の画像が保存されるため、安心して使用できます。

Q4: エラーが発生した場合はどうなりますか?

A: エラーハンドリング機能により、1つのファイルでエラーが発生しても他のファイルの処理は続行されます。エラーメッセージが表示されるので、問題のあるファイルを特定できます。


まとめ

このスクリプトのポイントをまとめます。

技術的なポイント

  • Pillowライブラリで画像を読み込み・リサイズ・保存
  • LANCZOSリサンプリングで高品質なリサイズ
  • アスペクト比を維持する計算式
  • エラーハンドリングで安全な一括処理
  • os.path.join()でクロスプラットフォーム対応

実用的なポイント

  • 自動化:手作業でのリサイズが不要
  • 品質保証:統一された画質とサイズ
  • 柔軟性:簡単にカスタマイズ可能
  • 安全性:元画像を保持
  • 効率性:一括処理で約99%の時間短縮(10枚で4分40秒→4秒)

ブログ記事の画像準備が圧倒的に楽になる、まさに「便利すぎる」スクリプトです!

コードを一行ずつ理解することで、自分のニーズに合わせてカスタマイズできるようになります。


関連記事・参考情報


このスクリプトを使って、ブログ運営をもっと効率的に!