【Python】argparseとPillowで画像一括変換ツールを作ってみた

【Python】argparseとPillowで画像一括変換ツールを作ってみた

公開: 更新:
CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座

画像を1枚ずつ変換していくのは、地味に手間がかかります。そこでPythonargparseを使い、フォルダ内の画像をまとめてJPEG・PNG・WebPへ変換するコマンドラインツールを作ってみました。サンプル生成用のgenと一括変換用のconvertという2つのサブコマンドに分け、Pillowが実際の変換を担当します。

この記事では、コードの要点から実際に動かした結果、初心者がつまずきやすいところまでを順に解説していきます。

argparseの基本概念、要件定義、実装、動作確認までを順番に学べる構成です。動画は目次から確認したい場面へ移動でき、本文だけでも手順と考え方が完結します。

【Python】argparseとPillowで画像一括変換ツールを作ってみた|フルカリキュラム|概要・完成挙動
動画の内容をテキストで確認する

オープニング。argparseとPillowを使って画像一括変換CLIを作るカリキュラムを始めます。概要紹介。

argparseとPillowの役割と使い方を学ぶ 画像一括変換CLIの要件を整理する 完成コードと実行結果を確認する 最後に実コマンドとファイル状態で完成挙動を確かめる 具体的にやること。

genでサンプルPNG画像を生成するconvertでフォルダ内の画像を一括変換するJPEG・PNG・WebPの3形式へ出力できる --resizeで出力画像のサイズを変更する --qualityでJPEGとWebPの画質を指定する 実装環境・必須アプリ。

OS:Windows 11 Pro Python:3.13.3シェル:PowerShell 5.1必須アプリ:コードエディター、ターミナル、エクスプローラー パッケージ:Pillow Pythonのargparseと画像処理のPillowとは。

コマンドライン引数を読み取るargparseの役割:genは--outで生成先、--countで枚数を受け取る 画像を生成・変換するPillowの役割:Image.newで背景色付きの画像を新規作成する argparseとPillowで画像変換CLIを作る際の要点。

iterdirでフォルダ直下のファイルを走査するsuffix.lowerでSRC_SUFFIXES内の拡張子だけ残すsortedで処理順をファイル名順に揃える 画像一括変換CLIの要件定義。

genで--countに応じた枚数の画像が生成されるconvertで対象画像がすべて指定形式へ変換される 透過PNGをJPEGへ変換すると背景が白で保存される --resize指定時に出力画像が指定サイズになる 対象外の拡張子のファイルは変換されない 変換件数と出力先がメッセージに表示される 確認1/4: サンプル画像を生成する。

genサブコマンドを呼び出して、お試し用のサンプル画像を3枚生成します。生成先フォルダ名と作られたファイルの一覧が表示されます。実行2/4: 画像をJPEGへ一括変換する。

先にサンプルを用意してから、convertでフォルダ内の画像をJPEGへまとめて変換します。変換件数と入出力の対応が確認できます。確認2/4: 画像をJPEGへ一括変換する。

先にサンプルを用意してから、convertでフォルダ内の画像をJPEGへまとめて変換します。変換件数と入出力の対応が確認できます。実行3/4: リサイズしながらWebPへ変換する。

convertに--resizeを添えて、画像を200x200へ縮小しながらWebPへ変換します。ヘッダーに指定したサイズも表示されます。確認3/4: リサイズしながらWebPへ変換する。

convertに--resizeを添えて、画像を200x200へ縮小しながらWebPへ変換します。ヘッダーに指定したサイズも表示されます。実行4/4: PNGへまとめて変換する。

同じ手順でフォルダ内の画像をPNGへ一括変換します。出力フォルダに変換後のファイルがそろう様子を確認します。確認4/4: PNGへまとめて変換する。

同じ手順でフォルダ内の画像をPNGへ一括変換します。出力フォルダに変換後のファイルがそろう様子を確認します。学習内容のまとめ。

genは--outで生成先、--countで枚数を受け取るImage.newで背景色付きの画像を新規作成するiterdirでフォルダ直下のファイルを走査する 追加依存を増やさず標準のargparseで引数を扱う 小さく実行確認しながら完成状態まで段階的に組み立てる エンディング。Python研修はCodeCampでご確認ください。

Pythonのargparseと画像処理のPillowとは

今回使用する主要なライブラリについて、役割と使い分けを順番に確認します。

コマンドライン引数を読み取るargparseの役割

argparseはPythonに標準で付属する引数解析ライブラリで、追加インストールなしに使えます。ターミナルから渡されるオプションやサブコマンドを決められたルールに沿って読み取るため、入力チェックを一から書く手間が減ります。

