前回紹介したQt for PythonのQTreeWidgetを使って簡単なExifViewerを作ってみる。
コード全体(60行くらい)は最後に記載。
目次
全体構成
構成は下記図のような感じ。
入力はJPEGファイルのみ対応。
ExifViewer完成画面
今回作るExifViewerの画面。
GUIはQt for Pythonで作る。
以下コードの簡単な説明をしていく。
処理手順
1.JPEGからExifを取得する
まずPILを使ってJPEGの中にあるExif情報を取り出す。
PILはpip install pillow
でインストールできる。
Exif情報は_getexif()を使うとExif情報が辞書形式で取得できる。
from PIL import Image exif = Image.open(img_path)._getexif()
exif変数は辞書になっていて、{tag_id: value}
の形式になっている。exifはどんな情報なのかを識別するためのtag_idがあらかじめ用意されている。tag_idは16バイトの数字で定義されている。
viewerで表示するときはtag_idだと何の情報なのかよくわからないので、人間が分かるtag_nameに変換する。
これはfrom PIL.ExifTags import TAGS, GPSTAGS
を使うと簡単に変換できる。
下記コードはtag_idとtag_nameとtagの値を出力するコード。
from PIL.ExifTags import TAGS, GPSTAGS for tag_id, value in exif.items(): tag_name = TAGS[tag_id] print(tag_id, tag_name, value)
これを実行すると以下のような出力が得られる。
36864 ExifVersion b'0220' 37121 ComponentsConfiguration b'\x01\x02\x03\x00' 40960 FlashPixVersion b'0100' 36867 DateTimeOriginal 2008:10:22 16:28:39 36868 DateTimeDigitized 2008:10:22 16:28:39 ・ ・ 34853 GPSInfo {1: 'N', 2: ((43, 1), (28, 1), .... ・ ・
GPSTAGS
はExif情報の中にあるGPS情報に対して使う。GPS情報はtag_nameがGPSInfo
の中にある。GPSInfo
は{tag_id: value}
という形式の値を持っているので、同じようにGPSTAGS[tag_id]
とすればtag_nameが取り出せる。
今回はExif情報とGPS情報を親ツリーとして表示したいので、まずはExif情報からGPS情報だけを取り出す関数をつくる。こうしておくことで後々のコードをわかりやすく書ける。
def extract_gps_info(exif): for exif_id, exif_value in exif.items(): exif_tag = TAGS.get(exif_id, str(exif_id)) if exif_tag == 'GPSInfo': del exif[exif_id] # Exif情報からGPS情報を削除する. return exif_value # GPS情報をリターンする. return None exif = Image.open(img_path)._getexif() gps = extract_gps_info(exif)
2.Exif情報を使ってTreeを生成する
{tag_id: value}
形式のExif情報とGPS情報が取得できたので、次にこの情報を使ってTreeを作成する。
Treeの生成はQTreeWidget()
とQTreeWidgetItem
を使う。
今回はcreate_top_level_item
という関数を作って、Exif情報のツリーとGPS情報のツリーを生成する。
この関数でリターンしたQTreeWidgetItem
をQTreeWidget.addTopLevelItem()
の引数にすることでTreeに登録している。
def create_top_level_item(top_name, id_val, id_to_name): top_level_item = QTreeWidgetItem([top_name]) # 親ツリーアイテム生成 for tag_id, val in id_val.items(): tag_name = id_to_name.get(tag_id, str(tag_id)) child_item = QTreeWidgetItem([tag_name, str(val)]) # 子ツリーアイテム生成 top_level_item.addChild(child_item) # 親に子を追加 return top_level_item qw_tree = QTreeWidget() qw_tree.resize(500, 500) qw_tree.setAlternatingRowColors(True) qw_tree.setHeaderLabels(["name", "val"]) # Exif情報のツリーをつくる. top_level_item = create_top_level_item('exif', exif, TAGS) qw_tree.addTopLevelItem(top_level_item) # GPS情報のツリーをつくる. if gps is not None: top_level_item = create_top_level_item('gps', gps, GPSTAGS) qw_tree.addTopLevelItem(top_level_item)
全体コード
import sys from PySide2.QtWidgets import QApplication, QTreeWidget, QTreeWidgetItem from PIL import Image from PIL.ExifTags import TAGS, GPSTAGS def extract_gps_info(exif): for exif_id, exif_value in exif.items(): exif_tag = TAGS.get(exif_id, str(exif_id)) if exif_tag == 'GPSInfo': del exif[exif_id] # Exif情報からGPS情報を削除する. return exif_value # GPS情報をリターンする. return None def create_top_level_item(top_name, id_val, id_to_name): top_level_item = QTreeWidgetItem([top_name]) # 親ツリーアイテム生成 for tag_id, val in id_val.items(): tag_name = id_to_name.get(tag_id, str(tag_id)) child_item = QTreeWidgetItem([tag_name, str(val)]) # 子ツリーアイテム生成 top_level_item.addChild(child_item) # 親に子を追加 return top_level_item def main(img_path): app = QApplication([]) exif = Image.open(img_path)._getexif() # for tag_id, value in exif.items(): # print(tag_id, TAGS[tag_id], value) gps = extract_gps_info(exif) qw_tree = QTreeWidget() qw_tree.resize(500, 500) qw_tree.setAlternatingRowColors(True) qw_tree.setHeaderLabels(["name", "val"]) # Exif情報のツリーをつくる. top_level_item = create_top_level_item('exif', exif, TAGS) qw_tree.addTopLevelItem(top_level_item) # GPS情報のツリーをつくる. if gps is not None: top_level_item = create_top_level_item('gps', gps, GPSTAGS) qw_tree.addTopLevelItem(top_level_item) # qw_tree.expandAll() qw_tree.show() sys.exit(app.exec_()) if __name__ == "__main__": if len(sys.argv) != 2: sys.exit() img_path = sys.argv[1] main(img_path)