Best way to refresh changes in an image - c#

I have a winform c# app.
I am using Emgu for comparing the motion differences between 2 images.
I impose the changes detected onto the 1st image so in affect the first image now looks identical to the second image.
I am overriding the onpaint event of a user control to draw the image. I have to Invalidate the usercontrol to force the onpaint event.
This works well but the memory still 'spikes' a bit. Is there a way to invalidate only the pixels that have changed - like regions for instance?
This is my current code:
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
if (CurrentFrame != null)
{
pe.Graphics.DrawImageUnscaled(CurrentFrame, 0, 0);
}
}
The CurrentFrame is a static Bitmap
Thanks

Related

DrawToBitmap returning blank image

I have a problem on creating bitmap image out of my winform application.
Situation:
I have a UserControl named as "CanvasControl" that accepts OnPaint method acting as canvas for my Draw Pad application. Inside this user control I have a function "PrintCanvas()" that will create a screenshot image of the UserControl into PNG file. Below is the PrintCanvas() function:
public void PrintCanvas(string filename = "sample.png")
{
Graphics g = this.CreateGraphics();
//new bitmap object to save the image
Bitmap bmp = new Bitmap(this.Width, this.Height);
//Drawing control to the bitmap
this.DrawToBitmap(bmp, new Rectangle(0, 0, this.Width, this.Height));
bmp.Save(Application.StartupPath +
#"\ExperimentFiles\Experiment1" + filename, ImageFormat.Png);
bmp.Dispose();
}
This user control (CanvasControl) is called out inside my main form where user will draw something and have an option to save afterwards using a save button. The save button will call out the "PrintCanvas()" function of the UserControl.
I get the output image file as expected, but the problem is it was a blank image.
What I have tried so far:
To test that it is not a syntax issue, I tried to transfer the PrintCanvas() function into my main form and surprisingly I get an image of the whole main form on file but the UserControl is not visible there.
Is there any other setup i missed out to make a winform UserControl printable?
UPDATE: (DRAWING ROUTINES)
User control acting as canvas - code here
The code in the question gave a first hint but the code in the link showed the source of the problem: You use a 'wrong' instance of the Graphics object for drawing:
protected override void OnPaint(PaintEventArgs e)
{
// If there is an image and it has a location,
// paint it when the Form is repainted.
Graphics graphics = this.CreateGraphics();
..
This is one of the most common mistakes with winforms graphics! Never use CreateGraphics ! You always should draw onto the control surface with the Graphics object in a Paint or DrawXXX event. These events have a parameter e.Graphics which is the only one that can draw persistent graphics.
Persistent means that it will always be refreshed when necessary, not just when you trigger it. This is a nasty error because everything seems to work until you come upon a situation when an outside event makes redrawing necessary:
Minimizing and then maximizing the form
Moving it off the screen and back again
Calling DrawToBitmap
...
Note that all will only really work if you use the valid and current Graphics object from the PaintEventArgs e parameter.
So, the solution is simple:
protected override void OnPaint(PaintEventArgs e)
{
// If there is an image and it has a location,
// paint it when the Form is repainted.
Graphics graphics = e.Graphics(); // << === !!
..
But what is the CreateGraphics good for? It is only good for luring newbies into that error??
Not quite; here are some uses for it:
Drawing non-persistent graphics like a rubber-band rectangle or a special mouse cursor
Measuring text sizes without actually drawing it with a TextRenderer or the MeasureString method
Querying the screen or Bitmap resolution with Graphics.DpiX/Y
and probably some others I can't think of at the moment..
So for normal drawing onto controls always use the e.Grapahics object! You can pass it on to subroutines to make the code more structured, but do not try to cache it; it needs to be current!

Spurious lines when scrolling a GDI+ object

I am following a GDI+ tutorial, and in the section Drawing Shapes and Lines there's a simple example that draws a filled rectangle, filled ellipse and filled line in a scrolling window. It seems to work fine, but when I scroll down and back up it doesn't scroll properly as shown:
The OnPaint method is:
protected override void OnPaint(PaintEventArgs e)
{
Graphics dc = e.Graphics;
Point ScrollOffset = this.AutoScrollPosition;
dc.TranslateTransform(ScrollOffset.X, ScrollOffset.Y);
if (e.ClipRectangle.Top + ScrollOffset.X < 350 ||
e.ClipRectangle.Left + ScrollOffset.Y < 250)
{
dc.DrawRectangle(BluePen, rectangleBounds);
dc.FillRectangle(CrossBrush, rectangleBounds);
dc.DrawEllipse(RedPen, ellipseBounds);
dc.FillEllipse(SolidAzureBrush, ellipseBounds);
dc.DrawLine(BrickWidePen, rectangleBounds.Location, ellipseBounds.Location + ellipseBounds.Size);
}
base.OnPaint(e);
}
(The rest of the code can be seen at the page linked above, in case it matters).
If I minimise and restore it fixes the problem, so it looks as if the OnPaint method isn't getting called at the right time (is the window being scrolled between the OnPaint method being called and the paint actually occurring?). So how should I handle the paint so the scrolling doesn't corrupt the image?

Create Form fade out transition

How could you - in WinForms - create a black area that (over time) loses/gains transparency and is redrawn constantly so a kind of transition is created? I dont want to create a seperate form, so this would be very helpful and I could rearrange my new items as soon as the black area reaches a transparency of 0.
Left: What i have what at the moment:
Right: What the program looks like on startup
What I would want: A totally black screen
Override the OnPaint method of the form, and fill a rectangle the size of the form with the desired transparency. In this example, transparency keeps increasing:
var transparency = 0;
protected override OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// e.Graphics.DrawImage(Image, imageLeft, imageTop, imageWidth, imageHeight);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(transparency, Black)), this.ClientRectangle);
}
If you want to do this from a Timer event, inside the Tick event Invalidate the form to force the paint.
protected void MyTimer_Tick(object sender, eventArgs e) {
transparency++;
MyForm.Invalidate();
}
If you need to draw on top of the PictureBox, that presents a problem. One way to solve it is to get rid of the PictureBox and draw the image using Graphics.DrawImage before you draw the fade. If you want to show the image but have the black go up against the edges of your animal, then make it's background color of the PictureBox transparent and convert your image to use a PNG or GIF with all around the animal transparent in the original image.
For more complex effects, Check out the dot-net-transitions project on Google Code. It supports a variety of linear/non-linear transitions.

c# Override high-contrast for background image

I wasn't able to find an answer for this:
I have a background image on my form that I want to remain visible even when the system is on High Contrast mode. Is there code that can be entered that overrides the HC mode?
I've tried this on the Form Load event but no luck- no definition for graphics. (Not sure this would even be a viable solution):
OnPaint: e.Graphics.DrawImage(new Bitmap(BackgroundImage), 0, 0);
Aside from creating a PictureBox across my form and putting the image that way, does anyone know of a way to show the BG image of the form always?
Override the OnPaintBackground method:
protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.DrawImage(new Bitmap(BackgroundImage), e.ClipRectangle);
}
This DrawImage overload will stretch the image to fit the rectangle. If the ClipRectangle doesn't work (sorry, I can't test this right now!), create a new Rectangle with the background dimensions