今回のツールではサンプル生成のgenと一括変換のconvertを1つのコマンドへまとめたいので、サブコマンド機能が欠かせません。使い方を誤ったときには自動でヘルプやエラーが表示され、利用者にも親切な作りになるでしょう。

genとconvertの各サブコマンドが受け取る、主な引数とオプションの一覧です。

  • genは--outで生成先、--countで枚数を受け取る
  • convertは入力フォルダをsrc位置引数で受け取る
  • convertの--toはjpeg・png・webpから必須で選ぶ
  • --resizeは400x400のような文字列で指定する
  • --qualityは1から100の整数で既定値は85
  • dest=commandで選ばれたサブコマンド名を取得する

画像を生成・変換するPillowの役割

Pillowは画像の読み込みや加工、保存をまとめて扱えるライブラリで、PILという名前でインポートします。写真やイラストをコードから開き、サイズを変えたり別の形式で書き出したりといった操作が数行で実現できます。このツールがPillowを頼りにするのは、お試し用のサンプル画像を描く場面と、実際にフォーマットを変換する場面の両方です。

JPEGやWebPのように保存時の設定が要る形式にも対応しているため、画質やリサイズの指定も同じ流れで扱えるでしょう。

このツールがPillowに任せている画像処理の役割ごとの一覧です。

  • Image.newで背景色付きの画像を新規作成する
  • ImageDrawで円やテキストを描き込む
  • Image.openで既存の画像ファイルを読み込む
  • convertでRGBAやPからRGBへモードを変える
  • resizeで指定した幅と高さに縮小・拡大する
  • saveで拡張子に応じた形式へ書き出す
さらに詳しく学べるPython研修の詳細はこちら

Python・argparseで開発する場合の環境構築

この記事のセットアップ手順と掲載コードは、Windows 11 Pro、PowerShell 5.1、Python 3.13.3で動作確認しています。仮想環境を有効化せず、その中のPythonを直接指定するため、以下のコマンドはPowerShellとコマンドプロンプト(cmd)の両方で使えます。

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install Pillow

macOS・Linuxでは仮想環境内のPythonパスが異なります。今回の動作確認環境とは異なるため、以下は環境差分を補う参考手順です。

python3 -m venv .venv
./.venv/bin/python -m pip install Pillow
  • Pillowのdraw.textは追加フォントが無くても既定のビットマップフォントで描画できるため、サンプル生成にフォント指定は不要です。
  • convertは入力フォルダに画像がある前提なので、先にgenでサンプルを生成してから変換コマンドを実行してください。
さらに詳しく学べるPython研修の詳細はこちら

画像一括変換CLIの要件定義

目的は、argparseとPillowでフォルダ内の画像をまとめて別フォーマットへ変換するCLIを自作できるようになることです。

対象者として、Pythonの基本文法を終えてコマンドラインツールの作り方を学びたい人を想定しています。

完成物は、genとconvertの2つのサブコマンドを備えた画像一括変換CLIです。

実装へ入る前に、機能・品質・受け入れ条件を分けて確認します。

機能要件

  • genでサンプルPNG画像を生成する
  • convertでフォルダ内の画像を一括変換する
  • JPEG・PNG・WebPの3形式へ出力できる
  • --resizeで出力画像のサイズを変更する
  • --qualityでJPEGとWebPの画質を指定する
  • 変換した件数と入出力の対応を一覧表示する

非機能要件

  • 追加依存を増やさず標準のargparseで引数を扱う
  • 画像の生成と変換はPillowに任せる
  • 対応外の拡張子は入力から自動で除外する
  • 出力フォルダが無ければ実行時に作成する
  • サブコマンドの指定漏れはエラーで知らせる

実装方針

今回はargparseとPillowの基本動作を追いやすくするため、画像一括変換CLI本体を1つのPythonファイルへまとめます。

入力、判定、結果表示の役割を分け、実行結果を確認しながら機能を積み上げます。

画像一括変換CLIを安全に組み立てるための実装方針は次のとおりです。

  • 追加依存を増やさず標準のargparseで引数を扱う
  • 画像の生成と変換はPillowに任せる
  • 対応外の拡張子は入力から自動で除外する
  • 出力フォルダが無ければ実行時に作成する
  • サブコマンドの指定漏れはエラーで知らせる

完成と判断する条件

  1. genで--countに応じた枚数の画像が生成される
  2. convertで対象画像がすべて指定形式へ変換される
  3. 透過PNGをJPEGへ変換すると背景が白で保存される
  4. --resize指定時に出力画像が指定サイズになる
  5. 対象外の拡張子のファイルは変換されない
  6. 変換件数と出力先がメッセージに表示される
さらに詳しく学べるPython研修の詳細はこちら

