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?
A Bitmap is an object used to work with images defined by pixel data.
To draw on a bitmap, use the image control's canvas and attach the mouse-event handlers to the appropriate events in the image control. Typically, you would use region operations (fills, rectangles, polylines, and so on). These are fast and efficient methods of drawing.
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);
}
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.
//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);
To get to the actual bitmap bits, you have to know something about GDI bitmaps first. There are so-called device-dependent bitmaps (DDB, or often simply just "Bitmap" in the API), and device-independent bitmaps (DIB). A full explanation of the difference would be out of scope for this answer.
If you use this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
, then the graphics object in OnPaint
will use a DIB, otherwise it will use a DDB.
If your HBITMAP
is a DDB
, you cannot read/write the pixel data directly (even though it's technically possible, Windows exposes no way to do it). You have to use GetDIBits
to copy them to a device independent buffer, using a particular format, and then SetDIBits
to copy them back.
If your HBITMAP
is a DIB
, then you can get the actual pixel bits (as a pointer), and read/write them directly in memory using GetObject
(not to be confused with 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
will be null
if it was a DDB, and it will be a valid memory address if it's a DIB. If you just want to copy this data, you can directly use bmBits
; the total length is bmHeight * bmWidthBytes
.
If you actually want to manipulate pixel data in memory, you need to know the exact pixel format of the DIB in order to manipulate it correctly. There are many possibilities what the pixel format can be (number of bits per pixel 1/4/8/16/24/32, RGB vs BGR, palettes, etc). It's a lot of work if you really want to support everything.
To do that, know that when being given an HBITMAP
, the GetObject
function will either accept a BITMAP
struct (as shown in the code example above), or a DIBSECTION
struct. Note that DIBSECTION
starts with a BITMAP
, this makes the two structs compatible. Iff the HBITMAP
is a DIB, then GetObject
will fill in a valid (non-null) bmBits
pointer, and it will also fill in the DIBSECTION
's BITMAPINFOHEADER
struct, which you can then use to inspect the pixel format of the DIB. Examining the BITMAPINFOHEADER
will be painful.
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");
}
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With