Memory leak in Imaging.CreateBitmapSourceFromHBitmap - c#

I have next function (makes screenshot)
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
private Screen SavedScreen { get; } = Screen.PrimaryScreen;
private BitmapSource CopyScreen()
{
try
{
BitmapSource result;
using (
var screenBmp = new Bitmap(SavedScreen.Bounds.Width, SavedScreen.Bounds.Height, PixelFormat.Format32bppArgb))
{
using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
CopyPixelOperation.SourceCopy);
IntPtr hBitmap = screenBmp.GetHbitmap();
//********** Next line do memory leak
result = Imaging.CreateBitmapSourceFromHBitmap( hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
}
}
return result;
}
catch (Exception ex)
{
//ErrorReporting ($"Error in CopyScreen(): {ex}");
Debugger.Break();
return null;
}
}
And cannot avoid memory leak which is a result of calling Imaging.CreateBitmapSourceFromHBitmap. As I call this function in a cycle this memory leak is very important for me.
Called in WPF application (Windows, c#)

As you already know, you have to Dispose() screenBmp.
You are actually calling it by an using statement, so that should be fine, but I suspect the try/catch could interfere.
Do you have a chance to move the try/catch so that only the CopyFromScreen and CreateBitmapSourceFromHBitmap are surrounded?
From comments
Since only after that closing brace of the using statement you are sure that the screenBmp can be disposed, I'm forcing a GC collect there
GC.Collect();
return result;
and it doesn't seem leaking.
Here is my demo
class Program
{
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
private static Screen SavedScreen { get; } = Screen.PrimaryScreen;
private static BitmapSource CopyScreen()
{
//try
//{
BitmapSource result;
using (
var screenBmp = new Bitmap(200, 100))
{
using (Graphics bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(SavedScreen.Bounds.X, SavedScreen.Bounds.Y, 0, 0, screenBmp.Size,
CopyPixelOperation.SourceCopy);
IntPtr hBitmap = screenBmp.GetHbitmap();
bmpGraphics.Dispose();
//********** Next line do memory leak
result = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(hBitmap);
//result = null;
}
}
GC.Collect();
return result;
//}
//catch (Exception ex)
//{
// //ErrorReporting ($"Error in CopyScreen(): {ex}");
// Console.WriteLine(ex.Message);
// Debugger.Break();
// return null;
//}
}
static void Main(string[] args)
{
for (int i = 0; i < 100000; i++)
{
Thread.Sleep(100);
var test = CopyScreen();
}
}
}

As you are working with bitmaps (screen size) it means expected data size is bigger than 85000 bytes. The objects of such sizes are treated differently by GC.
It is called LOH. See https://blogs.msdn.microsoft.com/maoni/2016/05/31/large-object-heap-uncovered-from-an-old-msdn-article/, it was improved in 4.5 https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
But the problem is still here. Accounting huge objects with high frequency leads to significant increase of memory usage of your application. There're 2 problem leads to it: 1) GC does not work immediatly, it takes time before it started freeing memory; 2) fragmentation of LOH (see the first article), this is why it is not freed and this is why you can see the memory usage is increased.
Possible solutions:
1) Use server GC and concurent GC; force GC manually. Most likely it does not help greatly.
2) Re-use existing object(allocated memory) instead of creating new Bitmap and Graphics all the time in a loop.
3) Switch to use Windows API directly and handle allocations manually.

Related