PythonのargparseとPillowで画像変換CLIを作る際の要点

このツールの心臓部は、指定フォルダの中から対象画像を集め、1枚ずつ変換して別フォルダへ保存する流れです。まず対応する拡張子だけを選び出し、変換に向かない下ごしらえ(透過の除去やリサイズ)を済ませてから保存します。処理した結果は「元ファイルと出力ファイルの対応」として記録し、最後にまとめて件数と一覧を表示するようにしました。

genとconvertで入り口を分けているので、サンプル作りと本番の変換をはっきり区別して呼び出せます。

convertを実行したときに内部で順番に起こる処理の一覧です。

  • iterdirでフォルダ直下のファイルを走査する
  • suffix.lowerでSRC_SUFFIXES内の拡張子だけ残す
  • sortedで処理順をファイル名順に揃える
  • mkdirで出力フォルダを事前に用意する
  • 元パスと出力パスの組をresultsへ追記する
  • 件数と対応表を1つのメッセージへ整える

対象ファイルを拡張子で絞り込む

フォルダの中には、画像以外のファイルが混ざっていることもあります。convert_folderでは、Path(src).iterdirで直下の項目を取り出し、suffixを小文字にしてSRC_SUFFIXESに含まれるものだけを対象にします。大文字の.JPGでも同じ画像として扱えるよう、比較の前に必ず小文字へそろえている点がポイントです。

さらにsortedで並べ替えることで、実行するたびに処理順が変わらず、結果が読みやすくなります。

変換対象のファイルを選ぶときの判定条件の一覧です。

  • iterdirはサブフォルダの中までは探さない
  • 拡張子は.png・.jpg・.jpeg・.webp・.bmpに限る
  • suffix.lower()で大文字の拡張子も受け入れる
  • 対象が0件なら変換結果も空になる

prepare_imageで変換前の下ごしらえをする

画像はそのまま保存できないことがあるため、保存前にひと手間かけます。prepare_imageは、変換先がJPEGなら透過を白背景へ合成し、それ以外はRGBへ変換して形式の違いを吸収してくれます。--resizeが指定されているときだけ、resizeで幅と高さを作り直しましょう。

指定がなければ元のサイズを保つので、必要なときにだけサイズ変更が働く作りになっています。

prepare_imageが保存前に画像へ加える調整の一覧です。

  • JPEGのときだけ透過を白背景へ合成する
  • その他の形式ではRGBへ統一する
  • --resize指定時のみresizeでサイズを変える
  • resize文字列はparse_sizeで幅と高さに分ける

変換結果を件数と一覧のメッセージにする

処理が終わったあとに何が起きたのか分からないと、利用者は不安になります。mainでは、convert_folderが返した対応の一覧をもとに、変換件数と出力先を1行目のヘッダーへまとめましょう。--resizeを使ったときは、そのサイズもヘッダーに書き足して伝えます。

続く各行へ「元ファイル -> 出力ファイル」を並べ、結果を目で追える形にして返しています。

mainが変換後に組み立てる結果メッセージの構成要素の一覧です。

  • 1行目に件数と変換先フォーマットを示す
  • 出力フォルダ名を出力: の形で添える
  • --resize時はサイズ 幅x高さを追記する
  • 2行目以降に変換した各ファイルの対応を並べる

Python研修一覧はこちら

目的に合うPython研修を一覧形式から探したい方は、ぜひご利用ください。

Python研修を比較する

Java研修一覧はこちら

目的に合うJava研修を一覧形式から探したい方は、ぜひご利用ください。

Java研修を比較する

PHP研修一覧はこちら

目的に合うPHP研修を一覧形式から探したい方は、ぜひご利用ください。

PHP研修を比較する

新入社員研修

目的に合う新入社員研修を一覧形式から探したい方は、ぜひご利用ください。

新入社員研修を比較する

全ての研修からも探したい方はこちら

Pythonで画像一括変換CLIの完成コード

00:00 / 11:35
【Python】argparseとPillowで画像一括変換ツールを作ってみた|フルカリキュラム|コード実装
動画の内容をテキストで確認する

INTRO: argparseを使ったCLI開発を開始。コードを1行ずつ入力し、節目ごとに実行結果を確かめながら完成させます。LINE 001: モジュールの説明文の始まり。

ファイルの先頭に置いた三重引用符の説明文で、このプログラムがargparseを使って画像をまとめて変換するコマンドラインツールであることを示しています。LINE 003: genサブコマンドの紹介。説明文の続きで、genというサブコマンドを使うとお試し用のサンプルPNG画像を作れることを紹介しています。

