Set C# Picturebox to Bitmap - c#

I have a very basic problem. I have a variable of type: Bitmap. This variable updates with every frame received from the webcam. This variable is declared as follows:
Bitmap img=eventArgs.Frame;
I have verified that the above line is working properly.
All I need to know now is how to set my PictureBox on my form to this Bitmap image. I have tried the following:
pbImg.Image=img;
This doesn't work. Any help would be greatly appreciated.

Bitmaps generated by a camera normally only have a very short life-time. They are only valid while the event handler runs, the camera capture driver replaces the bitmap with a new frame. Pretty essential to avoid excessive memory usage.
You must therefore make a deep copy of the image so that it can survive in the PictureBox and still get painted after the event call completed. Like this:
Bitmap img = new Bitmap(eventArgs.Frame);
if (pbImg.Image != null) pbImg.Image.Dispose();
pbImg.Image = img;

Related

What's the best method for rendering a decoded frame?

After decoding and reaching to a frame, I need to know the best method for rendering it. I use Bitmap for this purpose, but every time I have to create a new bitmap, one for each frame. Maybe this is not the best method, since lots of memory is consumed and rebuilding bitmaps may take time. To clarify, I give the code:
ret = FFmpegInvoke.sws_scale(
convertContext,
&frame->data_0,
frame->linesize,
0,
frame->height,
&convertedFrame->data_0,
convertedFrame->linesize);
Debug.Assert(ret >= 0);
var bmp = new Bitmap(dest_width, dest_height,
convertedFrame->linesize[0], PixelFormat.Format32bppPArgb,
new IntPtr(convertedFrame->data_0));
pictureBox1.Image = bmp;
I've added a picture box control to my form. I create a Bitmap from every decoded and converted frame's data and then set the picture box's image to the bitmap.
After finding the best method, and knowing whether I've done correctly, I need to know why is my problem with a background worker I put in the form. Apparently concurrent accessing to the bitmap object causes exception. Nevermind, first I need to make sure about this one.

Image in the interface is not updated after WritableBitmap has changed

I am trying to update the image by drawing circles every time mouse pointer is moved. The pixelBuffer is stored in map object and updated with CircleFilledWithGradientMethod(). I load the pixel buffer in to WriteableBitmap Bitmap and then try to display it by setting image source of an image element in my XAML UI to Bitmap. What happens, is that when I first move my mouse, I see the very first 2 circles drawn but then as I move the mouse, the image does not get updated. Why could that be? Is there a method I should call on Image to force it to redraw? The reason I use stream.WriteAsync two times, when I could have just used it one, is just to show that it is working properly.
private async void TextArea_PointerMoved(object sender, PointerRoutedEventArgs e)
{
Pixel pixel1 = new Pixel(255, 0, 0);
Pixel pixel2 = new Pixel(255, 255, 255);
map.CircleFilledWithGradient((int) pointer.Position.X, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
map.CircleFilledWithGradient((int)pointer.Position.X+100, (int)pointer.Position.Y, 100, pixel1, pixel2);
using (Stream stream = Bitmap.PixelBuffer.AsStream())
{
stream.WriteAsync(map.pixelData, 0, map.pixelData.Length);
}
this.Image.Source = Bitmap;
}
What I think is happening, is that as soon as I draw the image on the screen, it caches it, and then keeps using the old image. Or is it that the standard Image element does not support redrawing?
Update:
My Bitmap was a private class variable. If I do
WriteableBitmap Bitmap = new WriteableBitmap((int)this.ActualWidth, (int)this.Grid.RowDefinitions[1].ActualHeight);
It all starts to work, but isn't that memory inefficient? Aren't I allocating memory for each new WriteableBitmap each time I move my mouse. And as I have found out, the issue is definitely with with Image component. Why wouldn't it update when I just make changes to it's source, but updates when I change its source to a different object.
`
Is there a method I should call on Image to force it to redraw?
Close. There's a method on WriteableBitmap.
Call WriteableBitmap.Invalidate after you update it to request the refresh.
Assuming the Bitmap was already set as Image.Source, replace the line:
this.Image.Source = Bitmap;
With:
Bitmap.Invalidate();
Why wouldn't it update when I just make changes to its source, but updates when I change its source to a different object.
Setting the Image.Source to the same thing it's already set to is a noop. Most complex Properties ignore "changes" which don't change the existing value. Creating a new WriteableBitmap each time works (very inefficiently) because it's different.

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!

How to cache the image of the control?

I have C# app, but the painting job is done within C++ project (this is how it has to be).
So I added to my window PictureBox, and passed the handle to the drawing function. It works fine.
However when the control is invalidated (I move the window outside the screen and then move it back), I get in result partially empty window. AFAIK there are two approaches for this -- repaint or cache the image.
Repainting could be costly process (the image does not change often, but processing is time consuming, think of 3d renderer), so I would like to simply cache the image.
If I remember correctly from old days of programming directly with Win32 API all it takes is to set some flags. Is it possible with WinForms? If yes, how?
This will help:
Bitmap getControlSurface(Control ctl)
{
bitmap = new Bitmap(ctl.Width, ctl.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
Point pScreen = PointToScreen(ctl.Location);
g.CopyFromScreen(pScreen, Point.Empty, ctl.Size);
}
return bitmap;
}
If you know when the surface has been refreshed you can use it like this:
if ( pictureBox1.Image != null) pictureBox1.Image.Dispose();
pictureBox1.Image = getControlSurface(pictureBox1);
The only catch is that the PictureBox actually must be completely visible on the screen!

c# picturebox bitmaps

I have a picturebox that upon request, I save the current display to a bitmap.
My question is, how do I then load that same bitmap to the picturebox?
Thanks.
EDIT:
The only relevant code is:
pictureBox1.DrawToBitmap(test1,pictureBox1.ClientRectangle);
The picture box contains graphics that I have written 'freehand' using the mouse. So you can use the mouse to write directly onto the screen when the left mouse is pressed.
You can assign any image to the picture box that you want during run-time. Just set the Image property of the picture box to the picture you want to be displayed.
For example, to display an image in a picture box from a file on your hard drive, you could use something like:
myPicBox.Image = Image.FromFile("C:\savedimage.bmp");
Or, your edit suggests that you have a bitmap object in memory that you want to display in the picture box. In that case, it's a simple matter of assigning that bitmap object to the Image property:
myPicBox.Image = test1; //(where test1 is your bitmap object in memory)
Edit: Just in case you want to save the bitmap object that you created in memory to disk so that you can reload and use it later, check out the Save method of the Bitmap object:
test1.Save("C:\savedimage.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
If I'm not mistaken, the picturebox should have an Image property that you can simply use to assign the Bitmap to.

Categories