C# graphics calculate image and keep it - c#

I have seen, that the drawing of two images is time consuming, so I want to reduce drawing these images as much as possible. I use pictureedit and have overriden the ondraw event.
Here I added the below part, but it ends up uin a black image. I do want to check, whether I need to draw at all. This check works. Then I draw the background and overlay it by another one and I want to store this as image and put it as background for my control.
If I do not redraw the background I just call:
g.Clear(Color.Transparent);
in my pictureEdit paint event.
Did I something wrong?
Best Regards,
Patrick
//Recalculate the background
if (redrawBackground)
{
g.FillRectangle(Brushes.White, 0, 0, backGroundImage.Width, backGroundImage.Height);
g.Clear(Color.White);
//this is drawn without aspect ration. The matrix is stored, since drawing images is expensive
GenerateTransformation(g, false);
g.DrawImageUnscaled(backGroundImage, new Rectangle(0, 0, backGroundImage.Width, backGroundImage.Height));
lastTransformation = g.Transform;
GenerateTransformation(g, true);
g.DrawImage(foreGroundImage, new Rectangle(0, 0, backGroundImage.Width, backGroundImage.Height));
lastTransformationAspect = g.Transform;
//Save bitmap as background
Bitmap bmp = new Bitmap(backGroundImage.Width, backGroundImage.Height, e.Graphics);
//Trick the background by a new image
pictureEdit.Image = bmp;
}

Your code (new Bitmap(backGroundImage.Width, backGroundImage.Height, e.Graphics);
) does not copy the image to the Bitmap; it only associates the Graphics object with the bitmap.
Try this:
Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);
g.DrawSomething(); // This draws to the bitmap

Related

Invert Crop from (Cut hole into) Image

Everywhere I look online, I see people posting on how to successfully crop an image. However, I want to 'crop'/ clear a hole out of an image. I want to keep the original image, but crop out a rectangle
As you can see in the image above, I have "cropped" out the kittens face. I maintained the original image, but removed only part of it. I cannot figure out how to do that.
Assuming you want to replace the original pixel colors with transparency you run into a small problem: You can't draw or fill with transparency in GDI+.
But you can use Graphics.Clear(Color.Transparent).
To do that you restrict the region where the Graphics object will draw. Here we can use the simple cropping rectangle but you can clear more complex shapes using a GraphicsPath..
Example using a bitmap bmp:
using (Graphics g = Graphics.FromImage(bmp))
{
Rectangle crop = new Rectangle(222,222,55,55);
g.SetClip(crop);
g.Clear(Color.Transparent);
}
bmp.Save(somefilename, ImageFormat.Png);
Setting your Graphics object's CompositingMode property to CompositingMode.SourceCopy will allow your drawing operations to replace the alpha value instead of proportionally opacifying it:
public static void TestDrawTransparent()
{
//This code will, successfully, draw something transparent overwriting an opaque area.
//More precisely, it creates a 100*100 fully-opaque red square with a 50*50 semi-transparent center.
using(Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb))
{
using(Graphics g = Graphics.FromImage(bmp))
using(Brush opaqueRedBrush = new SolidBrush(Color.FromArgb(255, 255, 0, 0)))
using(Brush semiRedBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
{
g.Clear(Color.Transparent);
Rectangle bigRect = new Rectangle(0, 0, 100, 100);
Rectangle smallRect = new Rectangle(25, 25, 50, 50);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
g.FillRectangle(opaqueRedBrush, bigRect);
g.FillRectangle(semiRedBrush, smallRect);
}
bmp.Save(#"C:\FilePath\TestDrawTransparent.png", ImageFormat.Png);
}
}
In this code, I first draw a fully-opaque red square, then a semi-transparent red square "over" it. The result is a semi-transparent "hole" in the square:
And on a black background:
A zero-opacity brush works just as well, leaving a clear hole through the image (I checked).
With that in mind, you should be able to crop any shapes you want, simply by filling them with a zero-opacity brush.

How to save the painted control as a bitmap?

I have a picturebox (pictureBox1), and it gets lines drawn on it, from the paint event. I was wondering how to convert that drawing (with the lines) to a bitmap, and save it as a file. I've tried:
Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox.Height);
pictureBox1.DrawToBitmap(bmp, pictureBox1.Bounds);
bmp.Save("MyImage.bmp");
But that is a blank image, without the lines. Does anyone know how I can save it with the lines? Thank you.
int bitmapX = 100
int bitmapY = 100
Bitmap imgToSave = new Bitmap(bitmapX, bitmapY);
Graphics gfx = Graphics.FromImage(imgToSave);
// draw on the image with
gfx.DrawLine() // or whatever you want to draw
// save the screenshot
string saveFilePath = Application.StartupPath + "\<name of the image>.png";
imgToSave.Save(saveFilePath, ImageFormat.Png);
This is a code snippet that works for me.
Don't use the PictureBox.Bounds property but instead use a simple Rectangle object/structure filled with the `PictureBox' width and height like this:
var bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.DrawToBitmap(bitmap, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height));
bitmap.Save("c:\\temp\\image.bmp");
Using the Bounds property you are fetching the correct size of the picture box control, but depending on the position not the 0,0 coordinate, but the control position, which leads to an empty bitmap.

