URL: http://www.eggheadcafe.com/forumarchives/NETFrameworkdrawing/Nov2005/post24263016.asp
Convert a DIB* to a System.Drawing.Bitmap
This is useful for scanner APIs that provide a DIB*. A dot.net app can more easily work with System.Drawing.Bitmap.
SetDIBitsToDevice... Bob Powell posted an approach here: http://www.eggheadcafe.com/forumarchives/NETFrameworkdrawing/Nov2005/post24263016.asp My code below is an implementation of his approach.
TwainGui ... I found code with namespace TwainGui and class DibToImage. It had 3 public static functions. WithStream worked and is shown below. Google for \"TwainGui.dibtoimage.withstream\" to find what I was looking at. I\'m using this for grayscale and 24-bit color bitmaps returned from a proprietary scanner API.
public class DibToBitmap { /// <summary> /// Convert DIB to Bitmap. /// </summary> /// <param name="dibPtrArg">Pointer to memory DIB, starting with BITMAPINFOHEADER.</param> /// <returns>A Bitmap</returns> public static Bitmap Convert(IntPtr dibPtrArg) { BITMAPINFOHEADER bmi; IntPtr pixptr; GetPixelInfo(dibPtrArg, out pixptr, out bmi ); Graphics scannedImageGraphics = Graphics.FromImage(bitMap); IntPtr hdc = scannedImageGraphics.GetHdc(); SetDIBitsToDevice( hdc, 0, // XDest 0, // YDest bmi.biWidth, bmi.biHeight, 0, // XSrc 0, // YSrc 0, // uStartScan bmi.biHeight, // cScanLines pixptr, // lpvBits dibPtrArg, // lpbmi 0); // 0 = literal RGB values rather than palette scannedImageGraphics.ReleaseHdc(hdc); const float inchPerMeter = 39.3700787F; bitMap.SetResolution(bmi.biXPelsPerMeter/inchPerMeter, bmi.biYPelsPerMeter/inchPerMeter); // bitMap.Save(@"c:\0\2.bmp", ImageFormat.Bmp); // debug code return bitMap; } static private void GetPixelInfo(IntPtr bmpptr, out IntPtr pix, out BITMAPINFOHEADER bmi) { Marshal.PtrToStructure(bmpptr, bmi); // copy into struct. if (bmi.biSizeImage == 0) { bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight; } int p = bmi.biClrUsed; if ((p == 0) && (bmi.biBitCount <= 8)) { p = 1 << bmi.biBitCount; } pix = (IntPtr)((p * 4) + bmi.biSize + (int)bmpptr); } [StructLayout(LayoutKind.Sequential, Pack=2)] private class BITMAPINFOHEADER { public int biSize; public int biWidth; public int biHeight; public short biPlanes; public short biBitCount; public int biCompression; public int biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public int biClrUsed; public int biClrImportant; } [DllImport("gdi32.dll", ExactSpelling = true)] internal static extern int SetDIBitsToDevice( IntPtr hdc, int xdst, int ydst, int width, int height, int xsrc, int ysrc, int start, int lines, IntPtr bitsptr, IntPtr bmiptr, int color); } // class DibToImage //////////////////////// Another approach.... [StructLayout(LayoutKind.Sequential, Pack=2)] private class BITMAPINFOHEADER { public int biSize; public int biWidth; public int biHeight; public short biPlanes; public short biBitCount; public int biCompression; public int biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public int biClrUsed; public int biClrImportant; } /// <summary> /// Get .NET 'Bitmap' object from memory DIB via stream constructor. /// This should work for most DIBs. /// </summary> /// <param name="dibPtr">Pointer to memory DIB, starting with BITMAPINFOHEADER.</param> public static Bitmap WithStream( IntPtr dibPtr ) { BITMAPINFOHEADER bmi = (BITMAPINFOHEADER) Marshal.PtrToStructure( dibPtr, bmiTyp ); if( bmi.biSizeImage == 0 ) bmi.biSizeImage = ((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * Math.Abs( bmi.biHeight ); if( (bmi.biClrUsed == 0) && (bmi.biBitCount < 16) ) bmi.biClrUsed = 1 << bmi.biBitCount; int dibSize = bmi.biSize + (bmi.biClrUsed * 4) + bmi.biSizeImage; // info + rgb + pixels fh.Size = fhSize + dibSize; // final file size fh.OffBits = fhSize + bmi.biSize + (bmi.biClrUsed * 4); // offset to pixels RawSerializeInto( fh, data ); // serialize BITMAPFILEHEADER into byte[] Marshal.Copy( dibPtr, data, fhSize, dibSize ); // mem-copy DIB into byte[] tmp.Dispose(); tmp = null; stream.Close(); stream = null; data = null; return result; }
You need to login to post a comment.
