Debian10(buster)ではpython2.7と3.7が両方デフォルトで入っています。最初に使うpython3のモジュールはPILですが、Debianではpython3-pilというパッケージになっています。aptで追加したかどうかは記憶にありませんのでデフォルトでインストールされていたのかもしれません。
pythonのモジュールはpipで管理する方法を見ますが、debianではdebianパッケージで追加することが可能です。また、python3-pipというパッケージもあって、どういう関係か不明ですが、debianパッケージで入れられるものはこれに従うことにしています。
次に使うモジュールはexifreadです。python3-exifパッケージになっています。
python3-pilパッケージを入れて使います。
PILは Python Image Library なのでexifだけのものではない様です。
#!/usr/bin/python3 from PIL import Image from PIL.ExifTags import TAGS def get_exif_dic(file): pilimage = Image.open(file) print(type(pilimage)) #class:PIL.MpoImagePlugin.MpoImageFile rawdic = pilimage._getexif() print(type(rawdic)) #class:dict exifdic = {} for k, v in rawdic.items(): vstr = str(v) if len(vstr) > 64: vstr = vstr[:65] + "..." print(str(k),":",TAGS.get(k,k),":",vstr,":",type(v)) exifdic[TAGS.get(k,k)] = v return exifdic file1 = "/home/adachi/Downloads/sample.jpg" file2 = "/home/adachi/Downloads/DSC_1414.JPG" edic = get_exif_dic(file2)
pilimage._getexif()でexifの辞書(dict,map)が得られます。keyはintで、valueは数値だったり文字列だったりいろいろです。
intのkeyをexifでよく見る文字列にするために、TAGSという辞書を使って、文字列のタグと値の辞書(exifdic)に変換するのがget_exif_dic(file)という関数です。
get(k,k)はTAGSにkがなければkそのものを返すようにしています。kはintなのでjava的な発想ではget(k,str(k))とするところですが、まあ問題ありません。get(k)を使うと None が返ります。
GPSInfoのvalueは辞書で、その中のkeyを文字列にするのには GPSTAGSがありますが、今回は使用していません。
MakerNoteのvalueはバイト列で返ります。解析がすすめばGPSInfoの様に辞書になって戻ると思いますが、PILではそこまでやってくれません。
LensModelを返してくれるのはNIKON,HUAWEI(スマホ),OLYMPUSの中では、OLYMPUSだけです。
NIKONならば、MakerNoteに情報がありますが、NIKON内でも機種によりMakerNoteの仕様が異なるので厄介です。
いままでruby用のexifではレンズ情報は取れていなかったので、PILでも十分なのですが、MakerNoteがとれないかということでもう一歩調べてみます。
get_exif_dic(file)関数内で、print出力しています。これは文字列のタグ名を知るため、またvalueの形式を知るためです。
ExposureTimeが'1/50'ではなく、(10, 500) という 'tuple' で返ってくるというのもひと手間がかかります。
adachi@fumita:/media/adachi/S1T/python3$ ./PilExifTag00.py <class 'PIL.MpoImagePlugin.MpoImageFile'> <class 'dict'> 34853 : GPSInfo : {0: b'\x02\x03\x00\x00'} : <class 'dict'> 296 : ResolutionUnit : 2 : <class 'int'> 34665 : ExifOffset : 348 : <class 'int'> 271 : Make : NIKON CORPORATION : <class 'str'> 272 : Model : NIKON D500 : <class 'str'> 305 : Software : Ver.1.20 : <class 'str'> 274 : Orientation : 1 : <class 'int'> 306 : DateTime : 2020:02:24 10:33:22 : <class 'str'> 315 : Artist : : <class 'str'> 531 : YCbCrPositioning : 2 : <class 'int'> 33432 : Copyright : : <class 'str'> 282 : XResolution : (300, 1) : <class 'tuple'> 283 : YResolution : (300, 1) : <class 'tuple'> 36864 : ExifVersion : b'0230' : <class 'bytes'> 37121 : ComponentsConfiguration : b'\x01\x02\x03\x00' : <class 'bytes'> 37122 : CompressedBitsPerPixel : (4, 1) : <class 'tuple'> 36867 : DateTimeOriginal : 2020:02:24 10:33:22 : <class 'str'> 36868 : DateTimeDigitized : 2020:02:24 10:33:22 : <class 'str'> 37380 : ExposureBiasValue : (-2, 6) : <class 'tuple'> 37381 : MaxApertureValue : (36, 10) : <class 'tuple'> 37383 : MeteringMode : 3 : <class 'int'> 37384 : LightSource : 0 : <class 'int'> 37385 : Flash : 0 : <class 'int'> 37386 : FocalLength : (400, 10) : <class 'tuple'> 37510 : UserComment : b'ASCII\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x... : <class 'bytes'> 40961 : ColorSpace : 1 : <class 'int'> 40962 : ExifImageWidth : 5568 : <class 'int'> 40965 : ExifInteroperabilityOffset : 18796 : <class 'int'> 41990 : SceneCaptureType : 0 : <class 'int'> 37520 : SubsecTime : 40 : <class 'str'> 37521 : SubsecTimeOriginal : 40 : <class 'str'> 37522 : SubsecTimeDigitized : 40 : <class 'str'> 40963 : ExifImageHeight : 3712 : <class 'int'> 41996 : SubjectDistanceRange : 0 : <class 'int'> 41495 : SensingMethod : 2 : <class 'int'> 41728 : FileSource : b'\x03' : <class 'bytes'> 33434 : ExposureTime : (10, 500) : <class 'tuple'> 33437 : FNumber : (110, 10) : <class 'tuple'> 41729 : SceneType : b'\x01' : <class 'bytes'> 34850 : ExposureProgram : 1 : <class 'int'> 41730 : CFAPattern : b'\x02\x00\x02\x00\x00\x01\x01\x02' : <class 'bytes'> 41985 : CustomRendered : 0 : <class 'int'> 34855 : ISOSpeedRatings : 800 : <class 'int'> 41986 : ExposureMode : 1 : <class 'int'> 40960 : FlashPixVersion : b'0100' : <class 'bytes'> 34864 : None : 2 : <class 'int'> 41987 : WhiteBalance : 0 : <class 'int'> 41989 : FocalLengthIn35mmFilm : 60 : <class 'int'> 41991 : GainControl : 1 : <class 'int'> 41992 : Contrast : 0 : <class 'int'> 41993 : Saturation : 0 : <class 'int'> 41994 : Sharpness : 0 : <class 'int'> 37500 : MakerNote : b'Nikon\x00\x02\x11\x00\x00II*\x00\x08\x00\x00\x00>\x00\x01\x00\x... : <class 'bytes'>
DateTimeOriginalなどの、exifのある値を求めるには、TAGSを使って相当するkeyを調べる必要があります。見つかればその値を返し、見つからなければ空文字列を返すことにします。
一つのファィルから複数の値を取るときには効率が悪いのですが、逆にひとつだけ必要な場合もあるでしょう。
DateTimeOriginalとExposureTimeを求めています。
#!/usr/bin/python3 from PIL import Image from PIL.ExifTags import TAGS def get_exif_value(file,strkey): pilimage = Image.open(file) rawdic = pilimage._getexif() for k in rawdic.keys(): if TAGS.get(k) == strkey: return rawdic[k] return '' file1 = "/home/adachi/Downloads/sample.jpg" file2 = "/home/adachi/Downloads/DSC_1414.JPG" strkey = "DateTimeOriginal" evalue = get_exif_value(file2,strkey) print(strkey,":",evalue,":",type(evalue)) strkey = "ExposureTime" evalue = get_exif_value(file2,strkey) print(strkey,":",evalue,":",type(evalue))
実行結果です。tupleは、1/50です。
adachi@fumita:/media/adachi/S1T/python3$ ./PilExifTag01.py DateTimeOriginal : 2020:02:24 10:33:22 : <class 'str'> ExposureTime : (10, 500) : <class 'tuple'>
python3-exifパッケージを入れて使います。
PILは 画像ファイルの加工がメインで、exif関係はおまけ的な扱いに見えます。exifreadの方は検索ではあまり出てきませんが、exifデータを取り出すことに特化しているようです。MakerNoteにもある程度対応しています。
プログラムはファイルハンドラf(pythonのtypeでは'_io.BufferedReader')から文字列をキーとした辞書tagsを直接得ることができますから、関数にする必要はないのですが、PILに形を合わせて、関数内でexifタグの一覧を表示します。
PILでは辞書は(int,いろいろ)でしたが、今度は(str,exifread.classes.IfdTag)です。(JPEGThumbnail だけはbytes)
exifread.classes.IfdTagとしてくるんでいるだけで実際には内容はさまざまです。str()で文字列化していますので違いが表面化していません。
#!/usr/bin/python3 #needs debian-package python3-exif #Python library to extract Exif data from TIFF and JPEG files #keyword:exifread #or/ pip install exifread import exifread def get_exif_dic(file): with open(file, 'rb') as f: tags = exifread.process_file(f) print(type(tags)) #class:dict for k, v in tags.items(): vstr = str(v) if len(vstr) > 42: vstr = vstr[:43] + "..." print(k,":",vstr,":",type(v)) return tags file1 = "/home/adachi/Downloads/sample.jpg" file2 = "/home/adachi/Downloads/DSC_1414.JPG" edic = get_exif_dic(file2)
withで始まるのは新し目の書き方です。closeがいらなくなります。mode='rb'はバイナリーモードを意味します。
exifread.process_file(f)だけでstrをkeyとする辞書が得られます。keyは'DateTimeOriginal'が'EXIF DateTimeOriginal'というように、'EXIF'や'Image'などもう一つの単語と組み合わさり2語になります。これは、'EXIF MakerNote' の値(バイト列ですが)を解析して発掘されるタグを、'MakerNote Hogehoge'というキーでマージするということをするためだと思います。バイト列のvalueは長いものが多いので、printには長さ制限をしています。
実行結果
adachi@fumita:/media/adachi/S1T/python3$ python3 withExifread00.py <class 'dict'> Image Make : NIKON CORPORATION : <class 'exifread.classes.IfdTag'> Image Model : NIKON D500 : <class 'exifread.classes.IfdTag'> Image Orientation : Horizontal (normal) : <class 'exifread.classes.IfdTag'> Image XResolution : 300 : <class 'exifread.classes.IfdTag'> Image YResolution : 300 : <class 'exifread.classes.IfdTag'> Image ResolutionUnit : Pixels/Inch : <class 'exifread.classes.IfdTag'> Image Software : Ver.1.20 : <class 'exifread.classes.IfdTag'> Image DateTime : 2020:02:24 10:33:22 : <class 'exifread.classes.IfdTag'> Image Artist : : <class 'exifread.classes.IfdTag'> Image YCbCrPositioning : Co-sited : <class 'exifread.classes.IfdTag'> Image Copyright : : <class 'exifread.classes.IfdTag'> Image ExifOffset : 348 : <class 'exifread.classes.IfdTag'> GPS GPSVersionID : [2, 3, 0, 0] : <class 'exifread.classes.IfdTag'> Image GPSInfo : 18828 : <class 'exifread.classes.IfdTag'> Thumbnail Compression : JPEG (old-style) : <class 'exifread.classes.IfdTag'> Thumbnail XResolution : 300 : <class 'exifread.classes.IfdTag'> Thumbnail YResolution : 300 : <class 'exifread.classes.IfdTag'> Thumbnail ResolutionUnit : Pixels/Inch : <class 'exifread.classes.IfdTag'> Thumbnail JPEGInterchangeFormat : 18956 : <class 'exifread.classes.IfdTag'> Thumbnail JPEGInterchangeFormatLength : 12147 : <class 'exifread.classes.IfdTag'> Thumbnail YCbCrPositioning : Co-sited : <class 'exifread.classes.IfdTag'> EXIF ExposureTime : 1/50 : <class 'exifread.classes.IfdTag'> EXIF FNumber : 11 : <class 'exifread.classes.IfdTag'> EXIF ExposureProgram : Manual : <class 'exifread.classes.IfdTag'> EXIF ISOSpeedRatings : 800 : <class 'exifread.classes.IfdTag'> EXIF SensitivityType : Recommended Exposure Index : <class 'exifread.classes.IfdTag'> EXIF ExifVersion : 0230 : <class 'exifread.classes.IfdTag'> EXIF DateTimeOriginal : 2020:02:24 10:33:22 : <class 'exifread.classes.IfdTag'> EXIF DateTimeDigitized : 2020:02:24 10:33:22 : <class 'exifread.classes.IfdTag'> EXIF ComponentsConfiguration : YCbCr : <class 'exifread.classes.IfdTag'> EXIF CompressedBitsPerPixel : 4 : <class 'exifread.classes.IfdTag'> EXIF ExposureBiasValue : -1/3 : <class 'exifread.classes.IfdTag'> EXIF MaxApertureValue : 18/5 : <class 'exifread.classes.IfdTag'> EXIF MeteringMode : Spot : <class 'exifread.classes.IfdTag'> EXIF LightSource : Unknown : <class 'exifread.classes.IfdTag'> EXIF Flash : Flash did not fire : <class 'exifread.classes.IfdTag'> EXIF FocalLength : 40 : <class 'exifread.classes.IfdTag'> EXIF MakerNote : [78, 105, 107, 111, 110, 0, 2, 17, 0, 0, 73... : <class 'exifread.classes.IfdTag'> EXIF UserComment : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... : <class 'exifread.classes.IfdTag'> EXIF SubSecTime : 40 : <class 'exifread.classes.IfdTag'> EXIF SubSecTimeOriginal : 40 : <class 'exifread.classes.IfdTag'> EXIF SubSecTimeDigitized : 40 : <class 'exifread.classes.IfdTag'> EXIF FlashPixVersion : 0100 : <class 'exifread.classes.IfdTag'> EXIF ColorSpace : sRGB : <class 'exifread.classes.IfdTag'> EXIF ExifImageWidth : 5568 : <class 'exifread.classes.IfdTag'> EXIF ExifImageLength : 3712 : <class 'exifread.classes.IfdTag'> Interoperability InteroperabilityIndex : R98 : <class 'exifread.classes.IfdTag'> Interoperability InteroperabilityVersion : [48, 49, 48, 48] : <class 'exifread.classes.IfdTag'> EXIF InteroperabilityOffset : 18796 : <class 'exifread.classes.IfdTag'> EXIF SensingMethod : One-chip color area : <class 'exifread.classes.IfdTag'> EXIF FileSource : Digital Camera : <class 'exifread.classes.IfdTag'> EXIF SceneType : Directly Photographed : <class 'exifread.classes.IfdTag'> EXIF CVAPattern : [2, 0, 2, 0, 0, 1, 1, 2] : <class 'exifread.classes.IfdTag'> EXIF CustomRendered : Normal : <class 'exifread.classes.IfdTag'> EXIF ExposureMode : Manual Exposure : <class 'exifread.classes.IfdTag'> EXIF WhiteBalance : Auto : <class 'exifread.classes.IfdTag'> EXIF FocalLengthIn35mmFilm : 60 : <class 'exifread.classes.IfdTag'> EXIF SceneCaptureType : Standard : <class 'exifread.classes.IfdTag'> EXIF GainControl : Low gain up : <class 'exifread.classes.IfdTag'> EXIF Contrast : Normal : <class 'exifread.classes.IfdTag'> EXIF Saturation : Normal : <class 'exifread.classes.IfdTag'> EXIF Sharpness : Normal : <class 'exifread.classes.IfdTag'> EXIF SubjectDistanceRange : 0 : <class 'exifread.classes.IfdTag'> MakerNote MakernoteVersion : 0211 : <class 'exifread.classes.IfdTag'> MakerNote Quality : FINE : <class 'exifread.classes.IfdTag'> MakerNote Whitebalance : AUTO0 : <class 'exifread.classes.IfdTag'> MakerNote FocusMode : AF-S : <class 'exifread.classes.IfdTag'> MakerNote FlashSetting : NORMAL : <class 'exifread.classes.IfdTag'> MakerNote AutoFlashMode : : <class 'exifread.classes.IfdTag'> MakerNote WhiteBalanceBias : [0, 0] : <class 'exifread.classes.IfdTag'> MakerNote WhiteBalanceRBCoeff : [2059/1024, 3533/2048, 1, 1] : <class 'exifread.classes.IfdTag'> MakerNote ProgramShift : 0 EV : <class 'exifread.classes.IfdTag'> MakerNote ExposureDifference : -1.6666666666666667 2/3 EV : <class 'exifread.classes.IfdTag'> MakerNote PhotoCornerCoordinates : [0, 0, 5568, 3712] : <class 'exifread.classes.IfdTag'> MakerNote ExternalFlashExposureComp : 0 EV : <class 'exifread.classes.IfdTag'> MakerNote FlashBracketCompensationApplied : 0 EV : <class 'exifread.classes.IfdTag'> MakerNote AEBracketCompensationApplied : 0 : <class 'exifread.classes.IfdTag'> MakerNote CropHiSpeed : [12, 5600, 3728, 5600, 3728, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote ExposureTuning : [0, 1, 6] : <class 'exifread.classes.IfdTag'> MakerNote SerialNumber : 2048107 : <class 'exifread.classes.IfdTag'> MakerNote ColorSpace : 1 : <class 'exifread.classes.IfdTag'> MakerNote VRInfo : [48, 49, 48, 48, 2, 2, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote ActiveDLighting : 0 : <class 'exifread.classes.IfdTag'> MakerNote PictureControl : [48, 50, 48, 48, 83, 84, 65, 78, 68, 65, 82... : <class 'exifread.classes.IfdTag'> MakerNote WorldTime : [28, 2, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote ISOInfo : [96, 1, 12, 0, 0, 0, 96, 1, 12, 0, 0, 0, 0,... : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x002A : 3 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x002B : [48, 49, 48, 48, 0, 4, 2, 17, 0, 0, 0, 0, 0... : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x002C : [48, 49, 48, 49, 35, 0, 128, 2, 170, 1, 0, ... : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0035 : [48, 49, 48, 48, 0, 0, 0, 255] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x003B : [1, 1, 1, 1] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x003C : 1 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x003E : 1 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x003F : [0, 0] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0040 : [48, 49, 48, 48, 1, 0, 67, 0, 48, 49, 50, 4... : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0041 : [48, 49, 48, 48, 0, 1] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0042 : [48, 49, 48, 48, 2, 0] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0043 : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0044 : 3 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0047 : [48, 49, 48, 48, 0, 0, 0, 0, 0, 128, 0, 128... : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x0049 : [48, 49, 48, 48, 0, 0, 0, 0, 0, 0, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote LensType : 6 : <class 'exifread.classes.IfdTag'> MakerNote LensMinMaxFocalMaxAperture : [40, 40, 14/5, 14/5] : <class 'exifread.classes.IfdTag'> MakerNote FlashMode : Did Not Fire : <class 'exifread.classes.IfdTag'> MakerNote BracketingMode : Single frame, no bracketing : <class 'exifread.classes.IfdTag'> MakerNote AutoBracketRelease : 1 : <class 'exifread.classes.IfdTag'> MakerNote LensFStops : [72, 1, 12, 0] : <class 'exifread.classes.IfdTag'> MakerNote ShotInfo : [] : <class 'exifread.classes.IfdTag'> MakerNote NoiseReduction : OFF : <class 'exifread.classes.IfdTag'> MakerNote ColorBalance : [] : <class 'exifread.classes.IfdTag'> MakerNote LensData : [48, 50, 48, 52, 196, 53, 1, 158, 201, 251,... : <class 'exifread.classes.IfdTag'> MakerNote RetouchHistory : [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote ImageDataSize : 8999015 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x00A3 : 0 : <class 'exifread.classes.IfdTag'> MakerNote TotalShutterReleases : 1494 : <class 'exifread.classes.IfdTag'> MakerNote FlashInfo : [48, 49, 48, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0,... : <class 'exifread.classes.IfdTag'> MakerNote MultiExposure : [48, 49, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0,... : <class 'exifread.classes.IfdTag'> MakerNote HighISONoiseReduction : 4 : <class 'exifread.classes.IfdTag'> MakerNote PowerUpTime : [0, 0, 0, 0, 0, 0, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote AFInfo2 : [48, 49, 48, 49, 0, 0, 7, 45, 0, 0, 0, 0, 0... : <class 'exifread.classes.IfdTag'> MakerNote FileInfo : [48, 49, 48, 48, 1, 0, 100, 0, 134, 5, 0, 0... : <class 'exifread.classes.IfdTag'> MakerNote AFTune : [0, 255, 0, 0] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x00BB : [48, 50, 48, 48, 255, 255, 255, 0] : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x00BF : 0 : <class 'exifread.classes.IfdTag'> MakerNote Tag 0x00C0 : [60, 1, 12, 0, 168, 1, 12, 0] : <class 'exifread.classes.IfdTag'> JPEGThumbnail : b'\xff\xd8\xff\xdb\x00\x84\x00\x01\x01\x01\... : <class 'bytes'>
いろいろなファイルを切り替えて試すためにコマンドライン引数を使って切り替えるようにしました。1〜5の引数で選択されたパス付きのファイル名が変数fileに入れられます。引数がなければ1、5以上は5を指定したことになります。
with以下が本筋です。
import sys import exifread files = { '1':"/home/adachi/Downloads/sample.jpg", '2':"/home/adachi/Downloads/DSC_1414.JPG", '3':"/home/adachi/Downloads/P3300108.JPG", '4':"/home/adachi/Downloads/IMG_20190224_111208.jpg", '5':"/home/adachi/Downloads/from_google200326.png", } file = files.get(sys.argv[1],files['5']) if len(sys.argv)>1 else files['0'] with open(file, 'rb') as f: tags = exifread.process_file(f) print('filename:',f.name) key = "Image Model" print(key,":",tags.get(key,'')) key = "Image Orientation" print(key,":",tags.get(key,'')) key = "EXIF DateTimeOriginal" print(key,":",tags.get(key,'')) key = "EXIF ExposureTime" print(key,":",tags.get(key,'')) key = "EXIF FNumber" print(key,":",tags.get(key,'')) key = "EXIF ISOSpeedRatings" print(key,":",tags.get(key,'')) key = "EXIF FocalLengthIn35mmFilm" print(key,":",tags.get(key,'')) key = "EXIF FocalLength" print(key,":",tags.get(key,'')) key = "EXIF ExifImageWidth" print(key,":",tags.get(key,'')) key = "EXIF LensSpecification" print(key,":",tags.get(key,'')) key = "EXIF LensModel" print(key,":",tags.get(key,'')) key = "MakerNote LensMinMaxFocalMaxAperture" print(key,":",tags.get(key,''))
exifread.process_file(f)で得られるtagsはdictなので、get()で値を取ることができます。''はkeyがなかったときに返す値です。
keyは一般的なexifのタグにEXIFとかImageがついたものを指定します。
返ってくる値の型は'exifread.classes.IfdTag'ですが、str()で文字列化可能です。
EXIF ExposureTime が 1/750 になっています。PIL.ExifTagsでは(10,7500)のタプルでした。手間が省けます。
adachi@fumita:/media/adachi/S1T/python3$ python3 withExifread01.py 1 filename: /home/adachi/Downloads/sample.jpg Image Model : NIKON D300S Image Orientation : Horizontal (normal) EXIF DateTimeOriginal : 2018:07:24 12:05:34 EXIF ExposureTime : 1/750 EXIF FNumber : 13 EXIF ISOSpeedRatings : 800 EXIF FocalLengthIn35mmFilm : 27 EXIF FocalLength : 18 EXIF ExifImageWidth : 4288 EXIF LensSpecification : EXIF LensModel : MakerNote LensMinMaxFocalMaxAperture :
前項のD300sの写真ではlensの情報はまったくなしです。もちろん撮影時のf値はわかりますが、絞る前のlensの開放f値や、ズームレンズのときの絞りの最大値を知りたいのです。次のD500ではLensMinMaxFocalMaxApertureが使えそうです。[40, 40, 14/5, 14/5]は、[40mm, 40mm, F2.8, F2.8]のことで、要するに40mm F2.8の単焦点レンズということです。
adachi@fumita:/media/adachi/S1T/python3$ python3 withExifread01.py 2 filename: /home/adachi/Downloads/DSC_1414.JPG Image Model : NIKON D500 Image Orientation : Horizontal (normal) EXIF DateTimeOriginal : 2020:02:24 10:33:22 EXIF ExposureTime : 1/50 EXIF FNumber : 11 EXIF ISOSpeedRatings : 800 EXIF FocalLengthIn35mmFilm : 60 EXIF FocalLength : 40 EXIF ExifImageWidth : 5568 EXIF LensSpecification : EXIF LensModel : MakerNote LensMinMaxFocalMaxAperture : [40, 40, 14/5, 14/5]
E-M10MarkIIではMakerNoteではなく、EXIFの中に同様のlistがあります。EXIF LensSpecification : [14, 42, 7/2, 28/5] これはズームレンズです。
加えてEXIF LensModel : OLYMPUS M.14-42mm F3.5-5.6 EZとあります。listの4つの数値の意味がわかるでしょう。
adachi@fumita:/media/adachi/S1T/python3$ python3 withExifread01.py 3 filename: /home/adachi/Downloads/P3300108.JPG Image Model : E-M10MarkII Image Orientation : Rotated 90 CW EXIF DateTimeOriginal : 2020:03:30 17:10:05 EXIF ExposureTime : 1/200 EXIF FNumber : 11 EXIF ISOSpeedRatings : 3200 EXIF FocalLengthIn35mmFilm : EXIF FocalLength : 14 EXIF ExifImageWidth : 4608 EXIF LensSpecification : [14, 42, 7/2, 28/5] EXIF LensModel : OLYMPUS M.14-42mm F3.5-5.6 EZ MakerNote LensMinMaxFocalMaxAperture :
HUAWEI VNS-L22 ではlensの情報はなしです。露出時間は711/1000000となっていますが、他のGUIソフトでは1/1406 秒となっています。焦点距離は379/100ですが、これも3.8mmのことです。割り切れないのでこのようにしていると思われますが、計算し直すべきか迷うところです。7/2は3.5が普通ですし、28/5は5.6が普通です。
計算し直すとすれば、数に変換し小数にするのか分数にするのか、精度も加味すると難しそうです。
adachi@fumita:/media/adachi/S1T/python3$ python3 withExifread01.py 4 filename: /home/adachi/Downloads/IMG_20190224_111208.jpg Image Model : HUAWEI VNS-L22 Image Orientation : 0 EXIF DateTimeOriginal : 2019:02:24 11:12:09 EXIF ExposureTime : 711/1000000 EXIF FNumber : 2 EXIF ISOSpeedRatings : 50 EXIF FocalLengthIn35mmFilm : 69 EXIF FocalLength : 379/100 EXIF ExifImageWidth : 4160 EXIF LensSpecification : EXIF LensModel : MakerNote LensMinMaxFocalMaxAperture :
PILでは分数になるものは分子分母の整数をタプルで表現していました。
class 'exifread.classes.IfdTag'では、有理数を表すrationalに似た仕組みが組み込まれているようです。
変数のtype、クラス、継承などpythonのそのあたりの仕組みはまだ知らないので、調べてみなければなりません。
これは、この次。