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

前端 未结 7 1619
逝去的感伤
逝去的感伤 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 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);
    
        /// Gets GDI HDC as an Emgu.CV.Mat image as BGRA
        /// GDI HDC
        /// Destination Mat which will receive the window contents image
        /// If TRUE, pixel will be flipped vertically
        /// TRUE if image was copied successfully
        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;
            }
        }
        
        /// Gets window contents as an Emgu.CV.Mat image as BGRA
        /// Handle to desired window
        /// Destination Mat which will receive the window contents image
        /// If TRUE, pixel will be flipped vertically
        /// TRUE if image was copied successfully
        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);
        }
    
        /// Gets GDI Graphics contents as an Emgu.CV.Mat image as BGRA
        /// .NET GDI Graphics instance
        /// Destination Mat which will receive the window contents image
        /// If TRUE, pixel will be flipped vertically
        /// TRUE if image was copied successfully
        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);
            }
        }
    

提交回复
热议问题