LINE 004: convertサブコマンドの紹介。こちらも説明文の続きで、convertを使うとフォルダ内の画像をJPEGやPNG、WebPへまとめて変換できることを伝えています。LINE 005: 説明文の終わり。

三重引用符を閉じて、モジュール全体の説明文を締めくくっています。ここまでがファイルの概要を表す部分です。LINE 007: argparseの読み込み。

コマンドラインの引数を解析するための標準ライブラリargparseを読み込んでいます。あとで引数のルールを組み立てるときに使います。LINE 008: Pathの読み込み。

ファイルやフォルダのパスを扱いやすくするPathクラスを、標準ライブラリのpathlibから取り込んでいます。LINE 010: Pillowの読み込み。画像を扱うライブラリPillowから、画像本体を表すImageと、図形や文字を描くImageDrawを読み込んでいます。

LINE 013: 対応表の目的を示すコメント。この次で作る辞書が、出力フォーマット名とファイル拡張子を結びつける対応表であることを説明するコメントです。LINE 014: 対応表の作成開始。

FORMATSという名前の辞書を作り始めています。フォーマット名をキー、拡張子を値として登録していきます。LINE 015: JPEGの拡張子登録。

jpegというフォーマットに.jpgという拡張子を対応させています。変換のときにこの拡張子で保存されます。LINE 016: PNGの拡張子登録。

pngというフォーマットに.pngという拡張子を対応づけています。LINE 017: WebPの拡張子登録。webpというフォーマットに.webpという拡張子を対応づけています。

LINE 018: 対応表の作成終了。波かっこを閉じて、フォーマットと拡張子の対応表を完成させています。LINE 020: 入力拡張子を示すコメント。

次の行で、変換元として読み込む画像の拡張子をまとめておくことを説明するコメントです。LINE 021: 入力拡張子の集合。読み込み対象にする拡張子を集合として定義しています。

ここに含まれる拡張子のファイルだけを変換の入力に使います。RUN 1/6: 対応フォーマット表と入力拡張子を確認する。FORMATSは変換先フォーマットと拡張子の対応表、SRC_SUFFIXESは入力として読み込む拡張子の集合です。

まずこの2つが正しく定義できているかを表示して確かめます。CHECK 1/6: 途中実行に成功。

出力フォーマット対応表: jpeg -> .jpg png -> .png webp -> .webp入力として扱う拡張子: ['.bmp', '.jpeg', '.jpg', '.png', '.webp'] LINE 024: パーサ定義を示すコメント。この下の関数で、コマンドラインの引数のルールを組み立てることを示すコメントです。

LINE 025: パーサ生成関数の定義。build_parserという関数を定義しています。引数の設計をここにまとめておき、あとで呼び出して使います。

LINE 026: パーサ本体の作成。argparseのArgumentParserを作り、このツールの引数を管理する土台を用意しています。LINE 027: プログラム名の指定。

prog引数でプログラム名をimgconvと指定しています。この名前はヘルプの表示で使われます。LINE 028: ツールの説明文設定。

description引数に説明文を渡し、ヘルプを表示したときにこのツールの目的が伝わるようにしています。LINE 029: パーサ設定の閉じかっこ。かっこを閉じてArgumentParserの設定を終え、その結果をparserという変数で受け取っています。

LINE 030: サブコマンドの受け口作成。add_subparsersでサブコマンドを追加できるようにしています。destで選ばれた名前を保存し、requiredをTrueにして指定を必須にしています。

LINE 032: genサブコマンドのコメント。ここからサンプル画像を生成するgenサブコマンドの引数を設定することを示すコメントです。LINE 033: genサブコマンドの追加。

add_parserでgenというサブコマンドを追加しています。helpにはサンプルPNG画像を生成するという説明を書いています。LINE 034: 生成先フォルダの引数。

genに--outオプションを追加し、指定がないときはsamplesフォルダへ生成するよう既定値を設定しています。LINE 035: 生成枚数の引数。--countオプションを追加しています。

type=intで整数として受け取り、既定では6枚を生成するようにしています。LINE 037: convertサブコマンドのコメント。ここから画像を一括変換するconvertサブコマンドの引数を設定することを示すコメントです。

LINE 038: convertサブコマンドの追加。add_parserでconvertというサブコマンドを追加し、helpにフォルダ内の画像を一括変換するという説明を添えています。LINE 039: 入力フォルダの引数。

srcという位置引数を追加しています。変換したい画像が入っている入力フォルダを、ここで受け取ります。LINE 040: 変換先フォーマットの引数。

--toオプションを追加しています。requiredをTrueにして指定を必須にし、choicesで対応表にあるフォーマットだけを選べるようにしています。LINE 041: 変換先引数のヘルプ。