.NET UserControl: Size property gives incorrect value on Resize event

Excuse the code dump, these are functions within a UserControl
private void PNGQuantPreviewControl_Resize(object sender, EventArgs e)
{
createOffScreenBm();
draw();
}
private void createOffScreenBm()
{
offScreenBm = new Bitmap(this.Size.Width, this.Size.Height);
offScreenGfx = Graphics.FromImage(offScreenBm);
}
private void draw()
{
// draw background
offScreenGfx.FillRectangle(transTexture, 0, 0, offScreenBm.Width, offScreenBm.Height);
// draw image preview
offScreenGfx.DrawImage(pngQuantPreview, getTopLeftPosition());
// apply to picture box
this.CreateGraphics().DrawImage(offScreenBm, 0, 0);
}
So, when the control changes size, it recreates the offscreen bitmap to reflect the new size and redraws the image.
However, if I quickly resize the control the bitmap doesn't fill it, there's a gap left at the right and/or bottom.
I'm fairly new to C#, so there's probably something obvious I'm doing wrong, or I'm reading the size values at the wrong time. Any ideas?
First of all you need to overwrite OnPaint method, or subscribe to Paint event and draw everything there.
Second you do not need to create offscreen bitmap for double buffering, because in .net already exist class for such purposes BufferedGraphics.
And third, it is much better to create UserControl descedant and enable internal .net double buffering, something like this:
public UserControl2
{
SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
}
Using this approach you will get double-buffering, and all you need is to draw your graphics in OnPaint method. You can read more about this control styles in Msdn.
Have you considered overriding the OnPaint method and placing the code within that method? This would result in your drawing code being executed any time the control needs to be redrawn, regardless of the reason.
A resize event does not necessarily wait until you are finished resizing the parent container. When the resize event is raised it needs to wait until the code exits before it can capture a new resize event so when the window/control is resized quickly, it can't keep up all that well and what you get is the last time it was able to capture the event, not necessarily the final state of the control ... if that makes any sense.
Do you have anything like a splitter on your control, or a MinSize or MaxSize declared?

Categories