Is there a way to overlay or merge a Drawing.Bitmap and a DrawingImage

In a windows forms application, I have as input a Drawing.Bitmap and a DrawingImage. I need to overlay them and put there output in a Controls.Image. How can I do this?
It doesn't matter if you use Image object or Bitmap object, The Drawing.Image is abstract class and Drawing.Bitmap inherited from it. to
draw image over image, get the graphics object from the base image and then use Graphics.DrawImage which accept parameter of type Image.
So you have two images here, one should be printed "overlay" over the other image:
System.Drawing.Image primaryImage = Image.FromFile(#"Your file path");//or resource..
using (Graphics graphics = Graphics.FromImage(primaryImage))//get the underlying graphics object from the image.
{
using (Bitmap overlayImage = new Bitmap(primaryImage.Width, primaryImage.Hieght,
System.Drawing.Imaging.PixelFormat.Format32bppArgb)//or your overlay image from file or resource...
{
graphics.DrawImage(overlayImage, new Point(0, 0));//this will draw the overlay image over the base image at (0, 0) coordination.
}
}
Control.Image = primaryImage;
Not that if the overlay image doesn't have some transparent, and its size is equals or larger than the base image, it will overlap the other image completely, so you the overlay image must have some opacity.
I realize it has been awhile, but the answers here weren't quite working for me. A little tweaking, though made them work fine. For what it is worth, here is my final version.
SCENARIO:
background image is RGB 24
overlay image is ARGB 32 with alpha channel already set properly.
images created from a memory stream
PROBLEM:
Creating the overlay image from the memory stream assumed I meant: Format32bppRgb
But what is needed is Format32bppArgb since the transparency is already in place..
SOLUTION:
pictureBox1.Image = MergeImages( backgroundImage, overlayImage);
using System.Drawing;
using System.Drawing.Imaging;
// ...
private Image MergeImages(Image backgroundImage,
Image overlayImage)
{
Image theResult = backgroundImage;
if (null != overlayImage)
{
Image theOverlay = overlayImage;
if (PixelFormat.Format32bppArgb != overlayImage.PixelFormat)
{
theOverlay = new Bitmap(overlayImage.Width,
overlayImage.Height,
PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(theOverlay))
{
graphics.DrawImage(overlayImage,
new Rectangle(0, 0, theOverlay.Width, theOverlay.Height),
new Rectangle(0, 0, overlayImage.Width, overlayImage.Height),
GraphicsUnit.Pixel);
}
((Bitmap)theOverlay).MakeTransparent();
}
using (Graphics graphics = Graphics.FromImage(theResult))
{
graphics.DrawImage(theOverlay,
new Rectangle(0, 0, theResult.Width, theResult.Height),
new Rectangle(0, 0, theOverlay.Width, theOverlay.Height),
GraphicsUnit.Pixel);
}
}
return theResult;
}

Saving System.Drawing.Graphics to a png or bmp

I have a Graphics object that I've drawn on the screen and I need to save it to a png or bmp file. Graphics doesn't seem to support that directly, but it must be possible somehow.
What are the steps?
Here is the code:
Bitmap bitmap = new Bitmap(Convert.ToInt32(1024), Convert.ToInt32(1024), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bitmap);
// Add drawing commands here
g.Clear(Color.Green);
bitmap.Save(#"C:\Users\johndoe\test.png", ImageFormat.Png);
If your Graphics is on a form, you can use this:
private void DrawImagePointF(PaintEventArgs e)
{
... Above code goes here ...
e.Graphics.DrawImage(bitmap, 0, 0);
}
In addition, to save on a web page, you could use this:
MemoryStream memoryStream = new MemoryStream();
bitmap.Save(memoryStream, ImageFormat.Png);
var pngData = memoryStream.ToArray();
<img src="data:image/png;base64,#(Convert.ToBase64String(pngData))"/>
Graphics objects are a GDI+ drawing surface. They must have an attached device context to draw on ie either a form or an image.
Copy it to a Bitmap and then call the bitmap's Save method.
Note that if you're literally drawing to the screen (by grabbing the screen's device context), then the only way to save what you just drew to the screen is to reverse the process by drawing from the screen to a Bitmap. This is possible, but it would obviously be a lot easier to just draw directly to a Bitmap (using the same code you use to draw to the screen).
Try this, works fine for me...
private void SaveControlImage(Control ctr)
{
try
{
var imagePath = #"C:\Image.png";
Image bmp = new Bitmap(ctr.Width, ctr.Height);
var gg = Graphics.FromImage(bmp);
var rect = ctr.RectangleToScreen(ctr.ClientRectangle);
gg.CopyFromScreen(rect.Location, Point.Empty, ctr.Size);
bmp.Save(imagePath);
Process.Start(imagePath);
}
catch (Exception)
{
//
}
}
Graphics graph = CreateGraphics();
Bitmap bmpPicture = new Bitmap("filename.bmp");
graph.DrawImage(bmpPicture, width, height);
You are likely drawing either to an image or on a control. If on image use
Image.Save("myfile.png",ImageFormat.Png)
If drawing on control use Control.DrawToBitmap() and then save the returned image as above.
Thanks for the correction - I wasn't aware you can draw directly to the screen.

GDI+: how do you render a Graphics object to a bitmap on a background thread?

I'd like to use GDI+ to render an image on a background thread. I found this example on how to rotate an image using GDI+, which is the operation I'd like to do.
private void RotationMenu_Click(object sender, System.EventArgs e)
{
Graphics g = this.CreateGraphics();
g.Clear(this.BackColor);
Bitmap curBitmap = new Bitmap(#"roses.jpg");
g.DrawImage(curBitmap, 0, 0, 200, 200);
// Create a Matrix object, call its Rotate method,
// and set it as Graphics.Transform
Matrix X = new Matrix();
X.Rotate(30);
g.Transform = X;
// Draw image
g.DrawImage(curBitmap,
new Rectangle(205, 0, 200, 200),
0, 0, curBitmap.Width,
curBitmap.Height,
GraphicsUnit.Pixel);
// Dispose of objects
curBitmap.Dispose();
g.Dispose();
}
My question has two parts:
How would you accomplish this.CreateGraphics() on a background thread? Is it possible? My understanding is that a UI object is this in this example. So if I'm doing this processing on a background thread, how would I create a graphics object?
How would I then extract a bitmap from the Graphics object I'm using once I'm done processing? I haven't been able to find a good example of how to do that.
Also: when formatting a code sample, how do I add newlines? If someone could leave me a comment explaining that I'd really appreciate it. Thanks!
To draw on a bitmap you don't want to create a Graphics object for an UI control. You create a Graphics object for the bitmap using the FromImage method:
Graphics g = Graphics.FromImage(theImage);
A Graphics object doesn't contain the graphics that you draw to it, instead it's just a tool to draw on another canvas, which is usually the screen, but it can also be a Bitmap object.
So, you don't draw first and then extract the bitmap, you create the bitmap first, then create the Graphics object to draw on it:
Bitmap destination = new Bitmap(200, 200);
using (Graphics g = Graphics.FromImage(destination)) {
Matrix rotation = new Matrix();
rotation.Rotate(30);
g.Transform = rotation;
g.DrawImage(source, 0, 0, 200, 200);
}

Categories

Resources