I have two questions:
1) I have a PictureBox and its Dock is set to Fill. When I resize the Form I cannot create a Graphic on the part of the PictureBox that is extended. What is the problem?
2) I want to convert the Graphic that is created on the PictureBox to Bitmap and save it as
*.JPG or *.bmp. How can I do this?
you can use the handle device to get the bitmap out of the picture box
Graphics g = pictureBox1.CreateGraphics();
Bitmap bitMap = Bitmap.FromHbitmap(g.GetHdc());
bitMap.Save(filePath, System.Drawing.Imaging.ImageFormat.Jpeg);
or even better, if the pictureBox does`nt modify the image, you can directly get the image from the pictureBox control
pictureBox1.Image.Save("path", System.Drawing.Imaging.ImageFormat.Jpeg);
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)
{
//
}
}
1) Your description is very vague. Do you get an exception? Does it display wrong results? What is happening?
2) You need to get the Image from the PictureBox and use its Save method.
When the Picturebox gets resized to fill the form, it seems it's Image property stays the same.
So what you need to do is handle the PictureBox.OnSizeChanged Event, and then use the following code to resize the image:
private void pictureBox1_SizeChanged(object sender, EventArgs e)
{
if ((pictureBox1.Image != null))
{
pictureBox1.Image = new Bitmap(pictureBox1.Image, pictureBox1.Size);
}
}
To save the image use:
pictureBox1.Image.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);
Hope that helps!
Related
Here is what I am trying to do. I have an Image that is 1920X1080. I am showing that image in a PictureBox and allowing a user to draw an ellipse on the screen. Once they finish that I will need to save that image off with the image and ellipse in 1 photo.
So I have tried several ways:
1. Just trying to save the image and ellipse from the PictureBox. No success doing that.
2. To store the location of the ellipse on the picture box and then redraw that ellipse on a new copy of the image using a graphics object. The problem with this one is that when it saves off the ellipse is not in the right place due to the size of the PictureBox and the original image difference.
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
pictureBox1.Cursor = Cursors.Default;
if (isMoving)
{
Circles.Add(mouseDownPosition, mouseMovePosition);
}
isMoving = false;
}
Bitmap newImage = new Bitmap(new Bitmap(#"C:\Personal\test\Sample.jpg"));
Graphics g = Graphics.FromImage(newImage);
foreach (var circle in Circles)
{
g.DrawEllipse(new Pen(Color.Red, 3), new Rectangle(circle.Key, new Size(circle.Value.X - circle.Key.X, circle.Value.Y - circle.Key.Y)));
}
newImage.Save(#"C:\Projects\Projects\SampleCombine.jpg");
I am really just looking for a way to take exactly what I see on the PictureBox and save it as its own jpg.
My take is that I need to figure out how to reposition the "Circle" based on where it was drawn and where it should be drawn on a larger file.
Any ideas?
I want to create a custom control or override the pictuebox's onpaint event such that i get access to the image before its drawn in the picturbox,so that i can rotate the image.
I know that i can do something like this
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawRectangle(Pens.Black, new Rectangle(10, 10, 20, 20));
}
How to get access to the image and how to create a custom control.
Here is a quick example of a subclass: It hides the original Image property and replaces it with one that does a rotation before assigning it:
class RotatedPictureBox : PictureBox
{
private Image image;
public new Image Image {
get { return image; } // ?? you may want to undo the rotation here ??
set {
Bitmap bmp = value as Bitmap ;
// use the rotation you need!
if ( bmp != null ) bmp.RotateFlip(RotateFlipType.Rotate270FlipX);
image = bmp;
base.Image = Image;
}
}
}
public RotatedPictureBox ()
{
}
}
Caveat: Assigning an Image seems to work but I didn't test it for all possible uses.. Known limitations
It doesn't rotate images assigned via ImageLocation.
I had a crash once, when assigning an image in the Designer, but can't reproduce.
I'm trying to build a little test application (and my WinForm skills have rusted somewhat) with an Image and some overlays on top of it.
My image is set to stretch in the PictureBox but my fields on the right hand side I want to be from the origin of the image. Therefore I decided to render directly on the image that the PictureBox is using to ensure that the co-ordinates are always correct. Here's the white box rendering:
private void pbImage_Paint(object sender, PaintEventArgs e)
{
try
{
if (this.rdFront.Checked)
RenderFront(pbImage.Image, true);
else
RenderBack(pbImage.Image, true);
}
catch (ArgumentNullException ex)
{ }
}
public void RenderFront(Image image, bool includeBoxes)
{
// If we have no image then we can't render
if (image == null)
throw new ArgumentNullException("image");
Graphics gfx = Graphics.FromImage(image);
// Get the top label
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes)
{
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
The problem that I've got is if I do this and always draw on the underlying image then when I move the white overlay, I end up with un-drawn parts of the image. So I decided to clone the image before each re-render (on the basis that I don't care about performance).
I therefore decided to clone the image whenever I need to manually invalidate it, and call this when a setting changes:
public void Refresh()
{
if (this.rdFront.Checked)
pbImage.Image = new Bitmap(front);
else
pbImage.Image = new Bitmap(back);
this.pbImage.Invalidate();
}
Now I'm sure I must be missing something obvious - if I modify one of the values my penguins render with no overlay. However if I force a resize of the application then both the penguins and the overlay suddenly appear.
Can anyone suggest what I might be doing wrong?
Edit
Here's a download link to the project as it's quite small. Paste a path to an image in the 'Front Image' box and try using the controls on the right (set 100x100 height and width). Try re-sizing to see the desired affect. https://dl.dropboxusercontent.com/u/41796243/TemplateTester.zip
Controls and Forms have a Refresh method already. Are you really calling your Refresh method? Aren't you getting a warning that you should use the new keyword? Better give your Refresh method another name (e.g RefreshImage)!
I'm really not sure why you are using a picture box but then decide to do your on painting. I suggest to draw to an image off-screen and then simply assign it to the picture box:
public void RefreshImage()
{
Bitmap bmp;
if (this.rdFront.Checked)
bmp = new Bitmap(front);
else
bmp = new Bitmap(back);
using (Graphics gfx = Graphics.FromImage(bmp)) {
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front))
{
if (includeBoxes) {
// Fill a White rectangle and then surround with a black border
gfx.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
gfx.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
gfx.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
pbImage.Image = bmp;
}
and remove the pbImage_Paint method.
Another possibility is to use the pbImage_Paint event handler in another way. Call the base.Paint() handler of the picture box that draws the image but leave the image itself unchanged. Instead draw on top of it by using the Graphics object given by the PaintEventArgs e argument. This Graphics object represents the client area of the picture box. This does not alter the Bitmap assigned to the picture box, but only draws on the screen.
private void pbImage_Paint(object sender, PaintEventArgs e)
{
base.Paint(); // Paints the image
if (this.rdFront.Checked)
RenderFront(e.Graphics, true);
else
RenderBack(e.Graphics, true);
}
public void RenderFront(Graphics g, bool includeBoxes)
{
foreach (MessageConfiguration config in this.config.Values.Where(c => c.Front)) {
if (includeBoxes) {
g.FillRectangle(Brushes.White, config.X, config.Y, config.Width, config.Height);
g.DrawRectangle(Pens.Black, config.X - 1, config.Y - 1, config.Width + 2, config.Height + 2);
}
g.DrawString(config.Text, new Font(FontFamily.GenericMonospace, config.FontSize), Brushes.Black, new PointF(config.X, config.Y));
}
}
I have some code where I draw a function graph into a PictureBox graphics. The code is implemented in the Paint event. At some point I want to save a bitmap of the content of the graphics in a file.
I already read the answers to this question, and didn't found what I was looking for.
What I need is both to draw in the PictureBox (or any other control that you suggest) so that I don't loose the drawing when the control is hidden or something (so I think I cannot CreateGraphics()) and be able to save that drawing in a button's click event.
I'm willing to put the drawing logic out of the Paint event if necesary.
Thanks in advance.
I went ahead and answered the question based on my assumption,
I created a new Winforms application
I added a panel and a button
I created a Bitmap named buffer, and in the Form1 constructor, initialized it to the size of the panel. Instead of drawing directly to the panel, I draw to the Bitmap, then set the panels background image buffer; This will add persistance to your graphics. If you truly wish to write to a file, I can show you that. Just ask.
To write to file you will need this namespace reference :
using System.IO;
I added the ImageToDisc function you were asking for.
Here is the Code :
Bitmap buffer;
public Form1()
{
InitializeComponent();
panel1.BorderStyle = BorderStyle.FixedSingle;
buffer = new Bitmap(panel1.Width,panel1.Height);
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics g = Graphics.FromImage(buffer))
{
g.DrawRectangle(Pens.Red, 100, 100,100,100);
}
panel1.BackgroundImage = buffer;
//writes the buffer Bitmap to a binary file, only neccessary if you want to save to disc
ImageToDisc();
//just to prove that it did write it to file and can be loaded I set the mainforms background image to the file
this.BackgroundImage=FileToImage();
}
//Converts the image to a byte[] and writes it to disc
public void ImageToDisc()
{
ImageConverter converter = new ImageConverter();
File.WriteAllBytes(#"c:\test.dat", (byte[])converter.ConvertTo(buffer, typeof(byte[])));
}
//Converts the image from disc to an image
public Bitmap FileToImage()
{
ImageConverter converter = new ImageConverter();
return (Bitmap)converter.ConvertFrom(File.ReadAllBytes(#"c:\test.dat"));
}
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.