経緯
Webサイトを制作していく過程で画像の圧縮、webp画像を作る際に
- gulpで環境を作成して実行
- Googleの変換ツールを使用してwebp画像を生成
という手順で作業を行った。
小規模なサイトならいいのですが、大規模なサイトや環境を組んでも共有できない事情があるなどを考えツールを作成してみた。
開発環境
- Windows10
- Python 3.9.5
目標
- 複数のJPG, PNG画像を圧縮してくれる
- 複数のJPG, PNG画像からWebp画像を生成してくれる
- エンジニア以外の環境構築ができない人でも作業を行うことができる
3を考えたときにWebブラウザで動作するかGUIを作ってアプリケーションとするか悩ましいが
今回はPythonを勉強中ということもあり、デスクトップで使用できるアプリケーションを作成する。
完成品
/dist/image_controller.exe
に完成品が入っている
- パスに圧縮・変換する画像が格納されているディレクトリを指定する
- webp画像に変換したい場合はチェックボックスにチェックをいれる
使用するライブラリ
-
Pillow
- リサイズや圧縮など画像の処理を行う
-
PySimpleGUI
- 簡単にGUIを実装する
- glob
- Pythonインストール時にデフォルトでインストールされる
- os
- Pythonインストール時にデフォルトでインストールされる
事前準備
$ pip install Pillow
$ pip install pysimplegui
実装
必要なライブラリを読み込む
# 画像圧縮のライブラリをImportする
from PIL import Image, ImageFilter
# ファイルを取得するためのライブラリをImportする
import glob
import os
#GUI生成するライブラリをImportする
import PySimpleGUI as sg
画像の圧縮をするソース
# 圧縮のクオリティ
quality = 70
# 画像が格納されているディレクトリを指定する
path = 'path/to/dir'
files = glob.glob(path + '/*')
# ディレクトリ内の画像をループで処理する
for file in files :
# 画像の情報を取得
image = Image.open(file)
# 画像を圧縮してセーブする
image.save(path + '/' + os.path.split(file)[1], optimize=True, quality=quality)
JPG, PNGをwebp画像として保存する
# 画像が格納されているディレクトリを指定する
path = 'path/to/dir'
files = glob.glob(path + '/*')
# ディレクトリ内の画像をループで処理する
for file in files :
image.save(path + '/' + os.path.split(file)[1].split('.')[0] + '.webp', 'webp')
これで圧縮、webp画像の生成ができる
GUIを実装する
# GUIのテーマを選択する
sg.theme('Reddit')
# GUIに必要な要素を配列で格納する
layout = [
[sg.Text(' パス'), sg.InputText(key='path', size=(40,8))],
[sg.Text('webp画像を生成する'), sg.Checkbox('',key='is_webp', default=False)],
[sg.Text('実行結果'),sg.MLine(key='output'+sg.WRITE_ONLY_KEY, size=(40,8))],
[sg.Button('実行')]
]
# Windowを生成する
window = sg.Window(title='Image controller', layout=layout)
# Window内の処理を記載する
while True:
event, values = window.read()
# Windowが閉じられたときの処理
if event == sg.WINDOW_CLOSED or event == 'Quit':
break
# ここに実行をクリックしたときの処理を記載する
# syori();
GUIの実装を行っただけでPythonファイルを実行すると完成品のような見た目のGUIができる
組み合わせて一つのPythonファイルにする
# ------------------------------ Settings ------------------------------ #
# 画像圧縮のライブラリ
from PIL import Image, ImageFilter
# ファイルを取得するためのライブラリ
import glob
import os
#GUI
import PySimpleGUI as sg
# ------------------------------ Config ------------------------------ #
# 圧縮のクオリティ
quality = 70
# GUI
sg.theme('Reddit')
layout = [
[sg.Text(' パス'), sg.InputText(key='path', size=(40,8))],
[sg.Text('webp画像を生成する'), sg.Checkbox('',key='is_webp', default=False)],
[sg.Text('実行結果'),sg.MLine(key='output'+sg.WRITE_ONLY_KEY, size=(40,8))],
[sg.Button('実行')]
]
window = sg.Window(title='Image controller', layout=layout)
# テーマの確認
# sg.preview_all_look_and_feel_themes()
# ------------------------------ 画像圧縮の処理 ------------------------------ #
def compression(file) :
# 画像の情報を取得
# フォーマット image.format
# サイズ image.size
# カラーモード image.mode
image = Image.open(file)
# 画像を圧縮してセーブする (values['path']でGUIで入力したパスが取得できる)
image.save(values['path'] + '/' + os.path.split(file)[1],optimize=True,quality=quality)
# メッセージをGUIに表示する
window['output'+sg.WRITE_ONLY_KEY].print(os.path.split(file)[1] + ' is compressed.')
def initalizeWebp(file) :
image = Image.open(file)
# webpに変換してセーブする (values['path']でGUIで入力したパスが取得できる)
image.save(values['path'] + '/' + os.path.split(file)[1].split('.')[0] + '.webp', 'webp')
# メッセージをGUIに表示する
window['output'+sg.WRITE_ONLY_KEY].print(os.path.split(file)[1] + ' is initalize webp image.')
# ------------------------------ GUIの処理 ------------------------------ #
# Windowの処理
while True:
event, values = window.read()
# See if user wants to quit or window was closed
if event == sg.WINDOW_CLOSED or event == 'Quit':
break
files = glob.glob(values['path'] + '/*')
for file in files :
compression(file)
# チェックボックスがチェックされていたら実行
if (values['is_webp'] == True) :
initalizeWebp(file)
参考サイト
https://note.com/kohaku935/n/n721e5e620839
https://qiita.com/dario_okazaki/items/656de21cab5c81cabe59
PySimpleGUIは公式のドキュメントがわかりやすく書いてあるので参考になります。
https://pysimplegui.readthedocs.io/en/latest/
補足
Pythonファイルのexe化は以下のツールを使用しています。
- pyinstaller
以下サイトを参考にしています。
https://techacademy.jp/magazine/18963
結構導入~実行まで簡単だったのでおすすめです。