在 Compact Framework 中创建单色位图

发布于 2024-07-27 18:54:00 字数 561 浏览 2 评论 0原文

我需要使用表示单色位图数据的原始字节创建一个 Bitmap 对象。 在完整的框架上,我正在执行以下操作:

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed)
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
// Write my data into bmpData.Scan0
bmp.UnlockBits(bmpData);

不幸的是,Compact Framework 没有 PixelFormat.Format8bppIndexed 枚举值。 那么我怎样才能在CF上实现这一点呢? 我唯一能想到的就是自己手动创建位图文件头并将其与数据一起写入 Stream 中,然后用该 Bitmap 对象构造一个 Bitmap 对象>流

有想法吗?

I need to create a Bitmap object using raw bytes representing monochrome bitmap data. On the full framework, I am doing the following:

Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed)
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
// Write my data into bmpData.Scan0
bmp.UnlockBits(bmpData);

Unfortunately, the Compact Framework doesn't have the PixelFormat.Format8bppIndexed enum value. So how can I accomplish this on the CF? The only thing I can think of is to manually create the bitmap file header myself and write it along with the data into a Stream and then construct a Bitmap object with that Stream.

Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

挥剑断情 2024-08-03 18:54:00

以下是一些可能有帮助的代码:

  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();

Here's some code that might help:

  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 );
}

To save it to a file do the following:

byte[] data = BWImage.GetByteArray(bitmap);
FileStream fs = new FileStream( "BW.bmp", FileMode.Create );
fs.Write( data, 0, data.Length );
fs.Flush();
fs.Close();
楠木可依 2024-08-03 18:54:00

OpenNetCf 智能设备框架库(有免费版本)中,他们有自己的 Bitmap 类(BitmapEx )。 虽然我还没有尝试过您想要做的事情,但您可以查看它们的实现。 (注意:我必须在下周内执行此操作,因此我可能会稍后更新)

In the OpenNetCf Smart Device Framework library (there is a free version), they have their own Bitmap class (BitmapEx). While I haven't tried what you are trying to do, you might check out their implementation. (note: I do have to do this in the next week, so I will probably update this later)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文