主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

Piexif: Python Exif Library

                
tags: python
 PythonでExifをいじるライブラリを書いていて、ドキュメントも作ってだいぶ体裁が整ってきた。PyPIでの区分をalphaからstableに一気に移行し、バージョンも1.0へ引き上げた。
 GoogleAppEngineで写真のアップローダを作るときにExifの扱いで不便を感じ、そのあとでも何度かPythonでExifを扱うことに不便を感じたので自分でPiexifというライブラリを書いてみた。その結果、Stackoverflowにある質問に対してもスマートな解法を提供できるライブラリができたので紹介がてらそのあたりを書いてみる。
https://github.com/hMatoba/Piexif

 まず基本的な部分について
- Pythonの2系と3系の両方で動作(2.7, 3.3, 3.4への対応)
- ドキュメント完備
- Travis CIでビルドテスト結果が確認可能
- ピュアPythonなのでどこへでも容易に移植



・Exifを消す:http://stackoverflow.com/questions/19786301/python-remove-exif-info-from-images
 JPEGのExifを消したいという要望がある。最近でははてなフォトライフというサービスで、アップロードした写真のExifを消すかどうかの設定ができるようになったとかなってないとか。
 PythonでExifを消したければPILを使って画像データだけを使って新しくファイルを作るとか、Gexiv2を使うという解法がある。PILでのやり方はテクニックを駆使していて、シンプルな解法ではない。Gexiv2ならStackoverflowでわかりやすいやり方が紹介されているが、このライブラリのドキュメントは行方不明。
 Piexifでは下記のように。シンプル。
piexif.remove("foo.jpg")



・PIL(Pillow)での編集によってExifが欠落するのを防ぐ:http://stackoverflow.com/questions/400788/resize-image-in-python-without-losing-exif-data
 PILではイメージを保存するとき、ただ保存するだけだとExifが欠落する。Exifを欠落させないやり方も実はあるが、Exifの編集ができず前のイメージそのままで引き継ぐので実画像データと解像度などで矛盾が出るだろう。JPEGにExifを埋め込むライブラリはいくつかあるみたいだがPILとは連携しないようだ。それらを使うと編集した画像を保存→Exifを埋め込んで保存というように保存が二度になっていて非合理。
 PiexifはPILと連携もできるので、保存を二度するという非合理はない。
from PIL import Image
import piexif

im = Image.open(filename)
exif_dict = piexif.load(im.info["exif"])
# process im and exif_dict...
w, h = im.size
exif_dict["0th"][piexif.ImageIFD.XResolution] = (w, 1)
exif_dict["0th"][piexif.ImageIFD.YResolution] = (h, 1)
exif_bytes = piexif.dump(exif_dict)
im.save(new_file, "jpeg", exif=exif_bytes)


 PILでの画像編集とExifの扱いという内容において、「Exifのオリエンテーションタグで指定されている方向を画像に反映したい」という要望もある。これの解法を探すといくつか出てくるが、方向を反映させた画像からExifが抜け落ちていたり、PILと連携できず画像を二度保存する非合理な方法だったり。
 Piexifでの解法。
from PIL import Image
import piexif

def rotate_jpeg(filename):
img = Image.open(filename)
if "exif" in img.info:
exif_dict = piexif.load(img.info["exif"])

if piexif.ImageIFD.Orientation in exif_dict["0th"]:
orientation = exif_dict["0th"].pop(piexif.ImageIFD.Orientation)
exif_bytes = piexif.dump(exif_dict)

if orientation == 2:
img = img.transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 3:
img = img.rotate(180)
elif orientation == 4:
img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 5:
img = img.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 6:
img = img.rotate(-90)
elif orientation == 7:
img = img.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation == 8:
img = img.rotate(90)

img.save(filename, exif=exif_bytes)



 PiexifはPythonでExifをいじるライブラリとしてまだ新しいものなのでユーザは少ない。だがPixabayというサービスの中の人から、pyexiv2をやめてpiexifを採用すると報告が来た。pyexiv2はPythonのExifライブラリとして著名だし標準のような位置にいる。おそらくpyexiv2の使用においてどこかで不便を感じていたんだろう。たとえばちょっと古くてPythonの3系への対応計画が立っていなかったりする。
 そんなわけでExifをいじりたくなったらPiexifの使用をご一考。
            

コメントの投稿

非公開コメント

ありがとうございます

Python3対応ということで、pyxifの頃から利用しています(パッケージ名変更、戻り値変更にビビりました…)。
使いやすいライブラリなので助かります。

Re: ありがとうございます

パッケージ名変更はPyPI上でExifで検索をかけたときに出てくるのが下の方だったので……
戻り値変更はExifの仕様に従ったすべてのIFDを扱うにはちょっと不便な形だったので……
という経緯があります。
どちらも満足いく結果が得られ、追加すべきものもなくなってきたので今後はそう変わらないと思います
ただ各関数にファイル名でなくbytes型で直接JPEGデータを渡せるようになってる点に関して、
BytesIOを使った方法にしようかと思案してますが
プロフィール

Matoba

Author:Matoba

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。