Crystalで PNG画像ファイルの幅と高さをヘッダの部分から取得します、
ヘッダ部分を見て、PNG画像のヘッダかどうかの判断もするようになっています、
実際に画像データを読み込むわけではないのでデータが壊れていないなどの保証は出来ません、
その分、情報の取得速度は非常に高速です。
ヘッダの構造を読み替えれば、その他の情報や その他のファイル形式にも応用できます。
# png_picture_size <filename> [0|1] [both|cols|rows] # 0 or 1 カウントを始める数、省略時は 1 # (座標として扱う時は0、 幅や高さとして扱う時は1の方が扱いやすい) # cols 幅だけ、rows 高さだけ、省略 または both 両方。 # 0, 1 および both, cols, rows を複数指定した場合は 最後のものが有効 # (例:「png_picture_size ./data.png both cols 0 rows 1」は「rows と 1」のオプションが有効) # 取得に成功した時は 標準出力で数値を返します (幅高さ両方の時は 半角スペース区切りです) # 取得に失敗した時は ERRORLEVEL に 1を設定するのでそれを参照するか # 標準出力に 長さ0の文字列 "" を返すのでそれで判断してください ( #puts("no option") exit(1) ) if ARGV.size < 1 png_file = File.expand_path(ARGV[0]) ( #puts("file not found") exit(1) ) if !File.exists?(png_file) count_decrement = 0 cols_rows = 0 # 0=両方 1=colsのみ 2=rowsのみ (1..(ARGV.size-1)).each{|c| case ARGV[c] when "0" then count_decrement = 1 when "1" then count_decrement = 0 when "both" then cols_rows = 0 when "cols" then cols_rows = 1 when "rows" then cols_rows = 2 end } # 画像の幅や高さの情報は IHDRチャンク内にあり場所は固定なので、その部分を取得すれば値を得られます # PNGファイルシグネチャ 8byte [0..7] -> 0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A ならPNG形式 # IHDRチャンク 25byte [8..32] # Length 4byte -> ChunkDataLength 0x0d (13)で固定 [8..11] # ChunkType 4byte -> 0x49 0x48 0x44 0x52 (IHDRのASCIIコード)で固定 [12..15] # ChunkData 4byte -> Width [16..19] # ChunkData 4byte -> Height [20..23] # ChunkData 1byte -> BitDepth [24] # ChunkData 1byte -> ColorType [25] # ChunkData 1byte -> Compression [26] # ChunkData 1byte -> Filter [27] # ChunkData 1byte -> Interlace [28] # CRC 4byte -> ChunkTypeとChunkDataから算出される [29..32] # 以降、IDATチャンク IENDチャンクが続く File.open(png_file){|f| begin bin = Slice(UInt8).new(24) f.read(bin) exit(1) if bin[0..7].hexstring != "89504e470d0a1a0a" width = bin[16..19].hexstring.to_i(16) height = bin[20..23].hexstring.to_i(16) print( case cols_rows when 0 "#{width-count_decrement} #{height-count_decrement}" when 1 "#{width-count_decrement}" when 2 "#{height-count_decrement}" end ) rescue #puts("some kind of error has occurred") exit(1) end }