|
-
Oct 5th, 2002, 03:44 AM
#1
Thread Starter
Frenzied Member
BitMap to Bytes - An Attempt
Hi!
A lot of times it has been asked, yours truly inlcuded, how a Bitmap in an app can be serialized into a byte array. Given below is an attempt modifying an example from All-API Guide. Hope this provides a start to all of you. The array is now written to disk. But can be sent directly through Winsock for network tranfer.
VB Code:
'The Sending App, containing a PictureBox and a Command Button
'ScaleMode of the Form and the PictureBox set to Pixels
Private Const BI_RGB = 0&
Private Const DIB_RGB_COLORS = 0
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBQUAD
End Type
Private Declare Function CreateCompatibleDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" _
(ByVal hdc As Long, pBitmapInfo As BITMAPINFO, _
ByVal un As Long, ByVal lplpVoid As Long, _
ByVal handle As Long, ByVal dw As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" _
(ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan _
As Long, ByVal nNumScans As Long, lpBits As Any, _
lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function SelectObject Lib "gdi32" _
(ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" _
(ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" _
(ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" _
(ByVal hDestDC As Long, ByVal x As Long, ByVal y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC _
As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
ByVal dwRop As Long) As Long
Private Declare Function GetDC Lib "user32" _
(ByVal hwnd As Long) As Long
Dim iBitmap As Long, iDC As Long
Private Sub Command1_Click()
Dim bi24BitInfo As BITMAPINFO, bBytes() As Byte
With bi24BitInfo.bmiHeader
.biBitCount = 24
.biCompression = BI_RGB
.biPlanes = 1
.biSize = Len(bi24BitInfo.bmiHeader)
.biWidth = Picture1.Width
.biHeight = Picture1.Height
End With
ReDim bBytes(1 To bi24BitInfo.bmiHeader.biWidth * _
bi24BitInfo.bmiHeader.biHeight * 3) As Byte
iDC = CreateCompatibleDC(0)
iBitmap = CreateDIBSection(iDC, bi24BitInfo, _
DIB_RGB_COLORS, ByVal 0&, ByVal 0&, ByVal 0&)
SelectObject iDC, iBitmap
BitBlt iDC, 0, 0, bi24BitInfo.bmiHeader.biWidth, _
bi24BitInfo.bmiHeader.biHeight, Picture1.hdc, 0, 0, _
vbSrcCopy
GetDIBits iDC, iBitmap, 0, _
bi24BitInfo.bmiHeader.biHeight, bBytes(1), _
bi24BitInfo, DIB_RGB_COLORS
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
Put #1, 1, CLng(Picture1.Width)
Put #1, 5, CLng(Picture1.Height)
Put #1, 9, bBytes
Close #1
DeleteDC iDC
DeleteObject iBitmap
Client.Show 'Run the client App. I used two forms in the same app
End Sub
Private Sub Form_Load()
Me.ScaleMode = vbPixels
With Picture1
.ScaleMode = vbPixels
.AutoRedraw = True
.AutoSize = True
.Picture = LoadPicture(App.Path & "\Clouds.bmp")
End With
End Sub
'The recieving App containing a pictureBox with a command button
'with the form and picturebox scalemode set to Pixels and
'autoredraw, autosize of the pictureBox set to true
Private Declare Function SetDIBitsToDevice Lib "gdi32" _
(ByVal hdc As Long, ByVal x As Long, ByVal y As Long, _
ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, _
ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans _
As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage _
As Long) As Long
Private Const BI_RGB = 0&
Private Const DIB_RGB_COLORS = 0
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBQUAD
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
rgbReserved As Byte
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBQUAD
End Type
Private Sub Command1_Click()
Dim bi24BitInfo As BITMAPINFO, bmpWidth As Long, _
bmpHeight As Long
Dim bbBytes() As Byte
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
ReDim bbBytes(1 To (LOF(1) - 8))
Get #1, 1, bmpWidth
Get #1, 5, bmpHeight
Get #1, 9, bbBytes
Close #1
With bi24BitInfo.bmiHeader
.biBitCount = 24
.biCompression = BI_RGB
.biPlanes = 1
.biSize = Len(bi24BitInfo.bmiHeader)
.biWidth = bmpWidth
.biHeight = bmpHeight
End With
Picture1.Width = bmpWidth
Picture1.Height = bmpHeight
SetDIBitsToDevice Picture1.hdc, 0, 0, _
bi24BitInfo.bmiHeader.biWidth, _
bi24BitInfo.bmiHeader.biHeight, 0, 0, 0, _
bi24BitInfo.bmiHeader.biHeight, bbBytes(1), _
bi24BitInfo, DIB_RGB_COLORS
Picture1.AutoSize = True
Picture1.Refresh
End Sub
Private Sub Form_Load()
Me.ScaleMode = vbPixels
Picture1.ScaleMode = vbPixels
End Sub
Last edited by KayJay; Oct 5th, 2002 at 05:11 AM.
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
-
Oct 5th, 2002, 06:21 AM
#2
Fanatic Member
you can convert a bitmap to a byte array with the GetBitmapBits API
Add a picturebox with a picture in it, and a command button
VB Code:
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Sub Command1_Click()
Dim hbm As Long
Dim bm As BITMAP
Dim status As Long
Dim bytes() As Byte
Dim i As Long
Dim j As Long
Dim wid As Long
Dim hgt As Long
hbm = Picture1.Image
'-- Get status of bitmap
status = GetObject(hbm, Len(bm), bm)
'-- Get the Bits
wid = bm.bmWidthBytes
hgt = bm.bmHeight
ReDim bytes(1 To wid, 1 To hgt)
status = GetBitmapBits(hbm, wid * hgt, bytes(1, 1))
'-- We now have the entire bitmap in our Byte Array
'-- And if you want to modify the image ( makes it darker )
For i = 1 To wid
For j = 1 To hgt
bytes(i, j) = bytes(i, j) / 2
Next j
Next i
'-- Set the Bits
status = SetBitmapBits(hbm, wid * hgt, bytes(1, 1))
End Sub
-
Oct 5th, 2002, 06:49 AM
#3
Thread Starter
Frenzied Member
Thanks for that
I tried the following
VB Code:
'First App
Picture1.Picture = LoadPicture(App.Path & "\Clouds.bmp")
Dim hbm As Long
Dim bm As BITMAP
Dim status As Long
Dim bytes() As Byte
Dim i As Long
Dim j As Long
Dim wid As Long
Dim hgt As Long
hbm = Picture1.Image
'-- Get status of bitmap
status = GetObject(hbm, Len(bm), bm)
'-- Get the Bits
wid = bm.bmWidthBytes
hgt = bm.bmHeight
ReDim bytes(1 To wid, 1 To hgt)
status = GetBitmapBits(hbm, wid * hgt, bytes(1, 1))
'-- We now have the entire bitmap in our Byte Array
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
Put #1, 1, CLng(wid)
Put #1, 5, CLng(hgt)
Put #1, 9, bytes
Close #1
Client.Show
'Second App
Private Sub Command1_Click()
Dim bmpWidth As Long, bmpHeight As Long
Dim bbBytes() As Byte
Dim hbm As Long
hbm = Picture1.Image
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
Get #1, 1, bmpWidth
Get #1, 5, bmpHeight
Close #1
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
ReDim bbBytes(1 To bmpWidth, 1 To bmpHeight)
Get #1, 9, bbBytes
Close #1
status = SetBitmapBits(hbm, bmpWidth * bmpHeight, bbBytes(1, 1))
Picture1.AutoSize = True
Picture1.Refresh
I get just a series of white, green and blue horizontal lines in the second form/app
Where am I wrong?
Thanks
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
-
Oct 5th, 2002, 07:33 AM
#4
Fanatic Member
hmmm thats interesting, the image gets badly distorted
yet the file contents matches the byte array
I made the byte array to a single dimensional array ( redim bytes(1 to wid*hgt) ) thinking that could be the problem, yet it still distorts
Ive tried removing the width and height ( 8 bytes ) from the start of the file and loading it, still distorts
Ive done a comparison between the file data and the bytes, and its exactly the same
im stumped
-
Oct 5th, 2002, 07:45 AM
#5
Thread Starter
Frenzied Member
Will try some more and keep you posted
Ta
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
-
Oct 5th, 2002, 08:16 AM
#6
Thread Starter
Frenzied Member
API Guide to the rescue again!
The dimensioning of the array is like so. So says an example from the ALL API Guide.
VB Code:
BytesPerLine = (PicInfo.bmWidth * 3 + 3) And &HFFFFFFFC
ReDim PicBits(1 To BytesPerLine * PicInfo.bmHeight * 3) As Byte
This one works ok for me.
VB Code:
'Form One
Dim PicBits() As Byte, PicInfo As BITMAP
Dim BytesPerLine As Long
Picture1.Picture = LoadPicture(App.Path & "\Clouds.bmp")
GetObject Picture1.Image, Len(PicInfo), PicInfo
BytesPerLine = (PicInfo.bmWidth * 3 + 3) And &HFFFFFFFC
ReDim PicBits(1 To BytesPerLine * PicInfo.bmHeight * 3) As Byte
GetBitmapBits Picture1.Image, UBound(PicBits), PicBits(1)
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
Put #1, 1, CLng(Picture1.Width)
Put #1, 5, CLng(Picture1.Height)
Put #1, 9, PicBits
Close #1
Client.Show
End Sub
'Client Form
Dim bmpWidth As Long, bmpHeight As Long, bbBytes() As Byte
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
Get #1, 1, bmpWidth
Get #1, 5, bmpHeight
Close #1
Picture1.Width = bmpWidth
Picture1.Height = bmpHeight
Open App.Path & "\CloudsCopy.BMP" For Binary As #1
ReDim bbBytes(1 To LOF(1) - 8)
Get #1, 9, bbBytes
Close #1
SetBitmapBits Picture1.Image, UBound(bbBytes), bbBytes(1)
Picture1.Refresh
Looks all right?
Last edited by KayJay; Oct 5th, 2002 at 08:20 AM.
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
-
Dec 27th, 2002, 09:59 AM
#7
Lively Member
Try this:
VB Code:
' Global Memory Flags
Const GMEM_MOVEABLE = &H2
Const GMEM_ZEROINIT = &H40
Const GHND = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
Private Declare Function GlobalAlloc Lib "kernel32" ( _
ByVal wFlags As Long, _
ByVal dwBytes As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" ( _
ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" ( _
ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" ( _
ByVal hMem As Long) As Long
Const PictureID = &H746C&
Private Type PictureHeader
Magic As Long
Size As Long
End Type
Public Sub Picture2Array(ByVal oObj As StdPicture, aBytes() As Byte)
Dim oIPS As IPersistStream
Dim oStream As IStream
Dim hGlobal As Long
Dim lPtr As Long
Dim lSize As Long
Dim Hdr As PictureHeader
' Get the IPersistStream interface
Set oIPS = oObj
' Create a IStream object
' on global memory
Set oStream = CreateStreamOnHGlobal(0, True)
' Save the picture in the stream
oIPS.Save oStream, True
' Get the global memory handle
' from the stream
hGlobal = GetHGlobalFromStream(oStream)
' Get the memory size
lSize = GlobalSize(hGlobal)
' Get a pointer to the memory
lPtr = GlobalLock(hGlobal)
If lPtr Then
lSize = lSize - Len(Hdr)
' Redim the array
ReDim aBytes(0 To lSize - 1)
' Copy the data to the array
MoveMemory aBytes(0), ByVal lPtr + Len(Hdr), lSize
End If
' Release the pointer
GlobalUnlock hGlobal
' Release the IStream object
Set oStream = Nothing
End Sub
-
Dec 27th, 2002, 10:17 AM
#8
Thread Starter
Frenzied Member
cool
Thanx pal. That project's now over. But this is being added to my arsenal of VBForums Code Snippets.
Cheers and Good Luck
"Brothers, you asked for it."
...Francisco Domingo Carlos Andres Sebastian D'Anconia
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|