IntPtr - Memory & GDI leak [C#]

The Problem:
When taking Screenshots of a Screen (in a loop) I get a RAM and GDI leak.
private Bitmap GetSS(int ScreenWidth, int ScreenHeight, int ScreenWidthCut, int ScreenHeightCut)
{
int ScreenLocWidth = Screen.PrimaryScreen.Bounds.Width - ScreenWidth;
int ScreenLocHeight = Screen.PrimaryScreen.Bounds.Height - ScreenHeight;
IntPtr dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);
//Create the DC of the display
Graphics g1 = Graphics.FromHdc(dc1);
//Create a new Graphics object from the handle of a specified device
Bitmap MyImage = new Bitmap(ScreenWidthCut, ScreenHeightCut, g1);
//Create a Bitmap object of the same size according to the screen size
Graphics g2 = Graphics.FromImage(MyImage);
//Get the handle of the screen
IntPtr dc3 = g1.GetHdc();
//Get the handle of the bitmap
IntPtr dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, ScreenWidth, ScreenHeight, dc3, ScreenLocWidth, ScreenLocHeight,
(int)CopyPixelOperation.SourceCopy | (int)CopyPixelOperation.CaptureBlt);
g1.ReleaseHdc(dc3);
//Release the screen handle
g2.ReleaseHdc(dc2);
//Release the bitmap handle
DeleteObject(dc1);
DeleteObject(dc2);
DeleteObject(dc3);
return MyImage;
}
Debugging gave me these lines which are potentially causing the leak.
//Get the handle of the screen
IntPtr dc3 = g1.GetHdc();
//Get the handle of the bitmap
IntPtr dc2 = g2.GetHdc();
With the following I am trying to release and delete the objects created, with no effect.
g1.ReleaseHdc(dc3);
//Release the screen handle
g2.ReleaseHdc(dc2);
//Release the bitmap handle
DeleteObject(dc1);
DeleteObject(dc2);
DeleteObject(dc3);
I found a solution using the GarbageCollector. That works! No more memory nor GDI leak. I simply call
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
after I call "GetSS".
But I would like to understand why releasing and deleting the objects manually doesn't work, I want to avoid using the GarbageCollector at all if possible.
EDIT: This is how I call GetSS
while (startLoc.x == 0)
{
using (Bitmap imgScene = GetSS(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Screen.PrimaryScreen.Bounds.Width, (int)(Screen.PrimaryScreen.Bounds.Height * 0.20)))
{
//the stuff I do with the image is commented out for testing purposes, this is not causing th leak
}
Thread.Sleep(10);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
}
And this is for deleting the Object:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
Stay healthy everyone.
If a forced GC solves the problem, it is probably due to some finalizer kicking in and freeing memory. That hints that it might be some disposable object not being disposed. The Graphics class are IDisposable, so they should be inside a using statement to ensure disposal. The bitmap seem to be correctly disposed outside the function.
This suggest that the corresponding function for CreateDC is DeleteDC.
I might also recommend releasing all resources inside finally-statements, to ensure they are disposed even if some exception occur.
You are missing using blocks, and also DeleteObject should be DeleteDC, which should also be in a finally.
Also, dc3 is not necessary as you have that already in dc1.
private Bitmap GetSS(int ScreenWidth, int ScreenHeight, int ScreenWidthCut, int ScreenHeightCut)
{
int ScreenLocWidth = Screen.PrimaryScreen.Bounds.Width - ScreenWidth;
int ScreenLocHeight = Screen.PrimaryScreen.Bounds.Height - ScreenHeight;
Bitmap MyImage;
IntPtr dc1 = IntPtr.Zero;
IntPtr dc2 = IntPtr.Zero;
try
{
dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);
//Create the DC of the display
//Create a Bitmap object of the same size according to the screen size
using (Graphics g1 = Graphics.FromHdc(dc1))
{
MyImage = new Bitmap(ScreenWidthCut, ScreenHeightCut, g1);
using (Graphics g2 = Graphics.FromImage(MyImage))
{
//Get the handle of the bitmap
dc2 = g2.GetHdc();
BitBlt(dc2, 0, 0, ScreenWidth, ScreenHeight, dc1, ScreenLocWidth, ScreenLocHeight,
(int)CopyPixelOperation.SourceCopy | (int)CopyPixelOperation.CaptureBlt);
}
}
}
catch
{
MyImage?.Dispose();
throw;
}
finally
{
//Release the bitmap handle
if (dc1 != IntPtr.Zero)
DeleteObject(dc1);
if (dc2 != IntPtr.Zero)
g2.ReleaseHdc(dc2);
}
return MyImage;
}
Don't forget that the image you return also must be disposed at some point.

OutOfMemory exception with BitmapSource in WPF app

