Rubyで画像ファイルが破損していないかチェックする
Tumblrの画像を取りまくるツールを書いていて、ふと「ちゃんと画像が取れているのか?」と気になったのでチェックするコードを書いてみた。
アルゴリズムというか考え方
- JPEG については、ファイルが "0xFF 0xD8" で始まり、"0xFF 0xD9" で終わることをチェック。
- GIF については、ファイルが "GIF" で始まり、Trailer "0x3B" で終わることをチェック。
- PNG については、ファイルがPNGファイルシグネチャで始まり、IENDで終わることをチェック。
チェックコード
# result : [ filetype, result ] # filetype ::= ( :gif, :jpg, :png, :unknown ) # result ::= ( :damaged, :clean ) def check_file(filename) result = [ :unknown, :clean ] File.open(filename, "rb") do |f| begin header = f.read(8) f.seek(-12, IO::SEEK_END) footer = f.read(12) rescue result[1] = :damaged return result end if header[0,2].unpack("H*") == [ "ffd8" ] result[0] = :jpg result[1] = :damaged unless footer[-2,2].unpack("H*") == [ "ffd9" ] elsif header[0,3].unpack("A*") == [ "GIF" ] result[0] = :gif result[1] = :damaged unless footer[-1,1].unpack("H*") == [ "3b" ] elsif header[0,8].unpack("H*") == [ "89504e470d0a1a0a" ] result[0] = :png result[1] = :damaged unless footer[-12,12].unpack("H*") == [ "0000000049454e44ae426082" ] end end result end