BMPから画像データを抽出するには?

解決


ジムニー  2008-12-03 22:18:43  No: 141000  IP: 192.*.*.*

いつもお世話になっています。
VB6を使用しています。

前回の質問でGetPixelを用いたピクセルごとのRGB値を取得することはできました。今は↓のサイトの
http://imagingsolution.blog107.fc2.com/blog-category-1.html#pagetop
VB6.0でビットマップファイルを開くのプログラムを参考にしてフォーマット解析を試みています。

BMPファイルの全体の構造も理解したつもりなのですが、画像データの所でつまづいています。
lpBits() As Byte
にデータが入っていると思われるのですが、どうすると各ピクセルの値が返ってくるのでしょうか?

'//----------------------------------------------------------------------------------------------------------
'//【関数名  】:LoadBitmapData
'//【処理概要】:ピットマップファイルデータの読込
'//【引数    】:strBitmapFileName  = ビットマップのファイルネーム
'//            :lpFileFeader       = ビットマップファイルのBITMAPFILEHEADER(戻り)
'//            :lpBitsInfo         = ビットマップファイルのBITMAPINFO(戻り)
'//            :lpBits()           = ビットマップファイルの画像データ配列(戻り)
'//【戻り値  】:0  =  正常終了
'//            :-1 =  ファイル読込失敗
'//【備考    】:
'//            :
'//----------------------------------------------------------------------------------------------------------
Public Function LoadBitmapData(strBitmapFileName As String, lpFileHeader As BITMAPFILEHEADER, lpBitsInfo As BITMAPINFO, lpBits() As Byte) As Long

    Dim i   As Integer
    Dim ret As Long
    Dim No  As Integer
    
    '戻り値の初期値
    LoadBitmapData = -1

    'ファイル名が指定されなかった場合
    If (strBitmapFileName = "") Then Exit Function
    
    If LCase(Right(strBitmapFileName, 3)) = "bmp" Then
        'ファイルがビットマップファイルのとき

        'ビットマップファイルをバイナリで開く
        No = FreeFile()
        Open strBitmapFileName For Binary As #No
        
            Get #No, , lpFileHeader
            If lpFileHeader.bfType <> &H4D42 Then    ' BM
                'ビットマップではない
                MsgBox "ビットマップファイル形式ではありません。"
                Close
                Exit Function
            End If
            Get #No, , lpBitsInfo.bmiHeader
            With lpBitsInfo.bmiHeader
                If lpFileHeader.bfOffBits <> Len(lpFileHeader) + Len(lpBitsInfo.bmiHeader) Then 'カラーテーブルにデータがあるとき
                    '8Bit以下の場合カラーテーブルを読み込む
                    Get #No, , lpBitsInfo.bmiColors
                End If
                'ReDim lpBits(((.biWidth * .biBitCount + 31) \ 32) * 4 - 1, Abs(.biHeight) - 1) As Byte ' バイト数を計算(4バイト単位幅)
                ReDim lpBits(100, 100) As Byte
            End With
            Seek #No, lpFileHeader.bfOffBits + 1  ' ピクセルビットのポインタへ移動
            Get #No, , lpBits
        Close #No
'確認の為付け足し'''''''''''''''''''''''''''''''''''''''''''''''''''
        For j = 0 To Abs(.biHeight) - 1
        For i = 0 To ((.biWidth * .biBitCount + 31) \ 32) * 4 - 1
        Form1.Text1.SelText = lpBits(i, j) & " "
        Next i
        Form1.Text1.SelText = vbCrLf
        Next j
        End With
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    End If

    '正常終了
    LoadBitmapData = 0
    
    Exit Function
        
LoadFileError:
    'エラー処理
    MsgBox "ファイル " & strBitmapFileName & " を読み込めません。"
    Exit Function
End Function

text1に表示されるのは
248 0 0 0 
80 0 0 0 
168 0 0 0 
80 0 0 0 
168 0 0 0 
このようになっています。

編集 削除
紅閃光  2008-12-04 14:20:50  No: 141001  IP: 192.*.*.*

この問題は、VB6上の多次元配列が、メモリ上にどのように保持されるかを理解しなければ始まりません。
とりあえずC言語向けですが、以下のサイトが参考になるかと思います。
http://ysserve.int-univ.com/sugsi/Lecture/c2/e_04-04-04.html
http://www.e-chishiki.com/jpn/articles/programming_languages/c/arrays/memory_map_of_a_2_dimensional_array

というか、なんでもともとあった下記の行をコメントアウトしているのですか?
ReDim lpBits(((.biWidth * .biBitCount + 31) \ 32) * 4 - 1, Abs(.biHeight) - 1) As Byte ' バイト数を計算(4バイト単位幅)
この行はビットマップファイルの構造にあわせてコーディングされているのですが。

ReDim lpBits(100, 100) As Byte
これではビットマップファイルの構造に合いませんよ。

編集 削除
ジムニー  2008-12-04 19:15:14  No: 141002  IP: 192.*.*.*

自力で解決できました。

ReDim lpBits(((.biWidth * .biBitCount + 31) \ 32) * 4 - 1, Abs(.biHeight) - 1) As Byte 
をコメントアウトした理由としては自分が思っていた値が出力されなかったので理解できていない箇所を置換えでいたんです。

BMPのカラーパレットやバイトの考え方が間違っていたのでおかしな値だと思っていました。

編集 削除
ジムニー  2008-12-04 19:16:26  No: 141003  IP: 192.*.*.*

お騒がせしました

編集 削除