前の行から続く--toの設定で、ヘルプに変換先フォーマットという説明を付けたうえでかっこを閉じています。LINE 042: 出力フォルダの引数。convertに--outオプションを追加し、指定がないときはconvertedフォルダへ変換結果を出力するよう既定値を設定しています。

LINE 043: リサイズ指定の引数を追加。convertサブコマンドに、任意で画像の大きさを変えるための--resizeオプションを追加します。「400x400」のように幅×高さの形式で受け取る想定で、指定がなければリサイズは行いません。

LINE 044: 画質オプションの追加。JPEGやWebPの画質を決める--qualityオプションを追加します。type=intで数値として受け取り、指定がないときはd

コードはおおまかに、引数の定義・サンプル生成・変換前の下ごしらえ・一括変換という4つの部品に分かれています。それぞれを関数として切り出し、build_parserが受け取った指示を各関数へ渡す形にしました。

対応する出力フォーマットは、辞書FORMATSで一元管理しています。ここに1行足すだけで対応形式を増やせるので、後からの拡張がとても楽です。

透過画像の扱いはprepare_imageにまとめました。JPEGだけは透過を残せないので、白背景へ合成してから変換する処理をこの関数に閉じ込めています。

このセクションの用語

add_subparsers
argparseで複数のサブコマンドを作るための仕組みです。genconvertごとに専用の引数を定義できます。
choices
add_argumentに付けられる制限で、引数に取れる値をあらかじめ列挙しておく指定です。範囲外の値が渡されると、処理に入る前にエラーで知らせてくれます。
アルファチャンネル
画像の透明度を表す情報のことです。JPEGはこれを保持できないため、透過部分の扱いには注意が必要になります。
convertサブコマンドのデータの流れ 入力フォルダの画像を読み込むJPEGなら白背景へ合成resize指定時はサイズ変更qualityを付けて保存
convertサブコマンドのデータの流れ
"""argparseで画像を一括変換するコマンドラインツール。

サブコマンド gen でお試し用のサンプルPNG画像を生成し、
convert でフォルダ内の画像をJPEG/PNG/WebPへまとめて変換する。
"""

import argparse
from pathlib import Path

from PIL import Image, ImageDraw


# 対応する出力フォーマットと拡張子の対応表
FORMATS = {
    "jpeg": ".jpg",
    "png": ".png",
    "webp": ".webp",
}

# 入力として読み込む画像の拡張子
SRC_SUFFIXES = {".png", ".jpg", ".jpeg", ".webp", ".bmp"}


# 引数パーサの定義
def build_parser():
    parser = argparse.ArgumentParser(
        prog="imgconv",
        description="フォルダ内の画像をまとめて別フォーマットへ変換するツール",
    )
    sub = parser.add_subparsers(dest="command", required=True)

    # サンプル画像を生成するサブコマンド
    gen = sub.add_parser("gen", help="お試し用のサンプルPNG画像を生成する")
    gen.add_argument("--out", default="samples", help="生成先フォルダ")
    gen.add_argument("--count", type=int, default=6, help="生成する画像の枚数")

    # 一括変換するサブコマンド
    conv = sub.add_parser("convert", help="フォルダ内の画像を一括変換する")
    conv.add_argument("src", help="入力フォルダ")
    conv.add_argument("--to", required=True, choices=sorted(FORMATS),
                      help="変換先フォーマット")
    conv.add_argument("--out", default="converted", help="出力フォルダ")
    conv.add_argument("--resize", help="WIDTHxHEIGHT でリサイズ (例: 400x400)")
    conv.add_argument("--quality", type=int, default=85,
                      help="JPEG/WebPの画質 (1-100)")
    return parser


# サンプル画像の生成
def generate_samples(out_dir, count):
    Path(out_dir).mkdir(parents=True, exist_ok=True)
    palette = [
        (231, 76, 60), (52, 152, 219), (46, 204, 113),
        (241, 196, 15), (155, 89, 182), (26, 188, 156),
    ]
    created = []
    for i in range(count):
        color = palette[i % len(palette)]
        img = Image.new("RGBA", (640, 480), color + (255,))
        draw = ImageDraw.Draw(img)
        draw.ellipse((180, 130, 460, 350), fill=(255, 255, 255, 255))
        draw.text((48, 36), f"sample {i + 1:02d}", fill=(0, 0, 0, 255))
        path = Path(out_dir) / f"sample_{i + 1:02d}.png"
        img.save(path)
        created.append(str(path))
    return created