Task: I got 2 monitors. And I need to show on #1 what is going on #2. In another words, first monitor is nothing but a reflector of second.
Current solution: Just making screenshot every ~100ms and re-render.
Following method is responsible for capturing screenshots:
private BitmapSource MakeScreenshot(Screen screen)
{
using (var screenBmp = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb))
{
using (var bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size);
return
Imaging.CreateBitmapSourceFromHBitmap(
screenBmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
}
}
After that I uset Start(...) method to run my "reflection" from second screen to first:
public void Start(int delay, int period)
{
if (_timer != null) throw new InvalidOperationException();
_timer = new System.Threading.Timer(
_ =>
{
_placeholder
.Dispatcher
.Invoke(() =>
{
_placeholder.Source = MakeScreenshot(_targetScreen); // re-render new screenshot
});
},
null,
delay,
period);
}
Problem: After around 30-40 second of pretty nice run it fails with OutOfMemoryException. I've investigated some of posts here, but found nothing regarding my problem.
That is because you leak memory here:
Imaging.CreateBitmapSourceFromHBitmap(
screenBmp.GetHbitmap(), // < here
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
You need to free memory used by GDI bitmap after you call screenBmp.GetHbitmap(). Change that like this:
private BitmapSource MakeScreenshot(Screen screen)
{
using (var screenBmp = new Bitmap(screen.Bounds.Width, screen.Bounds.Height, PixelFormat.Format32bppArgb))
{
using (var bmpGraphics = Graphics.FromImage(screenBmp))
{
bmpGraphics.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size);
var handle = screenBmp.GetHbitmap();
try {
return
Imaging.CreateBitmapSourceFromHBitmap(
handle,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
finally {
DeleteObject(handle);
}
}
}
}
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
And it should not leak any more.

c# Image loader memory leak

I'm implementing a small imageviewer, unfortunately I'am facing a memory leak.
Following is my loading routine.
public BitmapSource getImage(string fileName, double width, double height)
{
FileStream s = File.Open(fileName, FileMode.Open);
Image i = Image.FromStream(s, false, false);
double iWidth = i.Width;
double iHeight = i.Height;
i.Dispose();
s.Close();
BitmapImage tmpImage = new BitmapImage();
tmpImage.BeginInit();
tmpImage.CacheOption = BitmapCacheOption.OnLoad;
tmpImage.UriSource = new Uri(fileName);
if (iWidth > iHeight)
{
tmpImage.DecodePixelWidth = (int)width;
}
else
{
tmpImage.DecodePixelHeight = (int)height;
}
tmpImage.EndInit();
return tmpImage;
}
This is how I call the loader
private void whenArrowKeyPressed(int index)
{
CurrentImage = fh.getImage(fileList[index], 1920, 1080);
}
CurrentImage is a property, which is bound to a WPF ViewBox.
Any Ideas?
I also tried to read from StreamSource, with the same effect.
Only issue I could see is you are not disposing you FileStream. BitmapImage is not Disposable and it will release its memory if there are no references to it.
How did you find there is a memory leak? It’s recommended to use a profiling tool. Garbage collector doesn't release memory immediately something goes out of scope, it waits until memory usages exceeds certain thresholds (usually when Gen 0 going to exceed the threshold). So, you will see some memory increase and it will release memory only after garbage collector executes.
Apparently you are not using a profiling tool. In this case if you want to check if there is any memory leak, you can manually execute GC.Collect and wait for finalization before you get memory reading. Keep in mind that you don’t have to execute GC.Collect manually as it will occur automatically in an optimized way when required.
public BitmapSource getImage(string fileName, double width, double height)
{
using(FileStream s = File.Open(fileName, FileMode.Open))
using(Image i = Image.FromStream(s, false, false))
{
double iWidth = i.Width;
double iHeight = i.Height;
}
BitmapImage tmpImage = new BitmapImage();
tmpImage.BeginInit();
tmpImage.CacheOption = BitmapCacheOption.OnLoad;
tmpImage.UriSource = new Uri(fileName);
if (iWidth > iHeight)
{
tmpImage.DecodePixelWidth = (int)width;
}
else
{
tmpImage.DecodePixelHeight = (int)height;
}
tmpImage.EndInit();
return tmpImage;
}
private void whenArrowKeyPressed(int index)
{
CurrentImage = fh.getImage(fileList[index], 1920, 1080);
// Remove this once you finish testing.
GC.Collect();
GC.WaitForPendingFinalizers();
}

InvalidArgumentException when taking screenshot

Every second, I capture my screen with the following code. The first 40/50 times work, after that I get an InvalidArgumentException at the first and third line of code.
Bitmap bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(bmpScreenshot);
g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size);
bmpScreen = bmpScreenshot;
Probably you need to dispose of some objects.
It's hard to tell from just the code shown, but my guess would be that you're not properly disposing of objects and are running out of memory. I know for sure that Graphics objects should be disposed, and the bitmap likely needs to be disposed of as well when you're done with it. Depending on how your error catching is set up, if you swallow an out of memory exception and keep going then new objects that don't fit in the available memory will not be instantiated and their constructors will return null. If you then pass null to a method that doesn't want to receive null, an InvalidArgumentException is likely to result.
Try wrapping your Disposable objects in using statements. I was able to repro your problem using the code below:
public static void Main()
{
var i = 1;
while (true)
{
var screenSize = Screen.PrimaryScreen.Bounds.Size;
try
{
var bmpScreenshot = new Bitmap(screenSize.Width, screenSize.Height);
var g = Graphics.FromImage(bmpScreenshot);
g.CopyFromScreen(0, 0, 0, 0, screenSize);
}
catch (Exception e)
{
Console.WriteLine("Exception ignored: {0}", e.Message);
}
finally
{
Console.WriteLine("Iteration #{0}", i++);
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}
By wrapping the disposables with using statements, the issue did not happen again:
public static void Main()
{
var i = 1;
while (true)
{
var screenSize = Screen.PrimaryScreen.Bounds.Size;
try
{
using (var bmpScreenshot = new Bitmap(screenSize.Width, screenSize.Height))
using (var g = Graphics.FromImage(bmpScreenshot))
{
g.CopyFromScreen(0, 0, 0, 0, screenSize);
}
}
catch (Exception e)
{
Console.WriteLine("Exception ignored: {0}", e.Message);
}
finally
{
Console.WriteLine("Iteration #{0}", i++);
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}

WPF CreateBitmapSourceFromHBitmap() memory leak

I need to draw an image pixel by pixel and display it inside a WPF. I am attempting to do this by using a System.Drawing.Bitmap then using CreateBitmapSourceFromHBitmap() to create a BitmapSource for a WPF Image control. I have a memory leak somewhere because when the CreateBitmapSourceFromBitmap() is called repeatedly the memory usage goes up and does not drop off until the application is ended. If I don't call CreateBitmapSourceFromBitmap() there is no noticeable change in memory usage.
for (int i = 0; i < 100; i++)
{
var bmp = new System.Drawing.Bitmap(1000, 1000);
var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,
System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
source = null;
bmp.Dispose();
bmp = null;
}
What can I do to free the BitmapSource memory?
MSDN for Bitmap.GetHbitmap() states:
Remarks
You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object.
So use the following code:
// at class level
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
// your code
using (System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(1000, 1000))
{
IntPtr hBitmap = bmp.GetHbitmap();
try
{
var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(hBitmap);
}
}
I also replaced your Dispose() call by an using statement.
Whenever dealing with unmanaged handles it can be a good idea to use the "safe handle" wrappers:
public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[SecurityCritical]
public SafeHBitmapHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
SetHandle(preexistingHandle);
}
protected override bool ReleaseHandle()
{
return GdiNative.DeleteObject(handle) > 0;
}
}
Construct one like so as soon as you surface a handle (ideally your APIs would never expose IntPtr, they would always return safe handles):
IntPtr hbitmap = bitmap.GetHbitmap();
var handle = new SafeHBitmapHandle(hbitmap , true);
And use it like so:
using (handle)
{
... Imaging.CreateBitmapSourceFromHBitmap(handle.DangerousGetHandle(), ...)
}
The SafeHandle base gives you an automatic disposable/finalizer pattern, all you need to do is override the ReleaseHandle method.
I had the same requirement and issue (memory leak). I implemented the same solution as marked as answer. But although the solution works, it caused an unacceptable hit to performance. Running on a i7, my test app saw a steady 30-40% CPU, 200-400MB RAM increases and the garbage collector was running almost every millisecond.
Since I'm doing video processing, I'm in need of much better performance. I came up with the following, so thought I would share.
Reusable Global Objects
//set up your Bitmap and WritableBitmap as you see fit
Bitmap colorBitmap = new Bitmap(..);
WriteableBitmap colorWB = new WriteableBitmap(..);
//choose appropriate bytes as per your pixel format, I'll cheat here an just pick 4
int bytesPerPixel = 4;
//rectangles will be used to identify what bits change
Rectangle colorBitmapRectangle = new Rectangle(0, 0, colorBitmap.Width, colorBitmap.Height);
Int32Rect colorBitmapInt32Rect = new Int32Rect(0, 0, colorWB.PixelWidth, colorWB.PixelHeight);
Conversion Code
private void ConvertBitmapToWritableBitmap()
{
BitmapData data = colorBitmap.LockBits(colorBitmapRectangle, ImageLockMode.WriteOnly, colorBitmap.PixelFormat);
colorWB.WritePixels(colorBitmapInt32Rect, data.Scan0, data.Width * data.Height * bytesPerPixel, data.Stride);
colorBitmap.UnlockBits(data);
}
Implementation Example
//do stuff to your bitmap
ConvertBitmapToWritableBitmap();
Image.Source = colorWB;
The result is a steady 10-13% CPU, 70-150MB RAM, and the garbage collector only ran twice in a 6 minute run.
This is a great(!!) post, although with all the comments and suggestions, it took me an hour to figure out the pieces. So here is a call to get the BitMapSource with SafeHandles, and then an example usage of it to create a .PNG image file. At the very bottom are the 'usings' and some of the references. Of course, none of the credit is mine, I am just the scribe.
private static BitmapSource CopyScreen()
{
var left = Screen.AllScreens.Min(screen => screen.Bounds.X);
var top = Screen.AllScreens.Min(screen => screen.Bounds.Y);
var right = Screen.AllScreens.Max(screen => screen.Bounds.X + screen.Bounds.Width);
var bottom = Screen.AllScreens.Max(screen => screen.Bounds.Y + screen.Bounds.Height);
var width = right - left;
var height = bottom - top;
using (var screenBmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
{
BitmapSource bms = null;
using (var bmpGraphics = Graphics.FromImage(screenBmp))
{
IntPtr hBitmap = new IntPtr();
var handleBitmap = new SafeHBitmapHandle(hBitmap, true);
try
{
bmpGraphics.CopyFromScreen(left, top, 0, 0, new System.Drawing.Size(width, height));
hBitmap = screenBmp.GetHbitmap();
using (handleBitmap)
{
bms = Imaging.CreateBitmapSourceFromHBitmap(
hBitmap,
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
} // using
return bms;
}
catch (Exception ex)
{
throw new ApplicationException($"Cannot CopyFromScreen. Err={ex}");
}
} // using bmpGraphics
} // using screen bitmap
} // method CopyScreen
Here is the usage, and also the "Safe Handle" class:
private void buttonTestScreenCapture_Click(object sender, EventArgs e)
{
try
{
BitmapSource bms = CopyScreen();
BitmapFrame bmf = BitmapFrame.Create(bms);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(bmf);
string filepath = #"e:\(test)\test.png";
using (Stream stm = File.Create(filepath))
{
encoder.Save(stm);
}
}
catch (Exception ex)
{
MessageBox.Show($"Err={ex}");
}
}
public class SafeHBitmapHandle : SafeHandleZeroOrMinusOneIsInvalid
{
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern int DeleteObject(IntPtr hObject);
[SecurityCritical]
public SafeHBitmapHandle(IntPtr preexistingHandle, bool ownsHandle)
: base(ownsHandle)
{
SetHandle(preexistingHandle);
}
protected override bool ReleaseHandle()
{
return DeleteObject(handle) > 0;
}
}
And finally a look at my 'usings':
using System;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Media.Imaging;
using System.Windows.Interop;
using System.Windows;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Security;
The DLLs referenced included:
* PresentationCore
* System.Core
* System.Deployment
* System.Drawing
* WindowsBase
In my case it did not work directly with this method. I had to add a clean garbage collector in addition
using (PaintMap p = new PaintMap())
{
System.Drawing.Image i = p.AddLineToMap("1");
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(i, 8419, 5953);
IntPtr hBitmap = bmp.GetHbitmap();
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
Image2.ImageSource = bitmapSource;
DeleteObject(hBitmap);
System.GC.Collect();
}
I have a solution for someone who want to load image from memory or other class
public static InteropBitmap Bitmap2BitmapImage(Bitmap bitmap)
{
try
{
var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
return (InteropBitmap)source;
}
catch (Exception e)
{
MessageBox.Show("Convertion exception: " + e.Message + "\n" +e.StackTrace);
return null;
}
}
And then I use it the set the source of an image
CurrentImage.Source = ImageConverter.Bitmap2BitmapImage(cam.Bitmap);
Image is the following definition
<Image x:Name="CurrentImage" Margin="5" StretchDirection="Both"
Width="{Binding Width}"
Height="{Binding Height}">
</Image>

Categories

Resources