Thanks you SOOO much in advance,
-Tim
using System;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
namespace SaveThisImage
{
/// <summary>
/// Summary description for BitmapSaver.
/// </summary>
public class BitmapSaver
{
/// <summary>
/// Saves an image (image) at the location defined (szPath). This uses the
generic
/// 24-bit format, so the image is not compressed.
/// </summary>
/// <param name="image">The bitmap image to store</param>
/// <param name="szPath">The path to save at</param>
static public void SaveBitmapToFile(Image image, string szPath)
{
FileStream fs = File.Create(szPath);
SaveBitmapToStream(image, fs);
fs.Close();
}
/// <summary>
/// Saves an image (image) at the location defined (szPath). This uses the
generic
/// 24-bit format, so the image is not compressed.
/// </summary>
/// <param name="image">The bitmap image to store</param>
/// <param name="stream">The stream to save to</param>
static public void SaveBitmapToStream(Image image, Stream stream)
{
/*
* Sort of from
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_4v1h.asp.
* The below is hardcoded to support saving a 24-bit bitmap. Slight changes
would be made to certain
* constants in order to save 16-bit or 256-color (8-bit) or whatever. The
resulting file is probably
* the largest of any image format, which is at the benefit of speed. There
are other ways of saving
* bitmaps (such as using color indexing) which will reduce the bitmap size,
but they also add
* performance hits.
*
* ---Data--- ---Bytes---
* "BM" 0x00-0x01
* File Size 0x02-0x05
* Reserved 1 0x06-0x07
* Reserved 2 0x08-0x09
* Constant 0x36 0x0A
* Constant 0x00 0x0B-0x0D
* Constant 0x28 0x0E (This byte is always 0x28)
* Constant 0x00 0x0F-0x11 (These bytes are always 0x00)
* Bitmap Width 0x12-0x15
* Bitmap Height 0x16-0x19
* Constant 0x01 0x1A
* Constant 0x00 0x1B
* Constant 0x18 0x1C
* Constant 0x00 0x1D-0x21
* Image byte size 0x22-0x25
* Constant 0x00 0x26-0x35
* Pixels 0x36-Rest
* These are 3-byte RGB values for pixels starting at bottom left, moving
right.
* They are in G-B-R order, and you have to remember to make the full stride
(row) a
* multiple of 4, meaning that if you have a width of 3, that's only 9 bytes
and you
* have to pad with 3 to round it to the next multiple of 4.
*/
// This should probably be done a little more carefully
Bitmap bm = (Bitmap) image;
const int BYTES_PER_PIXEL = 3;
// Need 0x36 bytes for the headers, plus all of the pixel data, so round up
to nearest 4
int nBytes = 0x36 + (bm.Height * ((BYTES_PER_PIXEL * bm.Width) + 0x03) &
~0x03);
byte[] BitmapData = new byte[nBytes];
BitmapData[0x00] = (byte) 'B';
BitmapData[0x01] = (byte) 'M';
// I'm sure there's a better way to do this but I didn't look up the C#
equiv of memcpy
BitmapData[0x02] = (byte) nBytes;
BitmapData[0x03] = (byte) (nBytes >> 8);
BitmapData[0x04] = (byte) (nBytes >> 16);
BitmapData[0x05] = (byte) (nBytes >> 24);
BitmapData[0x0A] = 0x36;
BitmapData[0x0E] = 0x28;
BitmapData[0x12] = (byte) bm.Width;
BitmapData[0x13] = (byte) (bm.Width >> 8);
BitmapData[0x14] = (byte) (bm.Width >> 16);
BitmapData[0x15] = (byte) (bm.Width >> 24);
BitmapData[0x16] = (byte) bm.Height;
BitmapData[0x17] = (byte) (bm.Height >> 8);
BitmapData[0x18] = (byte) (bm.Height >> 16);
BitmapData[0x19] = (byte) (bm.Height >> 24);
BitmapData[0x1A] = 0x01;
BitmapData[0x1C] = 0x18;
BitmapData[0x22] = (byte) (nBytes - 0x36);
BitmapData[0x23] = (byte) ((nBytes - 0x36) >> 8);
BitmapData[0x24] = (byte) ((nBytes - 0x36) >> 16);
BitmapData[0x25] = (byte) ((nBytes - 0x36) >> 24);
// Stripping bitmap from bottom left, moving right through the row, then up
to the next row
int index = 0x36;
for (int h = bm.Height - 1; h >= 0; h--)
{
for (int w = 0; w < bm.Width; w++)
{
int c = bm.GetPixel(w, h).ToArgb();
BitmapData[index++] = (byte) c;
BitmapData[index++] = (byte) (c >> 8);
BitmapData[index++] = (byte) (c >> 16);
}
// Padding the end of the row
// (if I RTFM'd this wouldn't have taken so long to figure out :-)
int xtra = (bm.Width * 3) % 4;
if (xtra != 0)
{
index += 4 - xtra;
}
}
// Write the bytes to the stream
stream.Write(BitmapData, 0, BitmapData.Length);
}
}
}
Pete
--
Pete Vickers
Microsoft Windows Embedded MVP
HP Business Partner - Compaq Solutions Alliance
http://www.gui-innovations.com
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:etEFBzxK...@TK2MSFTNGP12.phx.gbl...
Thank you anyway,
-Timothy
"Pete Vickers" <pete at gui - innovations dot com> wrote in message
news:%23gsvv9y...@TK2MSFTNGP12.phx.gbl...
Hope it is of use.
Bob
Imports System.IO
Imports System.Runtime.InteropServices
Module BMP
Public Function SaveBMP(ByVal theBMP As Bitmap, ByVal filename As String) As
Boolean
'Given a bitmap, which could be from a PictureBox (picturebox.image), saves
the images to
'filename (of .bmp file format)
Dim c As Color
Dim pad As Boolean = theBMP.Width Mod 2 = 1, p As Long = 0
Dim padding As Short = 0
If pad Then padding = 1
Dim pixels(theBMP.Height * (theBMP.Width + padding) * 3) As Byte
Dim x As Long, y As Long
For y = theBMP.Height - 1 To 0 Step -1
For x = 0 To theBMP.Width - 1
c = theBMP.GetPixel(x, y)
pixels(p) = c.B
p += 1
pixels(p) = c.G
p += 1
pixels(p) = c.R
p += 1
Next
If pad Then
p += 3
End If
Next
Dim outBmp As Byte()
outBmp = CreateBitmap(theBMP.Width, theBMP.Height, pixels)
Dim fs As New FileStream(filename, FileMode.OpenOrCreate)
' Create the writer for data.
Dim w As New BinaryWriter(fs)
w.Write(outBmp)
w.Close()
fs.Close()
SaveBMP = True
End Function
Dim sizeBFH As Integer = 14 'sizeof(BITMAPFILEHEADER)
Private Function CreateBitmap(ByVal width As Integer, ByVal height As
Integer, ByVal bitmapData As Byte()) As Byte()
' Calculate bitmap size - 3 bytes per pixel
' Bitmap scanlines must be aligned at 16 bit boundary.
Dim padding As Short = 0
If (width Mod 2) = 1 Then
'Throw New ArgumentException("Width must be an even number")
padding = 1
End If
Dim WidthHelper As Long = (width * 3) + (width Mod 4)
Dim nSize As Integer = sizeBFH + Marshal.SizeOf(New BITMAPINFOHEADER) +
(width + padding) * height * 3
Dim data() As Byte = New Byte(nSize) {}
Dim bfh() As Byte = New Byte(sizeBFH) {}
BitConverter.GetBytes(CInt(&H4D42)).CopyTo(data, 0)
BitConverter.GetBytes(nSize).CopyTo(data, 2)
Dim bfhOffBits As Integer = CType((sizeBFH + Marshal.SizeOf(New
BITMAPINFOHEADER)), Integer)
BitConverter.GetBytes(bfhOffBits).CopyTo(data, 10)
Dim bi As BITMAPINFOHEADER = New BITMAPINFOHEADER
bi.biSize = System.Convert.ToUInt32(Marshal.SizeOf(bi))
bi.biBitCount = Convert.ToUInt16(24) ' Creating RGB bitmap. The following
three members don't matter
bi.biClrUsed = Convert.ToUInt32(0)
bi.biClrImportant = Convert.ToUInt32(0)
bi.biCompression = Convert.ToUInt32(0)
bi.biHeight = height
bi.biWidth = width
bi.biPlanes = Convert.ToUInt16(1)
Dim cb As Integer = (CLng(bi.biHeight) * CLng(bi.biWidth + padding) *
System.Convert.ToInt32(bi.biBitCount) / 8) '8 is bits per byte
bi.biSizeImage = System.Convert.ToUInt32(cb)
bi.biXPelsPerMeter = &HB12 ' 72 ppi, 96 would work well too
bi.biYPelsPerMeter = &HB12 ' 72 ppi
Dim hdr() As Byte = GetBytes(bi)
Buffer.BlockCopy(hdr, 0, data, sizeBFH, hdr.Length)
Buffer.BlockCopy(bitmapData, 0, data, bfhOffBits,
System.Math.Min(bitmapData.Length, cb))
Return data
End Function
' This works only for default-aligned structure.
' It does not work for BITMAPFILEHEADER because bfSize is not aligned to
DWORD boundary
' Unfortunately CF does not allow specifying structure member alignment
Private Function GetBytes(ByVal o As Object) As Byte()
Dim size As Integer = Marshal.SizeOf(o.GetType())
Dim p As IntPtr = LocalAlloc(GPTR, size)
Marshal.StructureToPtr(o, p, False)
Dim ret() As Byte = New Byte(size) {}
Marshal.Copy(p, ret, 0, size)
LocalFree(p)
Return ret
End Function
Structure BITMAPINFOHEADER
Public biSize As System.UInt32
Public biWidth As Integer
Public biHeight As Integer
Public biPlanes As System.UInt16
Public biBitCount As System.UInt16
Public biCompression As System.UInt32
Public biSizeImage As System.UInt32
Public biXPelsPerMeter As Integer
Public biYPelsPerMeter As Integer
Public biClrUsed As System.UInt32
Public biClrImportant As System.UInt32
End Structure
Structure BITMAPFILEHEADER
Public bfType As System.UInt16
Public bfSize As System.UInt32
Public bfReserved1 As System.UInt16
Public bfReserved2 As System.UInt16
Public bfOffBits As System.UInt32
End Structure
Const GPTR As Integer = &H40
<DllImport("KERNEL32.dll", SetLastError:=True)> _
Private Function LocalAlloc(ByVal uFlags As Integer, _
ByVal uBytes As Integer) As IntPtr
End Function
<DllImport("KERNEL32.dll", SetLastError:=True)> _
Private Function LocalFree(ByVal hMem As IntPtr) As IntPtr
End Function
End Module
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:O0W4LA7K...@tk2msftngp13.phx.gbl...
However, it has an error on this line of code saying
"MissingMethodException". do you know why?
Dim p As IntPtr = LocalAlloc(GPTR, size)
Thanks,
-Tim
"Bob Nicholls" <b...@notning.com> wrote in message
news:e$ZhtHRLD...@TK2MSFTNGP09.phx.gbl...
I can't think why at the moment and I'm just leaving to go on holiday for
the week. On my return I'll try to remember to check to see if you or
someone else has managed to fix it.
One thought, do you have another method of the same name, LocalAlloc, in
your code?
Bob
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:eSECdZkL...@TK2MSFTNGP10.phx.gbl...
And just in case it wasn't obvious you call the code like this:
SaveBMP(picbox.Image, "test.bmp")
Bob
"Bob Nicholls" <b...@notning.com> wrote in message
news:ere7ZalL...@TK2MSFTNGP10.phx.gbl...
Yeah, it's pretty ovbious, but do you put the whole path ("\My
Documents\image1.bmp") or just the name itself ("image1.bmp")?
Thank you very much bob, and have fun on your vacation!
-Timothy
"Bob Nicholls" <b...@notning.com> wrote in message
news:eleP3klL...@TK2MSFTNGP11.phx.gbl...
-Tim
"Bob Nicholls" <b...@notning.com> wrote in message
news:ere7ZalL...@TK2MSFTNGP10.phx.gbl...
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:u$DIWErLD...@TK2MSFTNGP10.phx.gbl...
However, is there a way to set one image as another shrinked?
For example, can I take an image that has pixels of 1600 x 1200 and save or
set another image to be the same image but as like pixels 800 x 600 or
something?
Thank you so much,
-Tim
"Alex Feinman [MVP]" <publi...@alexfeinman.com> wrote in message
news:OYlOgOrL...@TK2MSFTNGP11.phx.gbl...
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:%23tHi8Mu...@tk2msftngp13.phx.gbl...
-Chris
"Timothy Taylor" <timoth...@pocketelite.com> wrote in message
news:#tHi8MuL...@tk2msftngp13.phx.gbl...
and then from there save it.
Any code would be wonderful, thanks,
-Tim
"Chris Tacke, eMVP" <cta...@NOinnovativedssSPAM.com> wrote in message
news:upQhdnuL...@TK2MSFTNGP10.phx.gbl...
Well how would you "simply skip every other pixel"?
Thanks,
-Tim
"Alex Feinman [MVP]" <publi...@alexfeinman.com> wrote in message
news:uZWKXhuL...@TK2MSFTNGP12.phx.gbl...
Thanks for fixing it.
Bob
"Alex Feinman [MVP]" <publi...@alexfeinman.com> wrote in message
news:OYlOgOrL...@TK2MSFTNGP11.phx.gbl...