iMind Developers Blog

iMind開発者ブログ

Pythonのimghdrで画像の形式判定

概要

Pythonのimghdrモジュールを使って画像ファイルの形式を判定する。

バージョン情報

  • Python 3.7.6

参考ページ

https://docs.python.org/ja/3/library/imghdr.html

ファイル名を指定して判定

pngファイルをimghdrで判定してみる。

test.pngというファイル名で何か適当なpngファイルを保存し、下記のコードを実行する。

imghdr.what('test.png')

    #=> png

pngという文字列が返ってきた。jpegファイルならjpeg、gifファイルならgifという文字列が返る。

上記で使った test.png のファイル名だけ test.jpg に変更して判定してみる。

imghdr.what('test.jpg')

    #=> png

ちゃんとファイルの中身を見て判定しているので、拡張子が変わっても判定結果が変わることはない。

既に開いているファイルの判定

openしたファイルについても引数に渡せる。

with open('test.png', 'rb') as fp:
    print( imghdr.what(fp) )

    #=> png

3系の場合、開く時は rb で開かないとエラーになるので注意。

with open('test.png') as fp:
    print( imghdr.what(fp) )

    #=> UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte

imghdrの仕組み

imghdrはファイルの冒頭32byteを読み込んでマジックナンバー等を確認している。

下記はpngチェックの実装。

def test_png(h, f):
    if h.startswith(b'\211PNG\r\n\032\n'):
        return 'png'

pngのシグネチャは 89 50 4E 47 0D 0A 1A 0A で、これをbytesで表すとこうなるらしい。

こちらはjpeg。

def test_jpeg(h, f):
    """JPEG data in JFIF or Exif format"""
    if h[6:10] in (b'JFIF', b'Exif'):
        return 'jpeg'

jpegのチェックは見ての通り、適当に書いたテキストでも通過してしまうケースはある。

例えば下記のテキストを保存したファイルはjpegと判定される。

hoge AJFIF fuga

この実装を読むと画像ファイルのシグネチャについて詳しくなれそう。

https://github.com/python/cpython/blob/3.8/Lib/imghdr.py

判定可能なファイル形式

Image format
rgb SGI ImgLib Files
gif GIF 87a and 89a Files
pbm Portable Bitmap Files
pgm Portable Graymap Files
ppm Portable Pixmap Files
tiff TIFF Files
rast Sun Raster Files
xbm X Bitmap Files
jpeg JPEG data in JFIF or Exif formats
bmp BMP files
png Portable Network Graphics
webp WebP files
exr OpenEXR Files

改定履歴

Author: Masato Watanabe, Date: 2020-01-25, 記事投稿