# 変換前の下ごしらえ(透過の除去とリサイズ)
def prepare_image(img, fmt, resize):
    # JPEGは透過を扱えないため白背景へ合成してから変換する
    if fmt == "jpeg" and img.mode in ("RGBA", "LA", "P"):
        img = img.convert("RGBA")
        background = Image.new("RGB", img.size, (255, 255, 255))
        background.paste(img, mask=img.split()[-1])
        img = background
    else:
        img = img.convert("RGB")

    # サイズ変更(指定があるときだけ)
    if resize:
        img = img.resize(resize)
    return img


# 画像の一括変換
def convert_folder(src, dst, fmt, resize=None, quality=85):
    ext = FORMATS[fmt]
    Path(dst).mkdir(parents=True, exist_ok=True)
    src_files = sorted(
        p for p in Path(src).iterdir() if p.suffix.lower() in SRC_SUFFIXES
    )

    results = []
    for path in src_files:
        with Image.open(path) as img:
            out_img = prepare_image(img, fmt, resize)
            out_path = Path(dst) / (path.stem + ext)
            save_kwargs = {"quality": quality} if fmt in ("jpeg", "webp") else {}
            out_img.save(out_path, **save_kwargs)
        results.append((str(path), str(out_path)))
    return results


# サイズ指定文字列の解釈
def parse_size(text):
    width, height = text.lower().split("x")
    return int(width), int(height)


# メイン処理(サブコマンドの振り分けと結果メッセージの組み立て)
def main(argv=None):
    args = build_parser().parse_args(argv)

    if args.command == "gen":
        created = generate_samples(args.out, args.count)
        body = "\n".join(f"  生成: {p}" for p in created)
        return f"{len(created)}枚のサンプル画像を {args.out}/ に生成しました\n{body}"

    size = parse_size(args.resize) if args.resize else None
    results = convert_folder(args.src, args.out, args.to, size, args.quality)
    header = f"{len(results)}件を {args.to.upper()} へ変換しました (出力: {args.out}/)"
    if size:
        header += f" / サイズ {size[0]}x{size[1]}"
    body = "\n".join(f"  変換: {s} -> {d}" for s, d in results)
    return f"{header}\n{body}"


if __name__ == "__main__":
    print(main())

コード全文は上の折り畳みに入れてあるので、全部を上から読む必要はありません。ここでは特に重要な部分だけを抜き出して、何をしているのか順番に見ていきます。

対応フォーマットを辞書FORMATSで管理

FORMATS = {
    "jpeg": ".jpg",
    "png": ".png",
    "webp": ".webp",
}

変換先の名前と拡張子の対応を辞書にまとめています。jpegなら.jpgのように引けるので、出力ファイル名を組み立てるときに便利です。ここに1行足すだけで、対応フォーマットを増やせます。

add_subparsersでコマンドを分岐

    sub = parser.add_subparsers(dest="command", required=True)

add_subparsersgenconvertという2つのコマンドを作っています。dest="command"でどちらが選ばれたかを受け取り、required=Trueで指定漏れを防いでいます。

choicesで変換先フォーマットを限定

    conv.add_argument("--to", required=True, choices=sorted(FORMATS),
                      help="変換先フォーマット")

choices=sorted(FORMATS)は、--toに渡せる値を辞書のキーだけに絞る指定です。対応外の形式を打つとargparseが自動でエラーにしてくれるので、変換処理側で不正値を気にせず済みます。

Image.newとImageDrawでサンプル作成

        img = Image.new("RGBA", (640, 480), color + (255,))
        draw = ImageDraw.Draw(img)
        draw.ellipse((180, 130, 460, 350), fill=(255, 255, 255, 255))

Image.newで単色の下地を用意し、ImageDrawが白い楕円とサンプル文字を描き込みます。色を変えながら複数枚を作るため、素材が手元になくても変換をすぐ試せます。

白背景へ合成して透過を除去

    if fmt == "jpeg" and img.mode in ("RGBA", "LA", "P"):
        img = img.convert("RGBA")
        background = Image.new("RGB", img.size, (255, 255, 255))
        background.paste(img, mask=img.split()[-1])
        img = background

JPEGは透明部分を扱えないため、modeRGBAなどのときは白い背景画像を用意しています。pasteのマスクにアルファチャンネルを渡して合成することで、透過PNGでも黒くつぶれず変換できます。

resize指定時だけサイズを変更

    if resize:
        img = img.resize(resize)
    return img

resizeが指定されているときだけ、画像のサイズを変更します。何も指定しなければ元のサイズのまま保存されるので、必要なときだけ縮小や拡大を効かせられます。


Python基礎・実践(Django)

企業・法人向けのPython研修では、基礎から応用まで体系的に学べます。

Python研修の詳細

DX社員研修

企業・法人向けのDX研修では、実務に繋がるリスキリングでITレベルを向上させます。

DX研修の詳細

Javaエンジニア育成研修

