LoginSignup
4
3

More than 5 years have passed since last update.

画像ファイルがHEIFやWebPかどうかをImageMagickに依存せずに判定する方法

Last updated at Posted at 2018-02-15

要求

POSTでアップロードされた画像データのフォーマットをサーバサイド(Go言語)で判定していきたい。
一応ImageMagick の Go言語バインディングは存在するが、本番環境にImageMagickあまり入れたくない。
https://github.com/gographics/imagick

なので、それぞれの画像形式のバイナリフォーマットの仕様を見て、ヘッダ部分で特定可能な部分を泥臭く一致するかチェックして実装してみた。

結果

WebP

WebP Container Specification
-> 1-4バイト目が "RIFF", 9-12 "WEBP" のASCII文字列があればWebPとなす。

以下の様なコードにしました。

var (
    webpStartBytes = []byte{0x52, 0x49, 0x46, 0x46} // 'R' 'I' 'F' 'F'
    webpFormatChar = []byte{0x57, 0x45, 0x42, 0x50} // 'W' 'E' 'B' 'P'
)

func isWebp(imageBytes []byte) bool {
    if len(imageBytes) < 12 {
        return false
    }
    // 最初の4バイトをチェック
    if !simpleByteRangeEqual(imageBytes, webpStartBytes, len(webpStartBytes)) {
        return false
    }
    // 9から12バイトをチェック
    if !simpleByteRangeEqual(imageBytes[8:12], webpFormatChar, 4) {
        return false
    }
    return true
}

func simpleByteRangeEqual(bytes1, bytes2 []byte, checkLength int) bool {
    for index := 0; index < checkLength; index++ {
        if bytes1[index] != bytes2[index] {
            return false
        }
    }
    return true
}

HEIF

自分がしょぼいのかどうもはっきりとしたヘッダ部分のフォーマットがわからなかった。
探した資料は以下。

とりあえずすぐ実装したかったので、以下のサンプル画像をhexdump -Cとバイナリエディタ0xEDで眺めてみた。
http://nokiatech.github.io/heif/examples.html

hexdump の結果の一部。


  00000000  00 00 00 1c 66 74 79 70  6d 69 66 31 00 00 00 00  |....ftypmif1....|
00000010  6d 69 66 31 68 65 69 63  68 65 76 63 00 00 01 31  |mif1heichevc...1|
00000020  6d 65 74 61 00 00 00 00  00 00 00 21 68 64 6c 72  |meta.......!hdlr|
00000030  00 00 00 00 00 00 00 00  70 69 63 74 00 00 00 00  |........pict....|
00000040  00 00 00 00 00 00 00 00  00 00 00 00 0e 70 69 74  |.............pit|
00000050  6d 00 00 00 00 4e 21 00  00 00 22 69 6c 6f 63 00  |m....N!..."iloc.|
00000060  00 00 00 44 40 00 01 4e  21 00 00 00 00 01 55 00  |...D@..N!.....U.|
00000070  01 00 00 00 00 00 00 94  25 00 00 00 2f 69 69 6e  |........%.../iin|
00000080  66 02 00 00 00 00 00 00  01 00 00 00 1f 69 6e 66  |f............inf|
00000090  65 02 00 00 00 4e 21 00  00 68 76 63 31 48 45 56  |e....N!..hvc1HEV|
000000a0  43 20 49 6d 61 67 65 00  00 00 00 a5 69 70 72 70  |C Image.....iprp|

mif1heichevc とか hvc1HEV Image とか、フォーマットに関するヘッダぽいASCII文字列がいることがわかる。
一旦これをベタに一致するかどうかで判定してしまおう……

var heifHeaderChar = []byte{0x6d, 0x69, 0x66, 0x31, 0x68, 0x65, 0x69, 0x63, 0x68, 0x65, 0x76, 0x63} // "mif1heichevc"

func isHeif(imageBytes []byte) bool {
    // mif1heichevc in 17-28 byte
    if len(imageBytes) < 28 {
        return false
    }
    if simpleByteRangeEqual(imageBytes[16:28], heifHeaderChar, 12) {
        return true
    }
    return false
}

とりあえずこれで様子見ていて、問題あれば改善していく予定。

4
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3