下面是一些代碼,可以幫助:
const int XPelsPerMeter = 0xb12; // 72 ppi, 96 would work well too
const int YPelsPerMeter = 0xb12;
const int Gptr = 0x40;
const int Srccopy = 0x00CC0020;
struct BITMAPFILEHEADER
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
}
public static byte[] GetByteArray(Bitmap bitmap)
{
IntPtr hbm = bitmap.GetHbitmap(); // this is step (1)
IntPtr sdc = GetDC(IntPtr.Zero); // First we obtain the DC for the screen
// Next, create a DC for the original hbitmap
IntPtr hdc = CreateCompatibleDC(sdc);
SelectObject(hdc, hbm);
byte[] arrayBytes = CreateBinary(hdc, bitmap.Height, bitmap.Width);
// Finally some cleanup.
DeleteDC(hdc);
ReleaseDC(IntPtr.Zero, sdc);
DeleteObject(hbm);
return arrayBytes;
}
static int WIDTHBYTES(int bits)
{
return ((((bits) + 31)/32) * 4);
}
private static byte[] CreateBinary(IntPtr hDc, int height, int width)
{
IntPtr hMemDc = CreateCompatibleDC(hDc);
int cb = 0;
BITMAPINFOHEADER bi = new BITMAPINFOHEADER();
bi.biSize = (uint)Marshal.SizeOf(bi);
bi.biBitCount = 1; // Creating RGB bitmap. The following three members don't matter
bi.biClrUsed = 2;
bi.biClrImportant = 2;
bi.biCompression = 0;
bi.biHeight = height;
bi.biWidth = width;
bi.biPlanes = 1;
cb = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
bi.biSizeImage = (uint)cb;
bi.biXPelsPerMeter = XPelsPerMeter;
bi.biYPelsPerMeter = YPelsPerMeter;
IntPtr pBits = IntPtr.Zero;
//Allocate memory for bitmap bits
IntPtr pBi = LocalAlloc(Gptr, bi.biSize);
// Not sure if this needed - simply trying to keep marshaller happy
Marshal.StructureToPtr(bi, pBi, false);
//This will return IntPtr to actual DIB bits in pBits
IntPtr hBmp = CreateDIBSection(hDc, pBi, 0, ref pBits, IntPtr.Zero, 0);
//Marshall back - now we have BITMAPINFOHEADER correctly filled in
//Marshal.PtrToStructure(pBI, bi);
BITMAPINFOHEADER biNew = (BITMAPINFOHEADER)Marshal.PtrToStructure(pBi, typeof(BITMAPINFOHEADER));
//Usual stuff
IntPtr hOldBitmap = SelectObject(hMemDc, hBmp);
//Grab bitmap
BitBlt(hMemDc, 0, 0, bi.biWidth, bi.biHeight, hDc, 0, 0, Srccopy);
// Allocate memory for a copy of bitmap bits
byte[] RealBits = new byte[cb];
// And grab bits from DIBSestion data
Marshal.Copy(pBits, RealBits, 0, cb);
// This simply creates valid bitmap file header, so it can be saved to disk
BITMAPFILEHEADER bfh = new BITMAPFILEHEADER();
uint colorSize = 2 * 4;//2 colors for B&W, 4 bytes (RGBQUAD)
uint sizeofBinfo = 0x36 + colorSize;//original
//sizeofBINFO = (uint)Marshal.SizeOf(bi);//sorin
//bfh.bfSize = (uint)cb + 0x36; // Size of header + size of BITMAPINFOHEADER size of bitmap bits
bfh.bfSize = (uint)(cb + sizeofBinfo);
bfh.bfType = 0x4d42; //BM
bfh.bfOffBits = sizeofBinfo; //
int HdrSize = 14;
byte[] header = new byte[HdrSize];
BitConverter.GetBytes(bfh.bfType).CopyTo(header, 0);
BitConverter.GetBytes(bfh.bfSize).CopyTo(header, 2);
BitConverter.GetBytes(bfh.bfOffBits).CopyTo(header, 10);
//Allocate enough memory for complete bitmap file
byte[] data = new byte[cb + bfh.bfOffBits];
//BITMAPFILEHEADER
header.CopyTo(data, 0);
//BITMAPINFOHEADER
header = new byte[Marshal.SizeOf(bi)];
IntPtr pHeader = LocalAlloc(Gptr, (uint)Marshal.SizeOf(bi));
Marshal.StructureToPtr(biNew, pHeader, false);
Marshal.Copy(pHeader, header, 0, Marshal.SizeOf(bi));
LocalFree(pHeader);
header.CopyTo(data, HdrSize);
//set black color as second color from color table
byte[] colors = new byte[10];
colors[4] = 255;
colors[5] = 255;
colors[6] = 255;
colors.CopyTo(data, (int)bfh.bfOffBits - (int)colorSize);
//Bitmap bits
RealBits.CopyTo(data, (int)bfh.bfOffBits);
DeleteObject(SelectObject(hMemDc, hOldBitmap));
DeleteDC(hMemDc);
return data;
}
[DllImport("coredll.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("coredll.dll")]
public static extern int InvalidateRect(IntPtr hwnd, IntPtr rect, int bErase);
[DllImport("coredll.dll")]
public static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("coredll.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("coredll.dll")]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("coredll.dll")]
public static extern int DeleteDC(IntPtr hdc);
[DllImport("coredll.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("coredll.dll")]
public static extern int BitBlt(IntPtr hdcDst, int xDst, int yDst, int w, int h, IntPtr hdcSrc, int xSrc, int ySrc, int rop);
[DllImport("coredll.dll")]
private static extern IntPtr LocalAlloc(uint flags, uint cb);
[DllImport("coredll.dll")]
private static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("coredll.dll")]
private static extern IntPtr CreateDIBSection(IntPtr hdc, IntPtr hdr, uint colors, ref IntPtr pBits, IntPtr hFile, uint offset);
}
將其保存到一個文件中執行以下操作:
byte[] data = BWImage.GetByteArray(bitmap);
FileStream fs = new FileStream("BW.bmp", FileMode.Create);
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
我看着OpenNETCF,但它依賴於相同的枚舉。看看他們如何實現一些Bitmap類可能會很有用,因爲我非常確定我需要自己手動構建頭部。 :( – Jason 2009-07-27 20:15:47