我想知道Graphics对象正在绘制一些东西的缓冲区的中间状态是什么。如何获取位图或它正在绘制的图像?
发布于 2011-03-15 14:58:50
我不太确定我是否理解你的要求,因为你的问题很不清楚。
如果您想知道如何保存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");
}
发布于 2011-03-15 15:38:36
这段代码适用于我正在转换图像>>位图>>字节>> 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);
}
发布于 2020-03-03 06:50:58
因为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.
//Bitmap bitmap = Image.FromHbitmap(hbitmap);
// To manipulate the actual bitmap pixel data directly, see below.
// Put these in finally:
//bitmap.Dispose();
// NOTE: You cannot use the graphics object before ReleaseHdc is called.
graphics.ReleaseHdc(hdc);
要获取实际的位图比特,请执行以下操作,你必须先了解一些关于GDI位图的知识。有所谓的设备相关位图(DDB,或者通常只是API中的“位图”),以及与设备无关的位图(DIB)。对这种差异的完整解释超出了这个答案的范围。
如果您使用
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
中的图形对象OnPaint
将使用DIB,否则将使用DDB。
如果你的HBITMAP
是一个DDB
,您不能直接读/写像素数据(尽管在技术上是可行的,但Windows没有提供这样做的方法)。你必须使用GetDIBits
使用特定格式将它们复制到与设备无关的缓冲区,然后SetDIBits
把它们复制回去。
如果你的HBITMAP
是一个DIB
,然后您可以获得实际的像素位(作为指针),并使用以下命令直接在内存中读/写它们`GetObject`(请不要与GetCurrentObject
):
[DllImport("gdi32.dll")]
static extern unsafe int GetObject(IntPtr hobj, int cb, void* data);
[StructLayout(LayoutKind.Sequential)]
unsafe struct BITMAP
{
int bmType;
int bmWidth;
int bmHeight;
int bmWidthBytes;
ushort bmPlanes;
ushort bmBitsPixel;
void* bmBits;
}
BITMAP BitmapDesc = new BITMAP();
GetObject(hbitmap, sizeof(BITMAP), &BitmapDesc);
BITMAP.bmBits
将会是null
如果是DDB,那么它将是一个有效的内存地址;如果它是一个DIB,那么它将是一个有效的内存地址。如果您只想复制此数据,可以直接使用bmBits
;总长度为bmHeight * bmWidthBytes
..。
如果你真的想要操作内存中的像素数据,你需要知道DIB的确切像素格式,以便正确地操作它。像素格式有多种可能(每像素的位数为1/4/8/16/24/32、RGB与BGR、调色板等)。如果你真的想要支持所有的东西,那就需要做大量的工作..。
要做到这一点,要知道当被赋予一个HBITMAP
、GetObject
函数将接受一个BITMAP
结构(如上面的代码示例所示)或一个`DIBSECTION`结构。请注意DIBSECTION
以一个BITMAP
,这使得两个结构兼容。如果HBITMAP
是DIB,那么GetObject
将填写有效的(非空)bmBits
指针,它还将填充DIBSECTION
%s`BITMAPINFOHEADER`结构,然后可以使用它来检查DIB的像素格式。
检查BITMAPINFOHEADER
会很痛苦。
https://stackoverflow.com/questions/5308363
复制相似问题