画像を1枚ずつ変換していくのは、地味に手間がかかります。そこでPythonのargparseを使い、フォルダ内の画像をまとめてJPEG・PNG・WebPへ変換するコマンドラインツールを作ってみました。サンプル生成用のgenと一括変換用のconvertという2つのサブコマンドに分け、Pillowが実際の変換を担当します。
この記事では、コードの要点から実際に動かした結果、初心者がつまずきやすいところまでを順に解説していきます。
argparseの基本概念、要件定義、実装、動作確認までを順番に学べる構成です。動画は目次から確認したい場面へ移動でき、本文だけでも手順と考え方が完結します。
動画の内容をテキストで確認する
オープニング。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・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でサンプルを生成してから変換コマンドを実行してください。
画像一括変換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に任せる
- 対応外の拡張子は入力から自動で除外する
- 出力フォルダが無ければ実行時に作成する
- サブコマンドの指定漏れはエラーで知らせる
完成と判断する条件
- genで--countに応じた枚数の画像が生成される
- convertで対象画像がすべて指定形式へ変換される
- 透過PNGをJPEGへ変換すると背景が白で保存される
- --resize指定時に出力画像が指定サイズになる
- 対象外の拡張子のファイルは変換されない
- 変換件数と出力先がメッセージに表示される
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で画像一括変換CLIの完成コード
動画の内容をテキストで確認する
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で複数のサブコマンドを作るための仕組みです。genやconvertごとに専用の引数を定義できます。 - choices
-
add_argumentに付けられる制限で、引数に取れる値をあらかじめ列挙しておく指定です。範囲外の値が渡されると、処理に入る前にエラーで知らせてくれます。 - アルファチャンネル
- 画像の透明度を表す情報のことです。JPEGはこれを保持できないため、透過部分の扱いには注意が必要になります。
"""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_subparsersでgenとconvertという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 = backgroundJPEGは透明部分を扱えないため、modeがRGBAなどのときは白い背景画像を用意しています。pasteのマスクにアルファチャンネルを渡して合成することで、透過PNGでも黒くつぶれず変換できます。
resize指定時だけサイズを変更
if resize:
img = img.resize(resize)
return imgresizeが指定されているときだけ、画像のサイズを変更します。何も指定しなければ元のサイズのまま保存されるので、必要なときだけ縮小や拡大を効かせられます。
画像一括変換CLIの動作確認
できあがったツールを、実際に5回のコマンドで動かしてみました。サンプル生成から各フォーマットへの変換、リサイズ付きの変換まで一通り試しています。
結果はすべて終了コード0で、途中で止まることなく最後まで走り切りました。生成したサンプルや変換後の画像は、それぞれ指定した別フォルダへ出力されています。
このセクションの用語
- 終了コード
- プログラムが終わるときに返す数字で、0は正常終了を示します。0以外なら、途中で問題が起きたサインだと考えてください。
今回実際に実行した5つのコマンドは次のとおりです。
-
python subject.py gen --out samples --count 6でサンプルPNGを6枚生成 -
python subject.py convert samples --to jpeg --out jpg_outでJPEGへ一括変換 -
python subject.py convert samples --to webp --out webp_out --quality 80でWebPへ変換 -
python subject.py convert samples --to jpeg --out thumb --resize 200x200でリサイズ付きJPEG変換 -
python subject.py convert samples --to png --out png_small --resize 320x240でリサイズ付きPNG変換





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で注意したい点
変換まわりで戸惑いやすいのが、リサイズと画質、そして透過の扱いです。--resizeは400x400のように幅x高さの形式で渡す約束になっています。
画質を決める--qualityはJPEGとWebPで効き、値は1から100の範囲で指定します。PNGには画質の概念がないため、--qualityを付けても仕上がりは変わらない点に注意してください。
とくにJPEGは透過を保持できません。透過PNGをそのまま保存しようとすると失敗するので、白背景へ合成してから変換する処理をprepare_imageにまとめました。
ポイントとしては、リサイズ・画質・透過の3点を意識しておくと、変換でつまずく場面をぐっと減らせます。
resize:幅x高さの形式で指定
quality:JPEGとWebPで有効
JPEG保存:透過は白背景へ合成
Pythonの画像変換ツールが活きる場面
このツールは、日常の画像処理をまとめて片付けたい場面で役立ちます。手作業で1枚ずつ変換する手間を、1回のコマンドに置き換えられるからです。
とくにフォーマットをそろえたいときや、容量を抑えたいときに向いています。用途に合わせて--toや--quality、--resizeを組み合わせて使います。
このセクションの用語
- サムネイル
- 一覧表示などで使う縮小版の画像のことです。元の画像を小さくして、表示を軽くする目的でよく使われます。
| 使える場面 | 具体的な使い方 |
|---|---|
| ブログ画像の軽量化 | convertでJPEGへ変換し、--qualityで容量を下げる |
| 一覧用サムネイル作成 | --resizeで同じサイズにそろえて縮小画像を作る |
| WebPへの移行 | --to webpで既存のPNGやJPEGをまとめて置き換える |
| 変換処理の動作確認 | genでダミー画像を作り、convertの挙動を試す |
画像一括変換CLI開発のまとめ
argparseのadd_subparsersとPillowを組み合わせると、画像の一括変換ツールが無理なく作れます。サブコマンドで役割を分けたことで、機能を足すときも見通しが保てました。
実際に5回のコマンドで動かし、いずれも終了コード0で完走しました。まずはgenでサンプルを作り、convertの各オプションを試すところから始めると、動きがつかみやすいはずです。
参考にした一次情報
- ^ argparse — コマンドライン引数の解析(Python公式ドキュメント). https://docs.python.org/ja/3/library/argparse.html, (参照26-07-20).
- ^ argparseサブコマンド(add_subparsers). https://docs.python.org/ja/3/library/argparse.html#sub-commands, (参照26-07-20).
- ^ Pillow (PIL Fork)ドキュメント. https://pillow.readthedocs.io/en/stable/, (参照26-07-20).
- ^ Pillow Imageモジュール(open/convert/resize/save). https://pillow.readthedocs.io/en/stable/reference/Image.html, (参照26-07-20).
※内容は執筆時点のものです。ライブラリやサイトの仕様は変わる可能性があるため、公式ドキュメントもあわせてご確認ください。
ITやプログラミングに関するコラム
【CSS】notで複数の件を除外する方法
【Git】remote設定を変更する方法
【VBA】コメントアウトを設定する方法
x86とx64の違いを分かりやすく解説
マークダウンで改行する方法
CapsLockキーを解除する方法
GitLabとGitHubの違いを解説
Linuxで環境変数を確認する方法
UbuntuのIPアドレスを確認する方法
パソコンのメモリの目安を用途別に選ぶ方法
ITやプログラミングに関するニュース
VercelがAI GatewayにSeedream 5.0 Proを追加、AI SDKのモデル指定で画像生成と編集が可能に
AWSがAmazon LocationのPlaces APIを強化、住所表記の指定と移動手段別の検索が可能に
VercelがトレースにTree・Waterfallビューを追加、ログ画面で処理の階層と所要時間を確認可能に
Googleがエージェント評価の再考を提唱、難易度を情報量で測るDiscovery Benchを解説
Google CloudがCloud Runサンドボックスを公開プレビューで提供、サービスヘルスは一般提供に
Google Cloud EMEAが英国金融の重要第三者に指定、イングランド銀行・PRA・FCAの直接監督下に
AWS DMS Schema ConversionがSQL Serverのオフライン変換に対応、ソースDBへ接続せずスキーマを変換可能に
EC2 G7インスタンスが米国東部(バージニア北部)で利用可能に、G6比でAI推論性能が最大4.6倍
SageMaker HyperPodが継続プロビジョニングでのAMIベース構成に対応、S3のスクリプト管理なしでSlurmクラスターを作成可能に
AWSがEMR on EKSでSparkトラブルシューティングエージェントに対応、失敗ジョブの原因分析を自然言語で依頼可能に
