How to get the bitmap/image from a Graphics object in C#?

前端 未结 7 1591
逝去的感伤
逝去的感伤 2021-02-20 07:34

I want to know what the intermediate state of the buffer where the Graphics object is drawing some stuff. How do I get hold of the bitmap or the image that it is drawing on?

相关标签:
7条回答
  • 2021-02-20 07:57

    Have you taken a look at this MSDN article? It describes the Bitmap class, which is an object used to work with images defined by pixel data. System.Drawing.Image provides additional functionality for it. HTH

    0 讨论(0)
  • 2021-02-20 08:02

    Not 100% sure what you want here, but if you want to use the graphics class to draw, and then save to file, you have to obtain the Graphics object from a Bitmap file, and then save the bitmap after you are done. You can do that like this:

      Bitmap bitmap = new Bitmap(bWidth, bHeight);
      Graphics g = Graphics.FromImage(bitmap);
      //do all your operations on g here.
      bitmap.Save(fileName, imageFormat);
    
    0 讨论(0)
  • 2021-02-20 08:04

    Since nobody answered the actual question after 9 years...

    // System.Windows.Forms.Internal.IntUnsafeNativeMethods
    [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "GetCurrentObject", ExactSpelling = true, SetLastError = true)]
    public static extern IntPtr IntGetCurrentObject(HandleRef hDC, int uObjectType);
    
    
    IntPtr hdc = graphics.GetHdc();
    // This is a HBITMAP, which is the actual buffer that is being drawn to by hdc.
    IntPtr hbitmap = IntGetCurrentObject(new HandleRef(null, hdc), 7 /*OBJ_BITMAP*/);
    // You can create a Gdiplus::Bitmap object from this, but it will copy all image data.
    // I have not found any way to get a Gdiplus::Bitmap object from a HBITMAP *without* copying it.
    //Bitmap bitmap = Image.FromHbitmap(hbitmap);
    
    // Put these in finally:
    //bitmap.Dispose();
    // NOTE: You cannot use the graphics object before ReleaseHdc is called.
    graphics.ReleaseHdc(hdc);
    
    0 讨论(0)
  • 2021-02-20 08:10

    I'm not really sure if I understand what you're asking for, as your question is very unclear.

    If you want to know how to save the contents of a Graphics object to a bitmap, then the answer is that there's no direct approach for doing so. Drawing on a Graphics object is a one-way operation.

    The better option is to create a new Bitmap object, obtain a Graphics object for that bitmap, and draw directly onto it. The following code is an example of how you might do that:

    // Create a new bitmap object
    using (Bitmap bmp = new Bitmap(200, 300))
    {
        // Obtain a Graphics object from that bitmap
        using (Graphics g = Graphics.FromImage(bmp))
        {
            // Draw onto the bitmap here
            // ....
            g.DrawRectangle(Pens.Red, 10, 10, 50, 50);
        }
    
        // Save the bitmap to a file on disk, or do whatever else with it
        // ...
        bmp.Save("C:\\MyImage.bmp");
    }
    
    0 讨论(0)
  • 2021-02-20 08:11

    @dialer Has the best answer in this thread so far. As an additional example, here is how to get bits from Graphics or any HWND into Emgu.CV Mat in C#.

        struct BITMAP
        {
            public Int32 bmType;
            public Int32 bmWidth;
            public Int32 bmHeight;
            public Int32 bmWidthBytes;
            public Int16 bmPlanes;
            public Int16 bmBitsPixel;
            public IntPtr bmBits;
        }
    
        [StructLayout(LayoutKind.Sequential, Pack = 4)]
        struct BITMAPINFOHEADER
        {
            public int biSize;
            public int biWidth;
            public int biHeight;
            public Int16 biPlanes;
            public Int16 biBitCount;
            public int biCompression;
            public int biSizeImage;
            public int biXPelsPerMeter;
            public int biYPelsPerMeter;
            public int biClrUsed;
            public int bitClrImportant;
        }
    
        [DllImport("user32.dll", SetLastError=true)]
        static extern IntPtr GetDC(IntPtr hWnd);
    
        // System.Windows.Forms.Internal.IntUnsafeNativeMethods
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "GetCurrentObject", ExactSpelling = true, SetLastError = true)]
        static extern IntPtr IntGetCurrentObject(HandleRef hDC, int uObjectType);
        
        [DllImport("gdi32.dll", CharSet = CharSet.Auto, EntryPoint = "GetObject")]
        static extern int GetObjectBitmap(IntPtr hObject, int nCount, ref BITMAP lpObject);
    
        [DllImport("gdi32.dll", EntryPoint = "GetDIBits")]
        static extern int GetDIBits(IntPtr hdc, IntPtr hbmp, int uStartScan, int cScanLines, 
                                    IntPtr lpvBits, ref BITMAPINFOHEADER lpbi, int uUsage);
    
        /// <summary>Gets GDI HDC as an Emgu.CV.Mat image as BGRA</summary>
        /// <param name="hdc">GDI HDC</param>
        /// <param name="destination">Destination Mat which will receive the window contents image</param>
        /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
        /// <returns>TRUE if image was copied successfully</returns>
        public static bool GetHdcAsMat(IntPtr hdc, ref Mat destination, bool verticalFlip)
        {
            try
            {
                // This is a HBITMAP, which is the actual buffer that is being drawn to by hdc.
                IntPtr hbitmap = IntGetCurrentObject(new HandleRef(null, hdc), 7 /*OBJ_BITMAP*/);
    
                // Get width, height and the address of the pixel data for the native HBitmap
                BITMAP info = new BITMAP();
                if (0 == GetObjectBitmap(hbitmap, Marshal.SizeOf(info), ref info))
                    return false;
    
                // if the image is a DIB, we can copy the bits directly from bmBits
                if (info.bmBits != IntPtr.Zero)
                {
                    // data view of the DIB bits, no allocations
                    Mat view = new Mat(info.bmHeight, info.bmWidth, DepthType.Cv8U, 4, 
                                       info.bmBits, info.bmWidth * 4);
    
                    if (verticalFlip) // copy flipped:
                        CvInvoke.Flip(view, destination, FlipType.Vertical);
                    else // copy directly:
                        view.CopyTo(destination); // automatically resize destination
                    return true;
                }
    
                // otherwise, use GetDIBits to get the bitmap from the GPU
                // a copy is always needed to get the data from GPU to system memory
    
                if (destination.Width != info.bmWidth ||
                    destination.Height != info.bmHeight)
                {
                    destination.Dispose();
                    destination = new Mat(info.bmHeight, info.bmWidth, DepthType.Cv8U, 4);
                }
    
                var desired = new BITMAPINFOHEADER();
                desired.biSize = Marshal.SizeOf(desired);
                desired.biWidth = info.bmWidth;
                desired.biHeight = verticalFlip ? -info.bmHeight : info.bmHeight;
                desired.biPlanes = 1;
                desired.biBitCount = info.bmBitsPixel;
    
                // Copy bits into destination
                IntPtr dest = destination.DataPointer;
                return 0 != GetDIBits(hdc, hbitmap, 0, destination.Height, dest, ref desired, 0);
            }
            catch
            {
                return false;
            }
        }
        
        /// <summary>Gets window contents as an Emgu.CV.Mat image as BGRA</summary>
        /// <param name="hwnd">Handle to desired window</param>
        /// <param name="destination">Destination Mat which will receive the window contents image</param>
        /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
        /// <returns>TRUE if image was copied successfully</returns>
        public static bool GetWindowAsMat(IntPtr hwnd, ref Mat destination, bool verticalFlip)
        {
            IntPtr hdc = GetDC(hwnd); // private DC does not need to be released
            return GetHdcAsMat(hdc, ref destination, verticalFlip);
        }
    
        /// <summary>Gets GDI Graphics contents as an Emgu.CV.Mat image as BGRA</summary>
        /// <param name="graphics">.NET GDI Graphics instance</param>
        /// <param name="destination">Destination Mat which will receive the window contents image</param>
        /// <param name="verticalFlip">If TRUE, pixel will be flipped vertically</param>
        /// <returns>TRUE if image was copied successfully</returns>
        public static bool GetGraphicsAsMat(Graphics graphics, ref Mat destination, bool verticalFlip)
        {
            IntPtr hdc = graphics.GetHdc();
            try
            {
                return GetHdcAsMat(hdc, ref destination, verticalFlip);
            }
            finally
            {
                // NOTE: You cannot use the graphics object before ReleaseHdc is called.
                graphics.ReleaseHdc(hdc);
            }
        }
    
    0 讨论(0)
  • 2021-02-20 08:12

    This code working for me where I am converting image >> bitmap >> byte >> Base64 String.

    System.Drawing.Image originalImage = //your image
    
    //Create empty bitmap image of original size
    
    Bitmap tempBmp = new Bitmap(originalImage.Width, originalImage.Height);
    
    Graphics g = Graphics.FromImage(tempBmp);
    
    //draw the original image on tempBmp
    
    g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);
    
    //dispose originalImage and Graphics so the file is now free
    
    g.Dispose();
    
    originalImage.Dispose();
    
    using (MemoryStream ms = new MemoryStream())
    {
        // Convert Image to byte[]
        tempBmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
        //dpgraphic.image.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
        byte[] imageBytes = ms.ToArray();
    
        // Convert byte[] to Base64 String
        string strImage = Convert.ToBase64String(imageBytes);
        sb.AppendFormat(strImage);
    }
    
    0 讨论(0)
提交回复
热议问题