How to resize a graphic? - c#

I have two pictureBoxes "source" and "dest". Now I would like to resize the "source" image and display it in my "dest"-picturebox.
Question:
How can I resize my "source" image and display it in my "dest"-picturebox?
Here is my code which only display the same image again:
private void pictureBoxZoom_Paint(object sender, PaintEventArgs e)
{
var settings = new Settings();
// Create a local version of the graphics object for the PictureBox.
Graphics Draw = e.Graphics;
Draw.ScaleTransform(2, 2); // rescale by factor 2
IntPtr hDC = Draw.GetHdc(); // Get a handle to pictureBoxZoom.
Draw.ReleaseHdc(hDC); // Release pictureBoxZoom handle.
}

In each case, you have to handle the PictureBox.SizeMode-Property. It determines what the PictureBox does to the image when painting.
If you want to apply a customized Zoom-factor, you can use the Graphics.ScaleTransform-Property. It allows you to scale the complete graphics. The Scaling can be done on the image itself by creating a bitmap (which has a Graphics-object you can use) or by overriding the PictureBox.OnPaint-Method, which requires you to create a class deriving from PictureBox. That's the most flexible attempt because you can control everything by yourself - if you like to.ยด
EDIT:
Sorry for not being clear enough, the way using the Paint-event does not work. You need to make your own PictureBox-class (derive from PictureBox) and override the OnPaint-method. Then you can call ScaleTransform on the Graphics-object the PictureBox uses. I got a tested sample for you:
public class PictureBoxScaleable : PictureBox
{
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.ScaleTransform(.2f, .2f);
base.OnPaint(pe);
}
}

Related

WinForms - How do I run a function with PaintEventArgs when the form is loaded?

I'm trying to understand the graphics, and in the Graphics.FromImage documentation, it has this as an example:
private void FromImageImage(PaintEventArgs e)
{
// Create image.
Image imageFile = Image.FromFile("SampImag.jpg");
// Create graphics object for alteration.
Graphics newGraphics = Graphics.FromImage(imageFile);
// Alter image.
newGraphics.FillRectangle(new SolidBrush(Color.Black), 100, 50, 100, 100);
// Draw image to screen.
e.Graphics.DrawImage(imageFile, new PointF(0.0F, 0.0F));
// Dispose of graphics object.
newGraphics.Dispose();
}
I'm new to C# and Windows Forms and am struggling to understand how this all fits together. How is this code run, say when the form first loads or when a button is pressed?
Maybe this will help. I have an example of both drawing on Paint events but also drawing on top of an existing Image. I created a form with two picture boxes. One for each case. pictureBox1 has an event handler for the .Paint event, while pictureBox2 is only drawn when a button is pressed.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
pictureBox1.BackColor=Color.Black;
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
// The code below will draw on the surface of pictureBox1
// It gets triggered automatically by Windows, or by
// calling .Invalidate() or .Refresh() on the picture box.
DrawGraphics(e.Graphics, pictureBox1.ClientRectangle);
}
private void toolStripButton1_Click(object sender, EventArgs e)
{
// The code below will draw on an existing image shown in pictureBox2
var img = new Bitmap(pictureBox2.Image);
var g = Graphics.FromImage(img);
DrawGraphics(g, pictureBox2.ClientRectangle);
pictureBox2.Image=img;
}
void DrawGraphics(Graphics g, Rectangle target)
{
// draw a red rectangle around the moon
g.DrawRectangle(Pens.Red, 130, 69, 8, 8);
}
}
So when you launch the application a red rectangle appears on the left only, because the button hasn't been pressed yet.
and when the button is pressed, the red rectangle appears on top of the image displayed in pictureBox2.
Nothing dramatic, but it does the job. So depending on the mode of operation you need (user graphics, or image annotations) use the example code to understand how to do it.

Convert Graphics object to Bitmap

