先日は丁寧に教えていただきありがとうございました。
また分からないことができましたので、教えていただけないでしょうか。
指定されたファイルの、フォーマットを調べる方法を知りたいです。
基本的に画像ファイルのみが対象で、jpeg, png, gif, bmp, 他、くらいの
識別ができればいいです。
読み込んだビットマップのGuidをGDI+を使って調べることで
可能だということは下記から分かりました。
http://www.atmarkit.co.jp/fdotnet/dotnettips/022getformat/getformat.html
が、実際に VBA で実行するにはどうすればよいのか分かりません。
ビットマップから、上記サイトでいうところの bitmap.RawFormat.Guid を
得る方法が全然分かりません。
照合するための配列 decoders = ImageCodecInfo.GetImageDecoders()
については、以前教えていただいた SDK に記載があったのですが、
http://msdn2.microsoft.com/ja-jp/library/system.drawing.imaging.imagecodecinfo.getimagedecoders(VS.80).aspx
これを VBA で使うための宣言や方法が分からないのです。
毎度申し訳ありませんが、お力をいただけたらと思います。
> jpeg, png, gif, bmp, 他、くらいの
簡易判定で良ければ、ファイルの内容で判定するとか。
ビットマップ:
先頭 2 バイトが 42,4D。(文字列 "BM")
http://kuwalab.net/technics/bitmap/index.html
JPEG:
先頭 3 バイトが FF,D8,FF。
http://siisise.net/jpeg.html
PNG:
先頭 8 バイトが 89,50,4E,47,0D,0A,1A,0A。
http://www.setsuki.com/hsp/ext/png.htm
GIF:
先頭 6 バイトが 47,49,46,38,39,61。(文字列 "GIF89a")
または
先頭 6 バイトが 47,49,46,38,37,61。(文字列 "GIF87a")
http://uketama.nekopps.com/article/gif_format/#header
> これを VBA で使うための宣言や方法が分からないのです。
こちらは、こんな感じかな。
Option Explicit
Private Declare Function GdiplusStartup Lib "GDIPlus" _
(ByRef hToken As Long, _
ByRef inputBuf As Long, _
ByVal outputBuf As Long) As Long
Private Declare Sub GdiplusShutdown Lib "GDIPlus" _
(ByVal token As Long)
Private Declare Function GdipLoadImageFromFile Lib "GDIPlus" _
(ByVal FileName As Long, _
ByRef hImage As Long) As Long
Private Declare Function GdipDisposeImage Lib "GDIPlus" _
(ByVal hImage As Long) As Long
Private Declare Function GdipGetImageRawFormat Lib "GDIPlus" _
(ByVal hImage As Long, _
ByRef fmt As Currency) As Long
Public Function GetFormat(ByVal FileName As String) As String
Dim ret As Long
Dim hToken As Long
Dim startInfo(3) As Long
startInfo(0) = 1
ret = GdiplusStartup(hToken, startInfo(0), 0&)
If ret <> 0 Then
GetFormat = "Error:" & CStr(ret)
Exit Function
End If
Dim hImage As Long
ret = GdipLoadImageFromFile(StrPtr(FileName), hImage)
If ret <> 0 Then
GetFormat = "Error:" & CStr(ret)
GdiplusShutdown hToken
Exit Function
End If
Dim fmt(1) As Currency
ret = GdipGetImageRawFormat(hImage, fmt(0))
If ret = 0 Then
GetFormat = "Unknown"
If fmt(1) = 338308179558612.8797@ Then
Select Case fmt(0)
Case 128437819022162.2443@
GetFormat = "BMP"
Case 128437819022162.2444@
GetFormat = "EMF"
Case 128437819022162.2445@
GetFormat = "WMF"
Case 128437819022162.2446@
GetFormat = "JPEG"
Case 128437819022162.2447@
GetFormat = "PNG"
Case 128437819022162.2448@
GetFormat = "GIF"
Case 128437819022162.2449@
GetFormat = "TIFF"
Case 128437819022162.2453@
GetFormat = "ICO"
End Select
End If
Else
GetFormat = "Error:" & CStr(ret)
End If
GdipDisposeImage hImage
GdiplusShutdown hToken
End Function
魔界の仮面弁士様
いただいたソースでちゃんと識別することができました!
いつもありがとうございます!!
最初の8バイトさえ読めば分かるんですね。
そのために Currency 型を使うところなどは、感心してしまいました。
fmt の辺りがよく分からないので、よろしければ教えていただけないでしょうか。
GdipGetImageRawFormat(hImage, fmt(0))
で、fmt(0) にファイルの最初の8バイトを格納し、分類しているのだと思うのですが、
If fmt(1) = 338308179558612.8797@ Then
は何をしているのでしょうか??
fmt(1)には他には特に何も処理していないようなので、空なのではないでしょうか?
また、PNG については最初の8バイトから識別できるようですが、
BMP, JPEG, GIF については最初の2〜6バイトですよね。
8バイト読み込んだfmt(0)のうち、最初の2〜6バイトだけを使って
分類しないといけないような気がするのですが、
どうしてうまくいくのでしょうか??
多分、バイトを Currency 型で表現した時の変換ルールが
分からないせいで、理解できないのだと思うのですが。
分からない事だらけですいませんが、教えていただけたら嬉しいです。
> fmt(0) にファイルの最初の8バイトを格納し、分類しているのだと
いえ、違います。
最初に書いた『ファイルの先頭バイトを読む方法』と、
2 番目の『GDIPlus.DLL の API を使う方法』は、まったくの別物です。
> 多分、バイトを Currency 型で表現した時の変換ルールが
> 分からないせいで、理解できないのだと思うのですが。
fmt に入るのは、画像情報を表す GUID 値です。
やたこさんが書かれた「bitmap.RawFormat.Guid」に相当する情報です。
GUID とは、128bit(16バイト)のデータです。
そして VB の 型(Currency) は、64 ビット (8 バイト) の変数です。
ですから、
>> Dim fmt(1) As Currency
とすると、16 バイト分のメモリ領域を確保できるので、ここに、
GUID 構造体の値を受け取っているというわけです。
> If fmt(1) = 338308179558612.8797@ Then
> は何をしているのでしょうか??
GDI+ で扱える各画像の GUID 値は、このようになります。
b96b3cab-0728-11d3-9d7b-0000f81ef32e … Bitmap
b96b3cae-0728-11d3-9d7b-0000f81ef32e … JPEG
b96b3cb0-0728-11d3-9d7b-0000f81ef32e … GIF
b96b3cac-0728-11d3-9d7b-0000f81ef32e … EMF
b96b3cad-0728-11d3-9d7b-0000f81ef32e … WMF
b96b3cb1-0728-11d3-9d7b-0000f81ef32e … TIFF
b96b3caf-0728-11d3-9d7b-0000f81ef32e … PNG
b96b3cb5-0728-11d3-9d7b-0000f81ef32e … ICON
後続 8 バイトの 9d7b-0000f81ef32e が、すべて一致していますよね。
それが
>> If fmt(1) = 338308179558612.8797@ Then
のチェックにあたります。
9d7b-0000f81ef32e というデータを、リトルエンディアンとして並び替えると
2EF31EF800007B9D という 16 進数表現になり、10進数に変換すると、
3383081795586128797 という数値になります。
Currency 型は、これを 1/10000 した値として表現されるので、
338308179558612.8797@ となるわけです。(@ は、Currency の型宣言文字です)
魔界の仮面弁士様
丁寧な解説をいただきましてありがとうございます。
よく分かりました。
自分だけでは解決まで全く見当もつきませんでした。
お力をいただきとても感謝しています。
どうもありがとうございました。