我有一個簽名圖像,我試圖保存爲1 bpp位圖以節省文件空間。完整的.NET Framework具有枚舉PixelFormat.Format1bppIndexed
,但.NET Compact Framework不支持它。在.net緊湊框架中將圖像轉換爲1 bpp位圖
有沒有人在Windows Mobile中發現了一種方法來實現這一點?
我有一個簽名圖像,我試圖保存爲1 bpp位圖以節省文件空間。完整的.NET Framework具有枚舉PixelFormat.Format1bppIndexed
,但.NET Compact Framework不支持它。在.net緊湊框架中將圖像轉換爲1 bpp位圖
有沒有人在Windows Mobile中發現了一種方法來實現這一點?
感謝您指向正確的方向ctacke。 我無法使用Bitmap
類保存圖像數據。它不斷扔出OutOfMemoryException
。我使用BinaryWriter寫出了位圖,就像你所建議的那樣。
我的最終解決方案返回一個字節數組,使用它可以選擇要寫入到磁盤,保存到數據庫,傳輸等
class ImageHelper
{
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPINFOHEADER
{
public BITMAPINFOHEADER(ushort bpp, int height, int width)
{
biBitCount = bpp;
biWidth = width;
biHeight = height;
biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER));
biPlanes = 1; // must be 1
biCompression = 0; // no compression
biSizeImage = 0; // no compression, so can be 0
biXPelsPerMeter = 0;
biYPelsPerMeter = 0;
biClrUsed = 0;
biClrImportant = 0;
}
public void Store(BinaryWriter bw)
{
Store(bw, null);
}
public void Store(BinaryWriter bw, uint[] colorPalette)
{
// Must maintain order for file writing
bw.Write(biSize);
bw.Write(biWidth);
bw.Write(biHeight);
bw.Write(biPlanes);
bw.Write(biBitCount);
bw.Write(biCompression);
bw.Write(biSizeImage);
bw.Write(biXPelsPerMeter);
bw.Write(biYPelsPerMeter);
bw.Write(biClrUsed);
bw.Write(biClrImportant);
// write color palette if 8 bpp or less
if (biBitCount <= 8)
{
if (colorPalette == null)
throw new ArgumentNullException("bpp is 8 or less, color palette is required");
uint paletteCount = BITMAPFILEHEADER.CalcPaletteSize(biBitCount)/4;
if (colorPalette.Length < paletteCount)
throw new ArgumentException(string.Format("bpp is 8 or less, color palette must contain {0} colors", paletteCount));
foreach (uint color in colorPalette)
bw.Write(color);
}
}
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;
}
[StructLayout(LayoutKind.Sequential)]
public struct BITMAPFILEHEADER
{
public BITMAPFILEHEADER(BITMAPINFOHEADER info, out uint sizeOfImageData)
{
bfType = 0x4D42; // Microsoft supplied value to indicate Bitmap 'BM'
bfReserved1 = 0;
bfReserved2 = 0;
// calculate amount of space needed for color palette
uint paletteSize = CalcPaletteSize(info.biBitCount);
bfOffBits = 54 + paletteSize; // default value + paletteSize
// calculate size of image
sizeOfImageData = (uint)(CalcRowSize(info.biWidth * info.biBitCount) * info.biHeight);
bfSize = sizeOfImageData + bfOffBits;
}
private static int CalcRowSize(int bits)
{
return ((((bits) + 31)/32) * 4);
}
public static uint CalcPaletteSize(int bpp)
{
// 8 bpp or less, needs an uint per color
if (bpp <= 8)
return 4 * (uint)Math.Pow(2, bpp);
// no palette needed for 16bpp or higher
return 0;
}
public void Store(BinaryWriter bw)
{
// Must maintain order for file writing
bw.Write(bfType);
bw.Write(bfSize);
bw.Write(bfReserved1);
bw.Write(bfReserved2);
bw.Write(bfOffBits);
}
public ushort bfType;
public uint bfSize;
public short bfReserved1;
public short bfReserved2;
public uint bfOffBits;
}
public static byte[] GetByteArray(Bitmap image)
{
IntPtr hbmOld;
IntPtr hBitmap;
IntPtr hDC;
// create infoheader
BITMAPINFOHEADER bih = new BITMAPINFOHEADER(1, image.Height, image.Width);
// set black and white for 1 bit color palette
// create fileheader and get data size
uint sizeOfImageData;
BITMAPFILEHEADER bfh = new BITMAPFILEHEADER(bih, out sizeOfImageData);
// create device context in memory
hDC = Win32.CreateCompatibleDC(IntPtr.Zero);
// create a 1 bpp DIB
IntPtr pBits = IntPtr.Zero;
hBitmap = Win32.CreateDIBSection(hDC, ref bih, 1, ref pBits, IntPtr.Zero, 0);
// selet DIB into device context
hbmOld = Win32.SelectObject(hDC, hBitmap);
using (Graphics g = Graphics.FromHdc(hDC))
{
g.DrawImage(image, 0, 0);
}
byte[] imageData = new byte[sizeOfImageData];
byte[] fileData;
using (MemoryStream ms = new MemoryStream((int)bfh.bfSize))
{
using (BinaryWriter w = new BinaryWriter(ms))
{
bfh.Store(w);
// store bitmapinfoheader with 1 bpp color palette for black and white
bih.Store(w, new uint[] { (uint)0x0, (uint)0xffffff });
// copy image data into imageData buffer
Marshal.Copy(pBits, imageData, 0, imageData.Length);
// write imageData to stream
w.Write(imageData);
w.Close();
}
fileData = ms.GetBuffer();
ms.Close();
}
// select old object
if (hbmOld != IntPtr.Zero)
Win32.SelectObject(hDC, hbmOld);
// delete memory bitmap
if (hBitmap != IntPtr.Zero)
Win32.DeleteObject(hBitmap);
// delete memory device context
if (hDC != IntPtr.Zero)
Win32.DeleteDC(hDC);
return fileData;
}
}
即使在完整的框架中創建並保存位圖位圖也是有問題的。
我以前撰寫過關於這個問題的文章。
http://www.codeproject.com/KB/GDI-plus/BitonalImageConverter.aspx
我在緊湊型框架的背景下重新審視這段代碼,當你這樣做的枚舉值不存在,所以你不能從頭開始創建雙色調圖像發現。
我很想知道您是否可以在緊湊框架中加載預先存在的雙色調圖像。如果您可以加載預先存在的二進制位圖,則可以降低級別,並將位圖圖像格式直接寫入磁盤或內存流,而不是使用GDI +對象,但這樣做可能不是微不足道的。
我必須在過去通過藍牙生成黑色&白色報告(顏色或灰度圖像對於打印機的緩衝區來說太大)。原來,我不得不使用本機代碼創建圖像。
這裏有一個片段:
private void CreateUnmanagedResources()
{
// for safety, clean up anything that was already allocated
ReleaseUnmanagedResources();
bih = new BITMAPINFOHEADER();
bih.biBitCount = 1;
bih.biClrImportant = 0;
bih.biClrUsed = 0;
bih.biCompression = 0;
bih.biHeight = m_cy;
bih.biPlanes = 1;
bih.biSize = (uint)(Marshal.SizeOf(typeof(BITMAPINFOHEADER)) - 8);
bih.biSizeImage = 0;
bih.biWidth = m_cx;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
bih.clr2 = 0xffffff;
bih.clr1 = 0x0;
hDC = Win32.CreateCompatibleDC(IntPtr.Zero);
pBits = IntPtr.Zero;
hBitmap = Win32.CreateDIBSection(hDC, bih, 1, ref pBits, IntPtr.Zero, 0);
hbmOld = Win32.SelectObject(hDC, hBitmap);
}
private void ReleaseUnmanagedResources()
{
if (hbmOld != IntPtr.Zero)
Win32.SelectObject(hDC, hbmOld);
if(hBitmap != IntPtr.Zero)
Win32.DeleteObject(hBitmap);
if (hDC != IntPtr.Zero)
Win32.DeleteDC(hDC);
}
然後我用Graphics.FromHdc獲得管理圖形對象,我就可以畫畫了報告到。
我沒有用的BinaryWriter節省,但在CF1.0天當Bitmap類沒有一個保存,讓你自由和清除那裏。
感謝您指出我在正確的方向。我設計了一個解決方案(在下面發佈),它建立在你的代碼片段上,並將一個Bitmap對象轉換成1位bpp位圖字節流。 – jnosek 2009-12-03 22:52:00
做得好,傑克 – ctacke 2009-12-04 01:35:27
不要以爲你知道你在哪裏得到Win32.DeleteObject(和其他Win32方法)?我的解決方案中有一個Win32項目,但它沒有這些方法。你是否自己推出了它們(或者你能記得這麼久以後?) – Vaccano 2010-10-07 22:10:02
它們是來自coredll.dll的P/Invoke函數。 實施例: [的DllImport( 「coredll.dll中」)] 公共靜態外部空隙DeleteObject的(IntPtr的hObj); – jnosek 2010-10-08 14:48:59