I do have following issue with my graphics object.
EDIT:
I do have a picturebox_image (imageRxTx) which is a live stream from a camera. What I do in the paint event is to draw some lines on top of the image imageRxTx (not shown in the code below). This works so far without problem.
Now I need to check for circles in imageRxTx and therefore I have to use the method ProcessImage() which needs a Bitmap as parameter. Unfortunately I do not have the Bitmap image but rather the handle (hDC) to my imageRxTx.
Question: How can I get the imageRxTx from my graphics-object and "convert" it to a bitmap-image which I need to use in the method ProcessImage(Bitmap bitmap)? This method needs to be called continously in the paint-event in order to check the live-stream of my camera (imageRxTx).
Here my code:
private void imageRxTx_paint(object sender, PaintEventArgs e)
{
var settings = new Settings();
// Create a local version of the graphics object for the PictureBox.
Graphics Draw = e.Graphics;
IntPtr hDC = Draw.GetHdc(); // Get a handle to image_RxTx.
Draw.ReleaseHdc(hDC); // Release image_RxTx handle.
//Here I need to send the picturebox_image 'image_RxTx' to ProcessImage as Bitmap
AForge.Point center = ProcessImage( ?....? );
}
// Check for circles in the bitmap-image
private AForge.Point ProcessImage(Bitmap bitmap)
{
//at this point I should read the picturebox_image 'image_RxTx'
...
The video image is updated here:
private void timer1_Elapsed(object sender, EventArgs e)
{
// If Live and captured image has changed then update the window
if (PIXCI_LIVE && LastCapturedField != pxd_capturedFieldCount(1))
{
LastCapturedField = pxd_capturedFieldCount(1);
image_RxTx.Invalidate();
}
}
As the title suggests, your main problem is a (common) misconception about what a Graphics object is.
So far I can draw to my graphics object without problem
No! A 'Graphics' object does not contain any graphics. It is only the tool used to draw graphics onto a related Bitmap. So you don't draw onto the Graphics object at all; you use it to draw onto imageRxTx, whatever that is, probably the surface of some Control or Form..
This line is using an often confusing rather useless format of the Bitmap constructor:
Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height, Draw);
The last parameter is doing next to nothing; its only function is to copy the Dpi setting. In particular it does not clone or copy any content from 'Draw', which, as you know now, a Graphics object doesn't have anyway, nor any of its other settings. So yes, the bmp Bitmap is still empty after that.
If you want to draw into bmp you need to use a Graphics object that is actually bound to it:
using (Graphics G = Graphics.FromImage(bmp)
{
// draw now..
// to draw an Image img onto the Bitmap use
G.DrawImage(img, ...);
// with the right params for source and destination!
}
None of this should probably happen in the Paint event! But all the preparation code is unclear as to what you really want to do. You should explain just what is the source of the drawing and what is the target!
If instead you want to get the stuff you draw onto image_RxTx into a Bitmap you can use this method somwhere outside (!) the Paint event:
Bitmap bmp = new Bitmap(image_RxTx.Width, image_RxTx.Height);
image_RxTx.DrawToBitmap(bmp, image_RxTx.ClientRectangle);
This will use the Paint event to draw the control into a Bitmap. Not that the result includes the whole PictureBox: The BackgroundImage, the Image and the surface drawing!
Update: To get the combined content of the PictureBox, that is both its Image and what you have drawn onto the surface, you should use the code above (the last 2 lines) in the Tick event of a Timer or right after the line that triggers the Paint event. (You didn't show us how that happens.) You can't acutally put it in the Paint event itself, as it will use the Paint event and therefore would cause an infinite loop!
The method Graphics.CopyFromScreen is probably what you're looking for.
var rect = myControl.DisplayRectangle;
var destBitmap = new Bitmap(rect.Width, rect.Height, PixelFormat.Format24bppRgb);
using (var gr = Graphics.FromImage(destBitmap))
{
gr.CopyFromScreen(myControl.PointToScreen(new Point(0, 0)), new Point(0, 0), rect.Size);
}

my png file is not showing in my picturebox

I want display an image in my picture box but when I run the code everything else works except the image isn't displayed. Here is the relevant code:
Image[] deadWoman = new Image[5]; //this array will hold the images of bit and pieces of katie
deadWoman[0] = Image.FromFile("F:/Jers Hangman Game/Jers Hangman Game/Resources/katie-hopkins.jpeg");
private void MainPic_Paint(object sender, PaintEventArgs e)
{
Graphics katie = e.Graphics; // creates a graphics object for the picture box
if (numWrongGuesses > 0)
{
e.Graphics.DrawImage(deadWoman[0], 20, 20,60,60);
}
}
I guess the image is never repainted, that's why you don't see it when numWrongGuesses is updated. You should Invalidate() the PictureBox in order to see the update.
I would advise to set the image though, and simply use Visible = true and Visible = false for showing and hiding. You could even set the BackgroundImage if you need to create some overlay effect.
You don't override Paint in order to put an Image object into a PictureBox. Just use the property:
MainPic.Image = deadWoman[0];
You can also do this in the WinForms designer, as long as the Image is a resource.
Also, you can hide and show your image by the .Visible property:
MainPic.Visible = numWrongGuesses > 0;

Draw and resize an image over a specific region

I'm creating a control that inherits from a Windows.Forms.Panel and has a specific region onto which I want to draw an image.
This code draws the image over the region I want, but doesn't stretch it.
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.FillRegion(new TextureBrush(ContentImage), ContentRegion);
regionNeedsRefresh = false;
}
This code draws the image over the rectangle I want, and stretches it to fit the rectangle, but it doesn't draw over the exact region I want:
private void PaintPanel(Graphics _g)
{
_g.FillRegion(new SolidBrush(BorderColor), BorderRegion);
_g.DrawImage(ContentImage, ContentRegion.GetBounds(_g));
regionNeedsRefresh = false;
}
So what I need is a bit of both solutions I'm guessing...
Any help would be much appreciated!
You can use Graphics.DrawImage, and simply set the Clip property of the Graphics object to the Region you want to draw in before and after the operation.

Cast Graphics to Image in C#

I have a pictureBox on a Windows Form.
I do the following to load a PNG file into it.
Bitmap bm = (Bitmap)Image.FromFile("Image.PNG", true);
Bitmap tmp;
public Form1() {
InitializeComponent();
this.tmp = new Bitmap(bm.Width, bm.Height);
}
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(this.bm, new Rectangle(0, 0, tmp.Width, tmp.Height), 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel);
}
However, I need to draw things on the image and then have the result displayed again. Drawing rectangles can only be done via the Graphics class.
I'd need to draw the needed rectangles on the image, make it an instance of the Image class again and save that to this.bm
I can add a button that executes this.pictureBox1.Refresh();, forcing the pictureBox to be painted again, but I can't cast Graphics to Image. Because of that, I can't save the edits to the this.bm bitmap.
That's my problem, and I see no way out.
What you need to do is use the Graphics.FromImage method, which will allow you to draw directly on the image instead of the temporary Graphics object create from within the Paint method:
using (Graphics g = Graphics.FromImage(this.bm))
{
g.DrawRectangle(...);
}
Do this instead of (or in addition to) hooking the Paint method of the PictureBox. This way, you won't need to use a temporary image or Graphics object at all, and when you're finished modifying the original bitmap (this.bm) then you can invoke pictureBox1.Refresh to force the image to be re-displayed.

Categories