企業・法人向けのJavaエンジニア育成研修では、Javaの基礎から応用まで確実に習得できます。

Java研修の詳細

新卒・新入社員向け研修

企業・法人に新入社員・新卒社員に向けたプログラミング研修を提供しています。

新入社員研修の詳細

コードキャンプのIT研修を全て見る

画像一括変換CLIの動作確認

できあがったツールを、実際に5回のコマンドで動かしてみました。サンプル生成から各フォーマットへの変換、リサイズ付きの変換まで一通り試しています。

結果はすべて終了コード0で、途中で止まることなく最後まで走り切りました。生成したサンプルや変換後の画像は、それぞれ指定した別フォルダへ出力されています。

このセクションの用語

終了コード
プログラムが終わるときに返す数字で、0は正常終了を示します。0以外なら、途中で問題が起きたサインだと考えてください。

今回実際に実行した5つのコマンドは次のとおりです。

  1. python subject.py gen --out samples --count 6 でサンプルPNGを6枚生成
  2. python subject.py convert samples --to jpeg --out jpg_out でJPEGへ一括変換
  3. python subject.py convert samples --to webp --out webp_out --quality 80 でWebPへ変換
  4. python subject.py convert samples --to jpeg --out thumb --resize 200x200 でリサイズ付きJPEG変換
  5. python subject.py convert samples --to png --out png_small --resize 320x240 でリサイズ付きPNG変換
python subject.py gen --out samples --count 6の実行結果(終了コード0)
python subject.py gen --out samples --count 6の実行結果(終了コード0)
python subject.py convert samples --to jpeg --out jpg_outの実行結果(終了コード0)
python subject.py convert samples --to jpeg --out jpg_outの実行結果(終了コード0)
python subject.py convert samples --to webp --out webp_out --quality 80の実行結果(終了コード0)
python subject.py convert samples --to webp --out webp_out --quality 80の実行結果(終了コード0)
python subject.py convert samples --to jpeg --out thumb --resize 200x200の実行結果(終了コード0)
python subject.py convert samples --to jpeg --out thumb --resize 200x200の実行結果(終了コード0)
python subject.py convert samples --to png --out png_small --resize 320x240の実行結果(終了コード0)
python subject.py convert samples --to png --out png_small --resize 320x240の実行結果(終了コード0)
さらに詳しく学べるPython研修の詳細はこちら

PythonのargparseとPillow利用時に起きやすいエラーと対処法

画像変換ツールを動かすとき、初心者がつまずきやすいのは実行前のエラーです。多くはインストール漏れや引数の指定ミスが原因で、メッセージを読めば対処できます。

とくにargparseは、必須の引数やchoicesの条件を満たさないと、処理に入る前にエラーで止めてくれます。エラー文には原因のヒントが含まれているので、まずはそこを確認するのがおすすめです。

このセクションの用語

ModuleNotFoundError
importしようとしたモジュールが見つからないときに出るエラーです。多くはライブラリの未インストールか、名前の綴り違いが原因になります。
pip
Pythonのパッケージを導入・管理するための標準的なコマンドです。pip installの形で必要なライブラリを追加できます。
エラー例 原因 対処
ModuleNotFoundError: No module named 'PIL' Pillowが未インストール pip install Pillowで導入する
the following arguments are required: command genかconvertを指定していない サブコマンドを先頭に付ける
argument --to: invalid choice: 'gif' choicesにない形式を指定 jpeg・png・webpから選ぶ
FileNotFoundError(入力フォルダがない) srcのパス指定が誤り 実在するフォルダを指定する
argument --quality: invalid int value 数値以外を--qualityへ渡した 1から100の整数を渡す

画像一括変換CLIで注意したい点

変換まわりで戸惑いやすいのが、リサイズと画質、そして透過の扱いです。--resize400x400のように幅x高さの形式で渡す約束になっています。

画質を決める--qualityはJPEGとWebPで効き、値は1から100の範囲で指定します。PNGには画質の概念がないため、--qualityを付けても仕上がりは変わらない点に注意してください。

とくにJPEGは透過を保持できません。透過PNGをそのまま保存しようとすると失敗するので、白背景へ合成してから変換する処理をprepare_imageにまとめました。

ポイントとしては、リサイズ・画質・透過の3点を意識しておくと、変換でつまずく場面をぐっと減らせます。

POINT

resize:幅x高さの形式で指定

quality:JPEGとWebPで有効

JPEG保存:透過は白背景へ合成

さらに詳しく学べるPython研修の詳細はこちら

Pythonの画像変換ツールが活きる場面

このツールは、日常の画像処理をまとめて片付けたい場面で役立ちます。手作業で1枚ずつ変換する手間を、1回のコマンドに置き換えられるからです。

