「うわっ…私のEXIF情報、漏れすぎ…?」
あなたのサイトは大丈夫ですか?
こんな状況になっていませんか?
あなただけなら、そこまで大事ではないかもしれません。
そう言っても、住所などの個人情報が漏れるのは避けたいところです。
しかし、あなたの作ったサイトでユーザーのEXIF情報が漏れていたら・・・
それは、かなりの問題になるでしょう。
サイト・サービスの信頼性という点では、大きなマイナスになります。
こんなときは、一気にEXIF情報を削除することを考えるでしょう。
でも、一体どうしたらいいのと迷う場合は、この記事をご覧ください。
安全確実に大量の画像から、EXIF情報を削除する方法を解説していきます。
本記事の内容
- 「指定フォルダ以下にある画像のEXIF情報を削除する」を機能定義する
- 【関数化】指定フォルダ以下の画像のパスを取得する
- 【関数化】画像からEXIF情報を削除する
- 【サンプルコード】指定フォルダ以下にある画像のEXIF情報を削除する
それでは、上記に沿って解説していきます。
「指定フォルダ以下にある画像のEXIF情報を削除する」を機能定義する
「指定フォルダ以下にある画像のEXIF情報を削除する」
今回は、この仕様を満たすプログラムを開発していきます。
この仕様は、大きく次の二つの機能に分けることができます。
- 指定フォルダ以下の画像のパスを取得する
- 画像からEXIF情報を削除する
また、指定フォルダ以下にはフォルダもある前提です。
つまり、サブフォルダがあることになります。
もちろん、サブフォルダにはフォルダも画像もあるという想定です。
なお、階層は何階層あるかはわかりません。
では、以下でこれらの機能を開発していきます。
まずは、「指定フォルダ以下の画像のパスを取得する」です。
【関数化】指定フォルダ以下の画像のパスを取得する
具体的には、WordPressを想定しましょう。
具体性がある方が、イメージしやすいです。
WordPressは、次のフォルダの下に画像などのファイルがアップロードされます。
/wp-content/uploads
直接上記フォルダにアップロードはされません。
通常は、uploadsの下に西暦(2020、2021など)でフォルダが作成されます。
さらに、その西暦フォルダの下に月(1、2,3・・・)でフォルダが作成されるのです。
その月フォルダの下に画像が、アップロードされることになります。
サムネイルなどのサイズ別画像も、この月フォルダに作成されます。
言葉による説明より、見た方が絶対に早いですね。
uploads
├── 2019
│ └── 12
├── 2020
│ ├── 01
│ ├── 02
│ ├── 03
│ ├── 04
│ ├── 05
│ ├── 06
│ ├── 07
│ ├── 08
│ ├── 09
│ ├── 10
│ ├── 11
│ └── 12
└── 2021
├── 01
├── 02
└── 03
上記のような構成のもとにある画像をすべて洗い出していきます。
それぞれのパスを取得すれば、後は何とでもなります。
ここまで見てきた内容をPythonの関数にしてみましょう。
関数化
関数のコードは以下。
from pathlib import Path
import re
def get_image_path_list(target):
# 結果用リスト初期化
result_list = []
# Pathクラス利用
path = Path(target)
# target以下のすべてのパス(フォルダ・ファイル含め)
all_path_list = path.glob('**/*')
# 拡張子が画像ファイルであれば画像パスと判定する
# 大文字(例えば、test.JPG)でも画像と判定する
for p in all_path_list:
hit = re.search('/*\.(jpg|jpeg|png|gif|bmp)', str(p), flags=re.IGNORECASE)
if hit:
result_list.append(p)
return result_list
引数targetには、フォルダのパスを設定します。
内容的には、コメントをしっかり残しています。
そちらを確認してください。
この関数を短くすると、次のようにコーディングできます。
def get_image_path_list_bk(target):
path = Path(target)
result_list = [p for p in path.glob('**/*') if re.search('/*\.(jpg|jpeg|png|gif|bmp)', str(p), flags=re.IGNORECASE)]
return result_list
個人的には、短く書くよりは可読性の高いコーディングが好きですね。
【関数化】画像からEXIF情報を削除する
EXIF情報を削除する方法は、何パターンかあります。
今回は、Pillowライブラリを利用した方法を説明します。
この方法が、最も確実にEXIF情報を削除できます。
削除というよりは、EXIF情報抜きで画像を新規に作り直します。
SQL文で言うとUPDATEではなく、DELETE + INSERTに近い考え方です。
よって、プログラムもこの考え方をベースにコーディングすることなります。
上記で出てきたPillow(PIL)に関しては、次の記事で説明しています。
もしまだインストールしていないなら、上記の記事を参考にしてください。
では、画像からEXIF情報を削除する機能を関数にしていきます。
関数化
関数のコードは以下。
from PIL import Image
def eraser_exif(file):
# 画像を開く
with Image.open(file) as src:
# 次の3つを取得
data = src.getdata()
mode = src.mode
size = src.size
# 上記で取得したデータをもとに新規で画像を作成=上書き
with Image.new(mode, size) as dst:
dst.putdata(data)
dst.save(file)
エラー処理も入れずに、少々強引なコードです。
エラー処理が必要な場合は、各自で入れてください。
引数fileは、画像のパスが設定されることを想定しています。
内容としては、上記で述べたようにPillowで画像を新規に作成しているだけです。
では、これにて必要な関数が用意できました。
最後に、これらの関数を利用したコードを見ていきましょう。
【サンプルコード】指定フォルダ以下にある画像のEXIF情報を削除する
上記で作成してきた関数を用いたサンプルコードは、以下。
from pathlib import Path
import re
from PIL import Image
TARGET_DIR = "uploadsのパス"
def get_image_path_list(target):
# 結果用リスト初期化
result_list = []
# Pathクラス利用
path = Path(target)
# target以下のすべてのパス(フォルダ・ファイル含め)
all_path_list = path.glob('**/*')
# 拡張子が画像ファイルであれば画像パスと判定する
# 大文字(例えば、test.JPG)でも画像と判定する
for p in all_path_list:
hit = re.search('/*\.(jpg|jpeg|png|gif|bmp)', str(p), flags=re.IGNORECASE)
if hit:
result_list.append(p)
return result_list
def eraser_exif(file):
# 画像を開く
with Image.open(file) as src:
# 次の3つを取得
data = src.getdata()
mode = src.mode
size = src.size
# 上記で取得したデータをもとに新規で画像を作成=上書き
with Image.new(mode, size) as dst:
dst.putdata(data)
dst.save(file)
image_path_list = get_image_path_list(TARGET_DIR)
for image_path in image_path_list:
eraser_exif(image_path)
関数に関しては、説明は不要ですね。
定数に関して、一応説明をしておきます。
TARGET_DIR = "uploadsのパス"
ここは、基本的には絶対パスを入れましょう。
OS別に設定するなら、次のような値になります。
| Windows | D:\\wordpress\\uploads |
| Linux | /var/www/wp/uploads |
あとは、以下のコード部分に関する補足です。
for image_path in image_path_list:
eraser_exif(image_path)
もちろん、ファイルの存在チェックがあればベターです。
例外処理も同じく。
このあたりは、各自で自由に入れてください。
さらには、画像毎にEXIF有無のチェックもすればよいでしょう。
その場合は、以下の記事で紹介したExifReadを使えます。
ExifReadを使えば、画像のEXIF情報を抽出できます。



