我想知道Graphics对象绘制一些东西的缓冲区的中间状态。如何获取位图或正在绘制的图像?
答案 0 :(得分:7)
我不确定我是否理解你的要求,因为你的问题很清楚。
如果您想知道如何将Graphics
对象的内容保存到位图,那么答案是没有直接的方法来执行此操作。在Graphics
对象上绘图是单向操作。
更好的选择是创建一个新的Bitmap
对象,获取该位图的Graphics
对象,并直接绘制到该对象上。以下代码是您如何执行此操作的示例:
// 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");
}
答案 1 :(得分:3)
此代码适用于我转换图像的位置>>位图>>字节>> Base64字符串。
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);
}
答案 2 :(得分:2)
不是100%确定你想要什么,但如果你想使用图形类绘制,然后保存到文件,你必须从Bitmap文件中获取Graphics对象,然后在你之后保存位图完成。你可以这样做:
Bitmap bitmap = new Bitmap(bWidth, bHeight);
Graphics g = Graphics.FromImage(bitmap);
//do all your operations on g here.
bitmap.Save(fileName, imageFormat);
答案 3 :(得分:1)
因为9年后没有人回答实际问题...
// 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);
答案 4 :(得分:0)
你看过this MSDN article了吗?它描述了Bitmap类,它是一个用于处理像素数据定义的图像的对象。 System.Drawing.Image为它提供了额外的功能。 HTH
答案 5 :(得分:0)
你可以让他的hdc成为表面缓冲区的指针,并最终将他的内容复制到另一个带有bitblt函数的hdc。这样,您就可以在位图上创建绘图表面的副本。
enum TernaryRasterOperations : uint
{
/// <summary>dest = source</summary>
SRCCOPY = 0x00CC0020,
/// <summary>dest = source OR dest</summary>
SRCPAINT = 0x00EE0086,
/// <summary>dest = source AND dest</summary>
SRCAND = 0x008800C6,
/// <summary>dest = source XOR dest</summary>
SRCINVERT = 0x00660046,
/// <summary>dest = source AND (NOT dest)</summary>
SRCERASE = 0x00440328,
/// <summary>dest = (NOT source)</summary>
NOTSRCCOPY = 0x00330008,
/// <summary>dest = (NOT src) AND (NOT dest)</summary>
NOTSRCERASE = 0x001100A6,
/// <summary>dest = (source AND pattern)</summary>
MERGECOPY = 0x00C000CA,
/// <summary>dest = (NOT source) OR dest</summary>
MERGEPAINT = 0x00BB0226,
/// <summary>dest = pattern</summary>
PATCOPY = 0x00F00021,
/// <summary>dest = DPSnoo</summary>
PATPAINT = 0x00FB0A09,
/// <summary>dest = pattern XOR dest</summary>
PATINVERT = 0x005A0049,
/// <summary>dest = (NOT dest)</summary>
DSTINVERT = 0x00550009,
/// <summary>dest = BLACK</summary>
BLACKNESS = 0x00000042,
/// <summary>dest = WHITE</summary>
WHITENESS = 0x00FF0062,
/// <summary>
/// Capture window as seen on screen. This includes layered windows
/// such as WPF windows with AllowsTransparency="true"
/// </summary>
CAPTUREBLT = 0x40000000
}
[DllImport("gdi32.dll", EntryPoint = "BitBlt", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool BitBlt([In] IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, [In] IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
public static Bitmap CopyGraphicsContent(Graphics source, Rectangle rect)
{
Bitmap bmp = new Bitmap(rect.Width, rect.Height);
using (Graphics dest = Graphics.FromImage(bmp))
{
IntPtr hdcSource = source.GetHdc();
IntPtr hdcDest = dest.GetHdc();
BitBlt(hdcDest, 0, 0, rect.Width, rect.Height, hdcSource, rect.X, rect.Y, TernaryRasterOperations.SRCCOPY);
source.ReleaseHdc(hdcSource);
dest.ReleaseHdc(hdcDest);
}
return bmp;
}
答案 6 :(得分:0)
@dialer 迄今为止在此线程中提供了最佳答案。再举一个例子,这里是如何从 Graphics 或任何 HWND 中获取位到 C# 中的 Emgu.CV Mat 中。
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);
}
}