PNG画像はLoadPicture関数でエラーになる
画像の情報を取得する際に使われる関数がLoadPicture関数です。
引数に画像ファイルを渡すと戻り値としてPictureクラス型が返却され、画像の幅と高さをピクセル単位で取得することが出来ます。
ただ、LoadPicture関数はJPEG、GIF、BMPファイルは対応しているのですがPNGファイルには未対応です。PNGファイルを開こうとすると「実行時エラー’481′: ピクチャが不正です。」というエラーメッセージが表示されます。
そこでPNGファイルの場合は別の方法で画像の幅と高さを取得することにします。
どうやってPNGファイルの幅と高さを取得するか
Windowsで扱う多くのファイルは拡張子に従ったファイルフォーマットが存在します。具体的には、バイナリデータの先頭の何バイトかを見ると、そのファイルが何のファイルなのかが分かるような識別子が設定されています。
PNGファイルも同様で、バイナリデータを見ると例えば先頭8バイトは「0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A」で固定されており、2、3、4バイト目の3バイトの「0x50 0x4E 0x47」はASCIIコードでの文字でいうと’P’ ‘N’ ‘G’、即ち、「PNG」と書かれています。
あとは画像の幅と高さですが、17バイト目から20バイト目の4バイトが幅を表し、21バイト目から24バイト目の4バイトが高さを指します。
なので、バイナリデータを取得して16進数を10進数に変換すれば画像の幅と高さのピクセルサイズを取得できます。
PNGファイルの幅と高さを取得するコード
以下の関数は3つの引数があり、1番目のa_sPngPathがPNGファイルのフルパス、2番目のa_lWidthが取得したPNGファイルの幅を返し、3番目のa_lHeightが取得したPNGファイルの高さを返します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Sub GetPngWidthHeight(a_sPngPath As String, a_lWidth As Long, a_lHeight As Long) Dim iFileNo As Integer '// ファイル番号 Dim byData() As Byte '// バイナリデータ '// バイナリデータサイズを24バイト分確保 ReDim byData(23) '// ファイル番号取得 iFileNo = FreeFile '// PNGファイルをバイナリ形式で開く Open a_sPngPath For Binary As #iFileNo '// 先頭から24バイト取得 Get #iFileNo, , byData '// クローズ Close #iFileNo '// 先頭から16バイトがPNGフォーマットの場合 If (byData(0) = 137) And (byData(1) = 80) And (byData(2) = 78) And (byData(3) = 71) And _ (byData(4) = 13) And (byData(5) = 10) And (byData(6) = 26) And (byData(7) = 10) And _ (byData(8) = 0) And (byData(9) = 0) And (byData(10) = 0) And (byData(11) = 13) And _ (byData(12) = 73) And (byData(13) = 72) And (byData(14) = 68) And (byData(15) = 82) Then '// 幅 a_lWidth = byData(16) * 16777216 + byData(17) * 65536 + byData(18) * 256 + byData(19) '// 高さ a_lHeight = byData(20) * 16777216 + byData(21) * 65536 + byData(22) * 256 + byData(23) End If End Sub |
処理概要
詳細はコメントに書いているので処理概要や使い方を補足します。
引数で渡されたPNGファイルのバイナリデータを先頭から24バイト取得します。
先頭から16バイトはPNGファイルを示す固定のデータが設定されているため、If文で各バイト値がPNGファイルフォーマットとして正しいのかをチェックします。
PNGフォーマットの詳細は省略しますが、以下の図の薄緑部分がPNGフォーマットかどうかを判定する16バイトで、黄色部分は幅、オレンジ部分は高さを指します。
PNGファイルフォーマットとして正しければ、幅の4バイトと高さの4バイトから算出して引数に設定します。
使い方は以下のようなコードになります。
1 2 3 4 5 6 7 8 9 |
Sub GetPngWidthHeightTest() Dim w As Long Dim h As Long Call GetPngWidthHeight("C:\test\abc.png", w, h) Debug.Print w Debug.Print h End Sub |
GetPngWidthHeight関数の1番目にPNGファイルのフルパス、2番目にPNGファイルの幅を受け取るLong型変数、3番目に戻り値用のPNGファイルの高さを受け取るLong型変数を指定します。
正しく取得できていればPNGファイルの幅と高さを取得できます。
エラー処理
上記のPNGファイルの幅と高さを取得する関数ですが、引数で渡されたファイルが存在するかどうかのチェックなどは入れていません。
そのあたりが必要な場合は呼び出し元でチェックするか、ファイル存在チェックの処理を追加してください。
なお、ファイルの存在チェックについては「VBAでファイルの存在をチェックする」をご参照ください。