J
Jon Brunson
After doing a LOT of research into saving Bitmaps and/or getting byte
arrays out of them, I finally found the "Graphic Object Internals"
article on the OpenNETCF forum
(http://www.opennetcf.org/Forums/forum.asp?FORUM_ID=22). Unfortunately,
this method doesn't work for Bitmap's created using the width-height
contstructor, only those loaded from file.
I did find a thread which discusses this problem, and found a potential
solution - http://www.opennetcf.org/Forums/topic.asp?TOPIC_ID=385
After converting the code posted to VB.NET (see end of post) so I could
use it in my project, I got an OverflowException on the line:
BitmapData(2) = CByte(nBytes)
which makes sence, because nBytes is in the region of 54,000, and bytes
only go up to 255.
But surely bitmaps can be larger than 256 bytes?
Am I missing something?
Code (be careful of word-wrap):
Public Shared Sub SaveBitmap(ByVal Image As System.Drawing.Image, ByVal
Path As String)
Dim fs As FileStream = File.Create(Path)
SaveBitmap(Image, fs)
fs.Close()
End Sub
Public Shared Sub SaveBitmap(ByVal Image As System.Drawing.Image, ByVal
Stream As System.IO.Stream)
' This should probably be done a little more carefully
Dim bm As Bitmap = CType(Image, Bitmap)
Const BYTES_PER_PIXEL As Integer = 3
' Need 0x36 bytes for the headers, plus all of the pixel data, so
round up to nearest 4
Dim nBytes As Integer = 54 + (bm.Height * ((BYTES_PER_PIXEL *
bm.Width) + 3) And Not 3)
Dim BitmapData(nBytes) As Byte
BitmapData(0) = System.Text.Encoding.UTF8.GetBytes(New Char() {"B"c})(0)
BitmapData(1) = System.Text.Encoding.UTF8.GetBytes(New Char() {"M"c})(0)
' I'm sure there's a better way to do this but I didn't look up the C#
equiv of memcpy
BitmapData(2) = CByte(nBytes)
BitmapData(3) = CByte((nBytes >> 8))
BitmapData(4) = CByte((nBytes >> 16))
BitmapData(5) = CByte((nBytes >> 24))
BitmapData(10) = 54
BitmapData(14) = 40
BitmapData(18) = CByte(bm.Width)
BitmapData(19) = CByte((bm.Width >> 8))
BitmapData(20) = CByte((bm.Width >> 16))
BitmapData(21) = CByte((bm.Width >> 24))
BitmapData(22) = CByte(bm.Height)
BitmapData(23) = CByte((bm.Height >> 8))
BitmapData(24) = CByte((bm.Height >> 16))
BitmapData(25) = CByte((bm.Height >> 24))
BitmapData(26) = 1
BitmapData(28) = 24
BitmapData(34) = CByte((nBytes - 54))
BitmapData(35) = CByte(((nBytes - 54) >> 8))
BitmapData(36) = CByte(((nBytes - 54) >> 16))
BitmapData(37) = CByte(((nBytes - 54) >> 24))
' Stripping bitmap from bottom left, moving right through the row,
then up to the next row
Dim index As Integer = 54
Dim h As Integer = bm.Height - 1
While h >= 0
Dim w As Integer = 0
While w < bm.Width
Dim c As Integer = bm.GetPixel(w, h).ToArgb
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType(c, Byte)
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType((c >> 8), Byte)
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType((c >> 16), Byte)
System.Math.Min(System.Threading.Interlocked.Increment(w), w - 1)
End While
' Padding the end of the row
' (if I RTFM'd this wouldn't have taken so long to figure out
Dim xtra As Integer = (bm.Width * 3) Mod 4
If Not (xtra = 0) Then
index += 4 - xtra
End If
System.Math.Max(System.Threading.Interlocked.Decrement(h), h + 1)
End While
' Write the bytes to the stream
Stream.Write(BitmapData, 0, BitmapData.Length)
End Sub
arrays out of them, I finally found the "Graphic Object Internals"
article on the OpenNETCF forum
(http://www.opennetcf.org/Forums/forum.asp?FORUM_ID=22). Unfortunately,
this method doesn't work for Bitmap's created using the width-height
contstructor, only those loaded from file.
I did find a thread which discusses this problem, and found a potential
solution - http://www.opennetcf.org/Forums/topic.asp?TOPIC_ID=385
After converting the code posted to VB.NET (see end of post) so I could
use it in my project, I got an OverflowException on the line:
BitmapData(2) = CByte(nBytes)
which makes sence, because nBytes is in the region of 54,000, and bytes
only go up to 255.
But surely bitmaps can be larger than 256 bytes?
Am I missing something?
Code (be careful of word-wrap):
Public Shared Sub SaveBitmap(ByVal Image As System.Drawing.Image, ByVal
Path As String)
Dim fs As FileStream = File.Create(Path)
SaveBitmap(Image, fs)
fs.Close()
End Sub
Public Shared Sub SaveBitmap(ByVal Image As System.Drawing.Image, ByVal
Stream As System.IO.Stream)
' This should probably be done a little more carefully
Dim bm As Bitmap = CType(Image, Bitmap)
Const BYTES_PER_PIXEL As Integer = 3
' Need 0x36 bytes for the headers, plus all of the pixel data, so
round up to nearest 4
Dim nBytes As Integer = 54 + (bm.Height * ((BYTES_PER_PIXEL *
bm.Width) + 3) And Not 3)
Dim BitmapData(nBytes) As Byte
BitmapData(0) = System.Text.Encoding.UTF8.GetBytes(New Char() {"B"c})(0)
BitmapData(1) = System.Text.Encoding.UTF8.GetBytes(New Char() {"M"c})(0)
' I'm sure there's a better way to do this but I didn't look up the C#
equiv of memcpy
BitmapData(2) = CByte(nBytes)
BitmapData(3) = CByte((nBytes >> 8))
BitmapData(4) = CByte((nBytes >> 16))
BitmapData(5) = CByte((nBytes >> 24))
BitmapData(10) = 54
BitmapData(14) = 40
BitmapData(18) = CByte(bm.Width)
BitmapData(19) = CByte((bm.Width >> 8))
BitmapData(20) = CByte((bm.Width >> 16))
BitmapData(21) = CByte((bm.Width >> 24))
BitmapData(22) = CByte(bm.Height)
BitmapData(23) = CByte((bm.Height >> 8))
BitmapData(24) = CByte((bm.Height >> 16))
BitmapData(25) = CByte((bm.Height >> 24))
BitmapData(26) = 1
BitmapData(28) = 24
BitmapData(34) = CByte((nBytes - 54))
BitmapData(35) = CByte(((nBytes - 54) >> 8))
BitmapData(36) = CByte(((nBytes - 54) >> 16))
BitmapData(37) = CByte(((nBytes - 54) >> 24))
' Stripping bitmap from bottom left, moving right through the row,
then up to the next row
Dim index As Integer = 54
Dim h As Integer = bm.Height - 1
While h >= 0
Dim w As Integer = 0
While w < bm.Width
Dim c As Integer = bm.GetPixel(w, h).ToArgb
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType(c, Byte)
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType((c >> 8), Byte)
BitmapData(System.Math.Min(System.Threading.Interlocked.Increment(index),
index - 1)) = CType((c >> 16), Byte)
System.Math.Min(System.Threading.Interlocked.Increment(w), w - 1)
End While
' Padding the end of the row
' (if I RTFM'd this wouldn't have taken so long to figure out
Dim xtra As Integer = (bm.Width * 3) Mod 4
If Not (xtra = 0) Then
index += 4 - xtra
End If
System.Math.Max(System.Threading.Interlocked.Decrement(h), h + 1)
End While
' Write the bytes to the stream
Stream.Write(BitmapData, 0, BitmapData.Length)
End Sub