とくにフォーマットをそろえたいときや、容量を抑えたいときに向いています。用途に合わせて--to--quality--resizeを組み合わせて使います。

このセクションの用語

サムネイル
一覧表示などで使う縮小版の画像のことです。元の画像を小さくして、表示を軽くする目的でよく使われます。
使える場面 具体的な使い方
ブログ画像の軽量化 convertでJPEGへ変換し、--qualityで容量を下げる
一覧用サムネイル作成 --resizeで同じサイズにそろえて縮小画像を作る
WebPへの移行 --to webpで既存のPNGやJPEGをまとめて置き換える
変換処理の動作確認 genでダミー画像を作り、convertの挙動を試す
さらに詳しく学べるPython研修の詳細はこちら

画像一括変換CLI開発のまとめ

argparseadd_subparsersPillowを組み合わせると、画像の一括変換ツールが無理なく作れます。サブコマンドで役割を分けたことで、機能を足すときも見通しが保てました。

実際に5回のコマンドで動かし、いずれも終了コード0で完走しました。まずはgenでサンプルを作り、convertの各オプションを試すところから始めると、動きがつかみやすいはずです。

さらに詳しく学べるPython研修の詳細はこちら

参考にした一次情報

  1. ^ argparse — コマンドライン引数の解析(Python公式ドキュメント). https://docs.python.org/ja/3/library/argparse.html, (参照26-07-20).
  2. ^ argparseサブコマンド(add_subparsers). https://docs.python.org/ja/3/library/argparse.html#sub-commands, (参照26-07-20).
  3. ^ Pillow (PIL Fork)ドキュメント. https://pillow.readthedocs.io/en/stable/, (参照26-07-20).
  4. ^ Pillow Imageモジュール(open/convert/resize/save). https://pillow.readthedocs.io/en/stable/reference/Image.html, (参照26-07-20).

※内容は執筆時点のものです。ライブラリやサイトの仕様は変わる可能性があるため、公式ドキュメントもあわせてご確認ください。

ITやプログラミングに関するコラム


ITやプログラミングに関するニュース

ブログに戻る

コメントを残す

コメントは公開前に承認される必要があることにご注意ください。

企業・法人向けのIT・プログラミング・生成AI研修を探す、比較する - IT・プログラミングを知って学べるコネクトメディア CodeCampが提供するDX人材育成が可能なプログラミングやITが学べる公開講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプが提供する無料で学べるプログラミングスクール講座 - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア 3.5日の研修で、年間1,600時間の削減効果が見込まれる。東京きらぼしフィナンシャルグループのDX人材育成事例 - IT・プログラミングを知って学べるコネクトメディア 配属3ヶ月で30%の生産性向上を実現するいよぎんコンピュータサービスの新人研修に迫る - IT・プログラミングを知って学べるコネクトメディア 金融業界の業務効率化を加速するニッセイアセットマネジメントの生成AI×GAS活用研修事例 - IT・プログラミングを知って学べるコネクトメディア 【製造業のDX人材育成事例】デジタル人材の即戦力化を実現する、日本ガイシ株式会社の異動者向オンボーディング研修 - ITやプログラミングを知って学べるコネクトメディア フューチャーアーキテクト株式会社が実現した新入社員向けIT研修プログラムでタスクフォース制度が主体的な学びと成長を生み出す - IT・プログラミングを知って学べるコネクトメディア コードキャンプDX人材育成研修 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【IT新入社員研修】オンラインとオフラインの最適バランスを実現したFutureOneの導入事例 - IT・プログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/【新入社員研修】柔軟なハイブリッド型Java研修で実現した新卒20名の成長と成果|サークレイス株式会社 - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/現場により近いところにデジタルを根付かせるDX基礎講座研修|株式会社ブリヂストン - ITやプログラミングを知って学べるコネクトメディア コードキャンプIT・プログラミング研修事例/業務の効率化・DX推進に向けたIT人材育成への第一歩|株式会社カナエ - ITやプログラミングを知って学べるコネクトメディア 企業・法人向けのIT・プログラミング研修 - ITやプログラミングを知って学べるコネクトメディア

新着記事

対象者別で探す

子供(小学生・中学生・高校生)向け
プログラミング教室検索する

子供(小学生・中学生・高校生)がロボットやプログラミング言語を学ぶことができるオフラインからオンラインスクールを検索、比較することが可能です。

子供(小学生・中学生・高校生)
プログラミング教室検索する

ITやプログラムなどの
最新情報を検索する

日々、新しいITやプログラミング言語の情報が流れていきますが、特定の情報を時系列でニュースやコラムを確認することができます。

ITやプログラムなどの
最新情報を検索する