
仕事で記事書いてて、ワードプレスに画像貼るときに、
”圧縮して”って言われるんだけど、
わざわざWebアプリ開くのが、面倒やし、複数選択したら、Zipフォルダに
なってダウンロードされてくるから、解凍しなきゃやし、面倒なんだけど!

それなら、圧縮ソフト作ればえぇんちゃう?
わいが、コード出したるから、VBCodeとかでサクッと作ってしまえば
楽やで?exeとかも希望なら出せるしなぁ。
ということで、作り方を聞きながら、チャッピーと一緒に、画像圧縮ソフト作りました!
とりあえず欲しい機能を追加→追加→追加で、わりと機能が充実してると思う、圧縮ソフトです(笑)
🏁 機能一覧
✅ 複数画像選択(ドラッグ&ブラウズ)
✅ フォルダ一括圧縮対応
✅ 保存形式:JPG / PNG / WEBP
✅ 圧縮品質と縮小比率の調整
✅ 保存先が未指定ならポップアップで警告
✅ 保存成功時はログに出力パス表示
✅ 拡張子自動変換でトラブル回避
✅ フォルダ自動作成で安定保存
見た目は以下のような感じ↓

最初は、フォルダを一括で、変換するのを作ったんだけど、どっちかというと、1個づつ圧縮するほうが多い気がしたので、1個ずつの機能も追加。
ドラックでファイルを選択しても、ちゃんとそのファイルを圧縮してくれるようにしました。
一番楽なのは、圧縮の待ち時間が短い‼
Webアプリと比べると、サクッと圧縮してくれる感があります。
仕事で記事を書くときに、これなら、さっくりを圧縮できるし、自分で作ったので、使いつつニヤニヤできるのが良い‼
※以下のような不審なダウンロードをブロックしましたと出るかもしれません。
これは自作の安全なツールですので、不審なファイルをダウンロードでダウンロードできます。
不安な場合は、コードも記載してるので、そちらを使って自作していただくのもありだと思います。

コードは以下の通りなので、作ってみたい人はコピペすれば、圧縮ソフト作れます!
import os
from PIL import Image
import PySimpleGUI as sg
valid_extensions = [".jpg", ".jpeg", ".png", ".webp"]
ext_map = {"JPEG": "jpg", "PNG": "png", "WEBP": "webp"}
def compress_image(input_path, output_path, quality, resize_ratio, output_format):
try:
before_size = os.path.getsize(input_path)
img = Image.open(input_path)
if img.mode in ("RGBA", "P"):
img = img.convert("RGBA" if output_format == "PNG" else "RGB")
else:
img = img.convert("RGB")
if resize_ratio < 1.0:
new_size = tuple([int(dim * resize_ratio) for dim in img.size])
img = img.resize(new_size, Image.LANCZOS)
save_kwargs = {"optimize": True}
if output_format in ["JPEG", "WEBP"]:
save_kwargs["quality"] = quality
os.makedirs(os.path.dirname(output_path), exist_ok=True)
print(f"💾 保存先: {output_path}")
img.save(output_path, output_format, **save_kwargs)
after_size = os.path.getsize(output_path)
saved_percent = (1 - after_size / before_size) * 100
return f"✅ {os.path.basename(input_path)}: {before_size//1024}KB → {after_size//1024}KB(-{saved_percent:.1f}%)"
except Exception as e:
return f"❌ 失敗: {os.path.basename(input_path)} - {e}"
def compress_images_in_folder(input_folder, output_folder, quality, resize_ratio, output_format):
os.makedirs(output_folder, exist_ok=True)
results = []
for filename in os.listdir(input_folder):
name, ext = os.path.splitext(filename)
ext_lower = ext.lower()
if ext_lower in valid_extensions:
input_path = os.path.join(input_folder, filename)
file_ext = ext_map[output_format]
output_path = os.path.join(output_folder, f"{name}.{file_ext}")
results.append(compress_image(input_path, output_path, quality, resize_ratio, output_format))
return results
layout = [
[sg.Text("🧭 モード選択:"),
sg.Radio("画像を複数選ぶ / D&D対応", "MODE", key="-MODE_FILE-", default=True),
sg.Radio("フォルダを一括変換", "MODE", key="-MODE_FOLDER-")],
[sg.Text("🖼 画像ファイル")],
[sg.Input(key="-FILE-", size=(60, 1)),
sg.FilesBrowse("画像を選ぶ", key="-BROWSE-", target="-FILE-", file_types=(("画像", "*.jpg;*.jpeg;*.png;*.webp"),))],
[sg.Text("📂 入力フォルダ"), sg.Input(key="-INPUT-"), sg.FolderBrowse()],
[sg.Text("💾 出力フォルダ"), sg.Input(key="-OUTPUT-"), sg.FolderBrowse()],
[sg.Text("🔧 圧縮品質"), sg.Slider(range=(10, 100), orientation="h", default_value=75, key="-QUALITY-")],
[sg.Text("📐 サイズ縮小比率 (%)"), sg.Slider(range=(10, 100), orientation="h", default_value=100, key="-RESIZE-")],
[sg.Text("🗂 保存形式:"),
sg.Radio("JPG", "FORMAT", default=True, key="-FMT_JPG-"),
sg.Radio("PNG", "FORMAT", key="-FMT_PNG-"),
sg.Radio("WEBP", "FORMAT", key="-FMT_WEBP-")],
[sg.Button("圧縮開始", key="-START-"), sg.Button("終了")],
[sg.Output(size=(80, 15))]
]
window = sg.Window("画像圧縮ツール(Final Edition)", layout)
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, "終了"):
break
if event == "-START-":
quality = int(values["-QUALITY-"])
resize_ratio = float(values["-RESIZE-"]) / 100.0
output_format = "JPEG" if values["-FMT_JPG-"] else "PNG" if values["-FMT_PNG-"] else "WEBP"
file_ext = ext_map[output_format]
out_dir = values["-OUTPUT-"]
if not out_dir:
sg.popup("💡出力フォルダを選択してください", title="出力先が未指定です")
continue
if not os.path.isdir(out_dir):
os.makedirs(out_dir, exist_ok=True)
print("\n▶ 圧縮開始...\n")
if values["-MODE_FILE-"]:
files = values["-FILE-"].split(";")
for file_path in files:
file_path = file_path.strip().strip("\"")
if not os.path.isfile(file_path):
continue
name, _ = os.path.splitext(os.path.basename(file_path))
out_path = os.path.join(out_dir, f"{name}.{file_ext}")
print(compress_image(file_path, out_path, quality, resize_ratio, output_format))
else:
folder_path = values["-INPUT-"]
if not os.path.isdir(folder_path):
sg.popup("❗ 入力フォルダが正しくありません", title="エラー")
continue
results = compress_images_in_folder(folder_path, out_dir, quality, resize_ratio, output_format)
for res in results:
print(res)
print("\n✅ 圧縮完了!\n")
window.close()

コメント