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.
Related
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.
I have a problem as follow:
I basically have a code that generates a series of bitmap images. At the end of each iteration I use:
I was expecting that after all the iterations being completed, I end up with a new list which is consisting of different images. However I just realised that in my list-1 only the same image is going to be copied again and again.
Can anyone tell me if I am making any mistake in my code?
You likely need to make a new image for each loop iteration in the "code that generates a series of bitmap images" (in the code you're not displaying).
If you reuse the same image (the bmp variable), without creating a new image, (ie: bmp = new Bitmap(width, height) or similar), you'll end up overwriting and reusing the same image in memory for each loop iteration, which explains your current behavior.
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;
I've got many images from an external source (umnanaged dll) which are to be displayed on a WPF canvas. The external source renders the images and passed back a pointer (IntPtr) to umnanaged memory, as well as size, stride etc.
Currently, I'm loading these images into a WriteableBitmap and then displaying the in the OnRender method of the Canvas. The WriteableBitmap fits this task very nicely.
WriteableBitmap temp = new WriteableBitmap(ImageWidth, ImageHeight, 96, 96, PixelFormat, null);
temp.WritePixels(new Int32Rect(0, 0, ImageWidth, ImageHeight), pointerToImageData, ImageHeight * stride, (int)stride);
Questions:
Does the WritableBitmap first copy the Image Data to another place (in managed memory)?
If so, is there any way to directly render the Image Data on screen (e.g. using DirectX?)
Are there any other tips and tricks which I could use?
Thanks and best whishes
Daniel
Edit: Tried after suggestion by Clemens: using BitmapSource.Create, using this methods heightens the memory consumtion to the point where I start suspecting that the method copies the whole image and Writeable bitmap may not.
WPF's Image control displays ImageSource, you need to convert your image to it, and not just Drawing.Image. Use System.Windows.Interop.Imaging to convert the image.
I'm not sure how your image is saved in the unmanaged memory, but you can use one of two methods. If it's saved as a bitmap you may be able to use CreateBitmapSourceFromHBitmap.
Or you may need to use CreateBitmapSourceFromMemorySection, here's how: http://social.msdn.microsoft.com/Forums/vstudio/en-US/a8d86cd0-10cc-4349-aa9c-e62d7d066508/createbitmapsourcefrommemorysection.
As for the memory allocation, you would always have to copy the image, aside from the fact that you'll have to convert the image to managed memory, the UI thread can't work with anything it didn't create. You must copy the image using the UI thread before you can display it.
The Layout:
I'm using third party controls to scan documents. I have an event that occurs when I scan an image (mostly used to add annotations the image). The event provides me with only one property named .PAhDC. This property is a handle to the DC that stores the image before it is written to a file. Thus I can make changes to the image before it gets written to a file.
The Expected Results:
I would like to simply add a 1/4 inch (lets say 100 pixels) of white space line on the very top of the image. If my original image is 200x200 (WxH) then my new final image would need to be 200x300.
Question And Other Thoughts:
How can I alter an existing image with only knowing it's DC handle? I was thinking of doing something like the following...
Create a new DC.
Create a new Bitmap 100 pixels taller than the original image.
Use that new bitmap in the new DC.
Copy the original image to the new bitmap (100 pixels from the top as a start point).
Then use something like SelectObject to replace the old bitmap in the original hDC with the new one and then destroy the old bitmap object.
Note: I would like to do this with MANAGED CODE as much as possible. Using SelectObject() was the only way I could think of but it's of course unmanaged code... :/
You can't without cooperation with the owner of the bitmap and DC.
The DeviceContext is purely a viewport onto an underlying DIB/bitmap and has no concept of size or dimensions (beyond the clipping region) While you can create a new bitmap and select it into the DC, it's highly likely that the application will just ignore what you've done and use the DIB that it has created.
The end result of this will be GDI object leaks and no change to the underlying image.
To do what you you ask, you will need full cooperation with the other code and them adding a method that allows you to replace the underlying data.
Sure, you can do this in managed code. All P/Invoke declarations are readily available from any decent search engine.
When creating a new DC, make sure it's a DC compatible with the original one
When creating a new bitmap, make sure it's compatible with the DC