ホーム ] TIPS ウィンドウズ系 ] TIPS グラフィックス系 ] TIPS メルチメディア系 ] TIPS 理数系 ] TIPS 総覧 ]

上へ
M0101 JPGサイズの獲得
M0105 EXIFメーカノートを読む

VB.NET2005 TIPS / マルチメディア系

M0101 JPGサイズの獲得

最終更新:2006/11/12 再掲

●解説

 JPEGファイルの画像サイズは、Imageとして読めば得ることができるが、画像ファイルを全て読み込むので時間が掛かる。ここでは、画像ファイルの付帯情報をバイナリで読み取り直接得る方法を紹介する。EXIFあるいは、JFIF(通常のJPEGファイル)で適用できる。

●原理

 EXIFやJFIFでは、画像の付帯情報が内包されており、マーカの hFFC0 で始まる領域に以下のように記録されている。

hFFC0 hSSSS hPP hYYYY hXXXX h・・・・

hSSSS:このブロックのサイズ(SSSSの2バイトを含む)
hPP:画像情報の一種
hYYYY:画像の縦のピクセルサイズ
hXXXX:画像の横のピクセルサイズ

●方法

○形式

 一般に、マーカの位置は不定なので、頭から手繰って探す必要がある。この場合は、一括に読むより、ストリームとしてバイト単位で逐次読む方が効率的である。Streamオブジェクトにてマーカを確認しながら読み取る。SeekおよびReadByteメソッドを使用する。マーカについては、ここを参照。

○手順

  1. SOIマーカ(Start Of Image):hFFD8 を確認する。

  2. APPマーカ:hFFE0(APP0:JFIF)、hFFE1(APP1:EXIF) を確認する。

  3. 上記がOKの場合は、hFFC0 を探し、あれば、画像サイズを読む。

●実例

Dim P As Long        'ストリームのポインタ
Dim W, H As Integer

Dim F As String = ファイルへのパス
Dim st As Stream = File.Open(F, FileMode.Open, FileAccess.Read)
If CheckJFIF(st) Then
   Select Case Marker(st)
      Case "FFE0"
         FT = "JFIF"
      Case "FFE1"
         FT = "EXIF"        
      Case Else
         FT = "不明"
   End Select
   If FT <> "不明" Then
      st.Seek(P, SeekOrigin.Current)
      If GetSize(st, W, H) Then
         →画像サイズ獲得
      Else
         →画像サイズ不明
      End If
   Else
      →JPEGファイルではない
   End If
Else
   →画像ファイルではない
End If
st.Close()

この例では、マーカは16進数の文字列に変換している。
ReadByteは1バイト読み込んで、Integerにし、ポインタを自動的に進めるものである。
(バッファリングやキャッシングはシステム側で自動的に行われる)

'ローカルな関数
Private Function CheckJFIF(ByVal st As Stream) As Boolean
   If Hex(st.ReadByte) = "FF" Then
      If Hex(st.ReadByte) = "D8" Then
         Return True
      End If
   End If
   Return False
End Function

Private Function GetSize(ByVal st As Stream, ByRef W As Integer, ByRef H As Integer) As Boolean
   Dim ff As Integer = 0
   Dim MK As String
   While ff = 0
      MK = Marker(st)
      Select Case MK
         Case "FFC0"
            st.Seek(1, SeekOrigin.Current)   '1バイト読み飛ばす
            H = st.ReadByte * 256
            H = H + st.ReadByte
            W = st.ReadByte * 256
            W = W + st.ReadByte

            Return True
         Case "FFD9"
            Return False     'hFFC0見つからず
         Case Else
            st.Seek(P, SeekOrigin.Current)   '次のマーカの先頭に行く
      End Select
   End While
   Return False
End Function

'マーカとそのサイズを獲得する。
Private Function Marker(ByVal st As Stream) As String
   Dim M As String
   M = Hex(st.ReadByte)
   M = M + Hex(st.ReadByte)
   If M <> "FFD9" Then
      P = st.ReadByte * 256
      P = P + st.ReadByte - 2
   End If
   Return M
End Function