Search code examples
vb.netbitmapgdidib

VB.NET Draw device independent bitmap in picturebox


I reached a dead end with my program. I have in memory a simple array consisting of RGB values of a DIB bitmap (no BITMAPFILEHEADER). This array is generated in C++ but I try to display it in VB.NET . I do not want to use GDI+ because I need raw speed.

This is my code (the image in the file has no header, width:1920 and height:100,24 bits,total size 6220804):

Dim bData As Byte()
Dim br As BinaryReader = New BinaryReader(File.OpenRead("img1.bmp"))
bData = br.ReadBytes(br.BaseStream.Length) 'no headers just raw data


Dim g As Graphics = Me.CreateGraphics() 'System.Drawing.Graphics.FromImage(bmp) 'or PictureBox1.CreateGraphics()
Dim hdc As IntPtr = g.GetHdc()

Dim bmi As New BITMAPINFO
bmi.bmiheader = New BITMAPINFOHEADER

'Now we fill up the bmi (Bitmap information variable) with all the necessary data
bmi.bmiheader.biSize = 40 'Size, in bytes, of the header (always 40)
bmi.bmiheader.biPlanes = 1 'Number of planes (always one)
bmi.bmiheader.biBitCount = 24 'Bits per pixel (always 24 for image processing)
bmi.bmiheader.biCompression = 0 'Compression: none or RLE (always zero)
bmi.bmiheader.biWidth = 1920
bmi.bmiheader.biHeight = 100
bmi.bmiheader.biSizeImage = 6220804

Dim memHDC As IntPtr = CreateCompatibleDC(hdc)

StretchDIBits(memHDC, 0, 0, 1920, 100, 0, 0, 1920, 100, bData, bmi, 0, 13369376)   ' Copy RGB values on an intermediary HDC
BitBlt(hdc, 0, 0, 1920, 100, memHDC, 0, 0, 13369376)    'Print directly from the memHDC

Here are my structures:

<StructLayout(LayoutKind.Sequential)>
Structure RGBQUAD
    Public rgbBlue As Byte
    Public rgbGreen As Byte
    Public rgbRed As Byte
    Public rgbReserved As Byte
End Structure

<StructLayout(LayoutKind.Sequential)>
Private Class BITMAPINFOHEADER
    Public biSize As Int32
    Public biWidth As Int32
    Public biHeight As Int32
    Public biPlanes As Int16
    Public biBitCount As Int16
    Public biCompression As Int32
    Public biSizeImage As Int32
    Public biXPelsPerMeter As Int32
    Public biYPelsPerMeter As Int32
    Public biClrUsed As Int32
    Public biClrImportant As Int32
End Class

<StructLayout(LayoutKind.Sequential)>
Private Structure BITMAPINFO
    Dim bmiheader As BITMAPINFOHEADER
    Dim bmiColors As RGBQUAD
End Structure

I tested almost every possible combination of variables,HDCs and graphics. Nothing works! Where am I failling?

NOTE: StretchDIBits and BitBlt seems to succed


Solution

  • I found a solution. I think the problem arises from the fact that CreateCompatibleDC creates a one pixel by one pixel grid. Because of this limitation I simply used StretchDIBits on the picture box's HDC:

    Dim bData As Byte()
    Dim br As BinaryReader = New BinaryReader(File.OpenRead("img1_arr.bmp"))
    bData = br.ReadBytes(br.BaseStream.Length)
    
    Dim g As Graphics = PictureBox1.CreateGraphics() 'or Me.CreateGraphics()
    Dim dsthdc As IntPtr = g.GetHdc()
    
    Dim bmi As New BITMAPINFO
    bmi.bmiheader = New BITMAPINFOHEADER
    
    'Now we fill up the bmi (Bitmap information variable) with all the necessary data
    bmi.bmiheader.biSize = 40 'Size, in bytes, of the header (always 40)
    bmi.bmiheader.biPlanes = 1 'Number of planes (always one)
    bmi.bmiheader.biBitCount = 24 'Bits per pixel (always 24 for image processing)
    bmi.bmiheader.biCompression = 0 'Compression: none or RLE (always zero)
    bmi.bmiheader.biWidth = 1920
    bmi.bmiheader.biHeight = 1080
    bmi.bmiheader.biSizeImage = 6220804
    
    
    StretchDIBits(dsthdc, 0, 0, 1920, 1080, 0, 0, 1920, 1080, bData, bmi, 0, SRCCOPY)
    

    Of course the example uses fixed values only for test purposes. It works flawlessly.