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