はじめに
恐縮ですが前の記事からお読みください。
PillowでExif情報を遊ぶ ~辞書の復習を兼ねて~
piexifを使う
piexif
により、Exifの規格にのっとった非常に多くの情報を得ることができる。
公式
辞書の構造がPILと違っているので注意。
from PIL import Image, ExifTags
import piexif
from pprint import pprint
filename = "hoge.jpg"
img = Image.open(filename)
exif_dict = piexif.load(img.info["exif"])
pprint(exif_dict)
{'0th': {256: 3264,
257: 2448,
以下略},
'1st': {256: 512,
257: 384,
以下略},
'Exif': {33434: (1122000, 1000000000),
33437: (220, 100),
以下略},
'GPS': {0: (2, 2, 0, 0),
1: b'N',
2: ((35, 1), (25, 1), (21098327, 1000000)),
以下略},
以下略}
もちろんタグ番号でなくタグ名称で引っ張り出すこともできる。
以下は公式のサンプルコードを少しだけ改造したもの。
for ifd in ("0th", "Exif", "GPS", "1st"):
for tag in exif_dict[ifd]:
print(ifd, tag, piexif.TAGS[ifd][tag]["name"], exif_dict[ifd][tag])
0th 256 ImageWidth 3264
0th 257 ImageLength 2448
中略
Exif 33434 ExposureTime (1122000, 1000000000)
Exif 33437 FNumber (220, 100)
中略
GPS 0 GPSVersionID (2, 2, 0, 0)
GPS 1 GPSLatitudeRef b'N'
GPS 2 GPSLatitude ((35, 1), (25, 1), (21098327, 1000000))
後略
辞書を逆引きする
これまで人間にとって理解しやすいようタグ名称の辞書を使ったが、内容を変更する際はやはり元のタグ番号で指定する必要がある。
名称から番号に戻すにはキーと値を逆転させた辞書を作るかループを回して調べるかするしかない。
キーと値を逆転させた辞書は、前回挙げた内包表記で1行で書くことができる。
もちろん辞書の値が辞書だったりタプルだったりするとひっくり返してキーにすることはできないので気を付ける必要がある。
# 基本形
# dic_swap = {value: key for key, value in dic.items()}
dic_swap_0th = {piexif.TAGS["0th"][tag]["name"]: tag for tag in exif_dict["0th"].keys()}
dic_swap_gps = {piexif.TAGS["GPS"][tag]["name"]: tag for tag in exif_dict["GPS"].keys()}
print (dic_swap_0th["ImageWidth"])
print (dic_swap_gps["GPSLatitude"])
256 # dic_swap_0th["ImageWidth"]
2 # dic_swap_gps["GPSLatitude"]
とはいえ、piexif
はタグ名称が(辞書ではなく)クラス化されているので、実際のところ逆引きの辞書を作る必要はない。辞書の勉強として作っただけだ。
print (piexif.ImageIFD.ImageWidth)
print (piexif.GPSIFD.GPSLatitude)
256 # piexif.ImageIFD.ImageWidth
2 # piexif.GPSIFD.GPSLatitude
では実際に書き換えてみる。
from PIL import Image, ExifTags
import piexif
filename = "hoge.jpg"
img = Image.open(filename)
exif_dict = piexif.load(img.info["exif"])
exif_dict["0th"][piexif.ImageIFD.Make] = b"Appoooh"
exif_dict["0th"][piexif.ImageIFD.Model] = b"xPhone champion professional special edition"
exif_bytes = piexif.dump(exif_dict)
img.save("_" + filename, exif=exif_bytes)
このプログラムを実行後、あらためて前回のプログラム(完成形がなくて恐縮ですけど)でExif情報を確認すると、ちゃんとメーカーと機種名が更新されていた。HuaweiのANE-LX2J(P20 lite)からAppoooh社のxPhone champion professional special editionに。
{前略
'Make': 'HUAWEI',
'Model': 'ANE-LX2J',
後略}
{前略
'Make': 'Appoooh',
'Model': 'xPhone champion professional special edition',
後略}
応用
Exif情報を持たないCGにExif情報を書き込んでみよう。
辞書の指定の仕方が上のコードと違っているが、どちらでも可だ。
緯度経度は3つのRATIONALで指定しよう。Pillowではないので小数は不可だ。
import piexif
filename = "rapture.jpg"
exif_dict = {}
oth = {piexif.ImageIFD.Make: b"Fontaine Futuristics",
piexif.ImageIFD.Model: b"Research Camera"}
gps = {piexif.GPSIFD.GPSLatitudeRef: b"N",
piexif.GPSIFD.GPSLatitude: ((63, 1), (2, 1), (0, 1)),
piexif.GPSIFD.GPSLongitudeRef: b"W",
piexif.GPSIFD.GPSLongitude:((29, 1), (55, 1), (0, 1))}
exif_dict["0th"] = oth
exif_dict["GPS"] = gps
exif_bytes = piexif.dump(exif_dict)
piexif.insert(exif_bytes, filename) # insertでExif情報を挿入するにあたりPILは不要
これがExif情報が追加された写真(?)だ。
追加されたExif情報をテキストで見ても面白くないので、EXIF確認君の結果をお見せしよう。
すごいぞ! ラプチャーは本当に63°2'N, 29°55'Wにあったんだ!
この写真のExif情報を見てみろよ、ちゃんと緯度経度が記録されているだろ。え? カメラ? フォンテイン未来技術社のリサーチカメラですが何か?
…ということができてしまうので、一般論としてデジタル記録は証拠能力が低いとされているわけですね。
ギャラリー
- キングコングがエンパイアステートビルに登っている場面
- アサシンが世界的名所に立っている場面
- 実在する土地や施設が登場するアニメ画像(定義的に「聖地」の逆)
などにジオタグを付与することを思いついたが、以前の記事とは違い画像としては変化がなく面白みに欠けるのでやめた。
終わりに
緯度経度入りの写真をアップして家バレ、ということのないように、イマドキのSNSは写真からExif情報を削除しているらしい。これも時代か。