How i can free my application memory in c#? - c#

in my c# application load form i make load like 30 picture and this make my memory full and if I add more pictures I'll get the message "that my memory is full"
how can I free my memory or increase the maximum used memory?
is there are any another way to get all my pictures to picture box without filling my memory?

1) how can I free my memory or increase the maximum used memory?
Are you receiving an OutOfMemoryException and your memory isn't filled up in your machine? This might be due to x86 compilation and you should change it to x64.
2) is there are any another way to get all my pictures to picture box without filling my memory?
Yes and no. If you are using Bitmap it will allocate the image in the memory. If you are recreating the image later with all the images together without compressing it, then you could be also losing some memory if you are not disposing the Bitmaps correctly. You could load them, compress them, and then dispose the original one, keeping the compressed/optimized one in memory.
Besides, remember to always dispose your Bitmap after using it. The GC usually takes care of them, but you should always dispose them:
using (Bitmap bitmap = new Bitmap("file.jpg")
{
// bitmap handling here
}
Of course, if you are displaying it in a picturebox you can't dispose it, but again, you are not being completely clear in your question.
Without your code I cannot provide you a better answer, and I'll gladly edit this one if you update your question.
Read:
Compress bitmap before sending over network
When do I need to use dispose() on graphics?
Update
Upon fixing your thread I've noticed you've given an image but the formatting was broken.
Read my answer and it should help you (specially the part of compression). You can also change to x64.
Update 2 - Compression code example
public void ExampleMethod()
{
pictureBox1.Image = GetCompressedFile("file.jpg", quality: 10);
}
private Image GetCompressedFile(string fileName, long quality)
{
using (Bitmap bitmap = new Bitmap(fileName))
{
return GetCompressedBitmap(bitmap, quality);
}
}
private Image GetCompressedBitmap(Bitmap bmp, long quality)
{
using (var mss = new MemoryStream())
{
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
ImageCodecInfo imageCodec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(o => o.FormatID == ImageFormat.Jpeg.Guid);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = qualityParam;
bmp.Save(mss, imageCodec, parameters);
return Image.FromStream(mss);
}
}
In the quality parameter you set the quality. 100 means 100%, 50 means 50%.
Try setting quality as 10 and see if it works.
Remove all Bitmap bmp = new Bitmap from the code, and display with your PictureBoxInstance.Image = GetCompressedFile(...);
Check the ExampleMethod().
Code based from: https://stackoverflow.com/a/48274706/4352946
You have to remember though, that even using Dispose, the memory won’t be freed right away, you should wait the GC for that.
P.S: compressing the file on-the-go you MIGHT end up with both images (the compressed and uncompressed) in the memory

Related

Trying to change image DPI without changing file size

I have the following code for changing the DPI of an image:
public void changeDPI(string imagePathSource,string imagePathDestination,float DPIx,float DPIy)
{
Bitmap bitmap = new Bitmap(imagePathSource);
Bitmap newBitmap = new Bitmap(bitmap);
newBitmap.SetResolution(DPIx,DPIy);
newBitmap.Save(imagePathDestination);
}
However, this ends up changing the memory size of the file. An example test image started at 267 KB, and the newBitmap version of the file ended up as 1.51 MB. How can I change the DPI without changing the file size?
Why are you making a new bitmap out of it? That converts the image to 32bpp ARGB, and loses the connection to the original loaded data.
The original loaded image's file format is available in the RawFormat property. So just set the original bitmap's resolution to your new one, and save it to the new path using bitmap.RawFormat:
public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
using (Bitmap bitmap = new Bitmap(imagePathSource))
{
bitmap.SetResolution(dpiX, dpiY);
bitmap.Save(imagePathDestination, bitmap.RawFormat);
}
}
I believe that this way, it won't even recompress the actual image content, meaning you have no further quality degrading due to reapplying the jpeg compression.
Also, do make sure you always either call Dispose() on image objects, or use them in a using block. They are objects backed by unmanaged sources (GDI+ objects), so you have to be careful or they'll pollute your program's memory, and keep locks on the files you opened.
On the note of locked files, if you give the same path for both imagePathSource and imagePathDestination you'll get an error about exactly that. To get around this, read the bytes from the image in advance, and use a MemoryStream to load the image:
public void changeDPI(String imagePathSource, String imagePathDestination, Single dpiX, Single dpiY)
{
Byte[] fileData = File.ReadAllbytes(imagePathSource);
using (MemoryStream ms = new MemoryStream(fileData))
using (Bitmap loadedImage = new Bitmap(ms))
{
bitmap.SetResolution(dpiX, dpiY);
bitmap.Save(imagePathDestination, bitmap.RawFormat);
}
}
I think you must indicate the format of the output file, to save as a compressed image format like JPEG.
newBitmap.Save(imagePathDestination, System.Drawing.Imaging.ImageFormat.Jpeg);

JPEG decompression from MemoryStream c#

In my program, I compress a BMP into a JPEG like this:
private void ConvertBmpToStreamJPG30(Bitmap b, Stream s)
{
s.Flush();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 30L);
b.Save(s, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
Then a function is receiving the JPEG in a MemoryStream, I transform it into a Bitmap by doing
Bitmap b = new Bitmap(stream);
When I display the image, there are a lot of lines like this :
What am I doing wrong, people?
Edit 1
Here a small visual studio solution showing the problem: http://www.fast-files.com/getfile.aspx?file=79311
It is the beginning of a screen sharing software. What it does: It takes screenshots, compare them, compress the difference and send it to another part of the program that decompress it and recompose an image with everything received. It opens a window displaying what is "sent" on the left and the recomposed image on the right.
Three things come to mind:
Try setting a better quality than 30 and see if that helps;
Check your RAM (and possibly video RAM, though I doubt that GDI+ might use VGA for compression) for hardware problems;
I've had a similar weird problem where I loaded some JPEG file, modified it a bit, and then saved it again. That produced an exception. The solution was to make a new bitmap based on the old one and save the copy. Try that.

c# save a picture file to ram

I am developing a program for image processing, and I need to save some pictures from a video and do some processing on them.
When dealing with 1 picture it doesn't really take time,
But when I'm dealing with 100 pictures it makes difference
I'm saving the files to my hard disk, and that's why it takes time
the thing is, the function I'm using is a ready made function and it only accepts (file name)
the function is really complicated so i cannot build my own function ( if that's what you are thinking )
I'm thinking of 2 things right now and would like to have your opinions about them:
change the input of the function, but how ? is there a way to change this input from a ( file name ) to an array which holds these pictures ?
save the file to ram. but how to save files to ram by names, and be able to use them as ( file name ) in the function ?
I appreciate your help , thanks so much
this is my code but i still have problems:
Capture video = new Capture("c:\\5.avi");
Image<Bgr, Byte> Imageframe ;
Dictionary<string, MemoryStream> dict = new Dictionary<string, MemoryStream>();
Imageframe = video.QueryFrame();
Bitmap bmp = Imageframe.ToBitmap();
dict.Add("mypicture.png", new MemoryStream());
bmp.Save(dict["mypicture.png"],imageformat.png);
its saying imageformat does not exist in the context
and this is the function im using :
Image<Bgr, byte> result;
result = DrawMatches.Draw("box.png", "box_in_scene.png", out matchTime,i);
You could save to RAM (in the loosest of senses) using a MemoryStream. If you wanted to name them you could use a Dictionary<string,MemoryStream>, such as:
Dictionary<string,MemoryStream> dict = new Dictionary<string,MemoryStream>();
dict.Add("mypicture.png",new MemoryStream());
image.Save(dict["mypicture.png"]);
However you'll need to write cleanup code for these streams and this doesn't take into account that eventually you could use up all the physical RAM and then start going into the paging file, which is disk based anyhow.
As an aside, if this is on a server you control and you're not releasing this software to end users you could get a RAM disk drive (plenty around just Google) that uses physical RAM as an actual disk available to Windows. Then you could just load/save to that.
Very very rough EmguCv variant:
// Global dictionary of memory streams
Dictionary<string,MemoryStream> dict = new Dictionary<string,MemoryStream>();
// Add image memory stream to dictionary
dict.Add("mypicture.png",new MemoryStream());
// Get bitmap from EmguCv
Bitmap bmp = image.ToBitmap();
// Save bitmap to image memory stream
bmp.Save(dict["mypicture.png"],ImageFormat.Png);
// Get bitmap from memory stream
dict["mypicture.png"].Seek(0,SeekOrigin.Begin);
Bitmap new_bmp = Image.FromStream(dict["mypicture.png"]);
// Convert bitmap to EmguCv image
Image<Bgr,Byte> new_img = new Image<Bgr,Byte>(new_bmp);
Try to use MemoryStream for work with memmory like with file,
and try to save files on harddisk by thread
I understand you are using a DLL you dont have the source for.
You might be able to load it into a reflector, and modify it to take the image as an argument instead of the file name.
I used Red Gate's reflector in the past and it worked for me: http://www.reflector.net/

OutOfMemory Exception when loading lots of Images from Isolated storage

EDIT: I keep getting OutOfMemoryException was unhandled,
I think it's how I am saving the image to isolated storage ,I think this is where I can solve my problem how do I reduce the size of the image before I save it? (added code where I save Image)
I am opening images from Isolated storage sometimes over 100 images and I want to loop over them images but I get a OutOfMemory Exception when there is around 100 to 150 images loaded in to a storyboard. How can I handle this exception, I have already brought down the resolution of the images. How can I handle this exception and stop my app from crashing?
I get the exception at this line here
image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage
here's my code
private void OnLoaded(object sender, RoutedEventArgs e)
{
IsolatedStorageFile isStoreTwo = IsolatedStorageFile.GetUserStoreForApplication();
try
{
storyboard = new Storyboard
{
//RepeatBehavior = RepeatBehavior.Forever
};
var animation = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTarget(animation, projectImage);
Storyboard.SetTargetProperty(animation, new PropertyPath("Source"));
storyboard.Children.Add(animation);
for (int i = 1; i <= savedCounter; i++)
{
BitmapImage image = new BitmapImage();
image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage
var keyframe = new DiscreteObjectKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(100 * i)),
Value = image
};
animation.KeyFrames.Add(keyframe);
}
}
catch (OutOfMemoryException exc)
{
//throw;
}
Resources.Add("ProjectStoryBoard", storyboard);
storyboard.Begin();
}
EDIT This is how I am saving the image to Isolated storage, I think this is where I can solve my problem, How do I reduce the size of the image when saving it to isolated storage?
void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
{
string fileName = folderName+"\\MyImage" + savedCounter + ".jpg";
try
{
// Save picture to the library camera roll.
//library.SavePictureToCameraRoll(fileName, e.ImageStream);
// Set the position of the stream back to start
e.ImageStream.Seek(0, SeekOrigin.Begin);
// Save picture as JPEG to isolated storage.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to isolated storage.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
}
finally
{
// Close image stream
e.ImageStream.Close();
}
}
I would appreciate if you could help me thanks.
It doesn't matter how large your images are on disk because when you load them into memory they're going to be uncompressed. The memory required for the image will be approximately (stride * height). stride is width * bitsPerPixel)/8, and then rounded up to the next multiple of 4 bytes. So an image that's 1024x768 and 24 bits per pixel will take up about 2.25 MB.
You should figure out how large your images are, uncompressed, and use that number to determine the memory requirements.
You are getting the OutOfMemory Exception because you are storing all the images in memory at the same time in order to create your StoryBoard. I don't think you will be able to overcome the uncompressed bitmap size that the images require to be displayed on screen.
So to get past this we must think about your goal rather than trying to fix the error. If your goal is to show a new image in sequence every X ms then you have a few options.
Keep using StoryBoards but chain them using the OnCompleted event. This way you don't have to create them all at once but can just generate the next few. It might not be fast enough though if you're changing images every 100ms.
Use CompositionTarget.Rendering as mentioned in my answer here. This would probably take the least amount of memory if you just preload the next one (as opposed to having them all preloaded as your current solution does). You'd need to manually check the elapsed time though.
Rethink what you're doing. If you state what you are going after people might have more alternatives.
To answer the edit at the top of your post, try ImageResizer. There's a NuGet package, and a HanselBlog episode on it. Obviously , this is Asp.Net based, but I'm sure you could butcher it to work in your scenario.
Tackling these kind of problems at design layer usually works better.
Making application smart about the running environment via some configurations makes your application more robust. For example you can define some variables like image size, image count, image quality... based on available memory and set these variables at run-time in your App. So your application always works; fast on high memory machines and slow on low memory ones; but never crash. (Don't believe working in managed environment means no worry about the environment... Design always matters)
Also there are some known design patterns like Lazy Loading you can benefit from.
I don't know about windows phone in particular, but in .net winforms, you need to use a separate thread when doing a long-running task. Are you using a BackgroundWorker or equivalent? The finalizer thread can become blocked, which will prevent the resources for the images from being disposed. Using a separate thread from the UI thread will allow will allow the Dispose method to be run automatically.
Ok, an image (1024x768) has at least a memsize of 3 mb (argb)
Don't know how ObjectAnimationUsingKeyFrames works internal. Maybe you can force the gc by destroying the instances of BitmapImage (and KeyFrames) without loss of its data in the animation.
(not possible, see comments!)
Based on one of your comments, you are building a Time Lapse app. Commercial time-lapse apps for WP7 compress the images to video, not stills. e.g. Time Lapse Pro
The whole point of video playback is to reduce similar, or time-related, images to highly compressed stream that do not require massive amounts of memory to play back.
If you can add the ability to encode to video, in your app, you will avoid the problem of trying to emulate a video player (using 100s of single full-resolution frames as a flick-book).
Processing the images into video server-side may be another option (but not as friendly as in-camera).

Loading an image from a stream without keeping the stream open

Is it possible to use the FromStream method of System.Drawing.Image without having to keep the stream open for the lifetime of the image?
I have an application which loads a bunch of toolbar graphics from resource files, using a combination of Image.FromStream and Assembly.GetManifestResourceStream.
The problem I'm having is while this works fine on Windows 7, on Windows XP the application crashes if a user interface element linked to one of these images is disabled. On Windows 7, the image is rendered in grayscale. On XP, it crashes with an out of memory exception.
After a load of hairpulling I have finally traced it to the initial loading of the image. As a matter of course, if I create any object implementing IDisposable that is also destroyed in the same method, I wrap it in a using statement, for example
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
image = Image.FromStream(resourceStream);
}
If I remove the using statement so that the stream isn't disposed, then the application no longer crashes on XP. But I now have a bunch of "orphan" streams hanging about - the images are stored in command classes and these correctly dispose of the images when they themselves are disposed, but the original stream isn't.
I checked the documentation for FromStream and it confirms the stream needs to remain open. Why this hasn't crashed and burned on the Windows 7 development system is a mystery however!
I really don't want this stream hanging around, and I certainly don't want to have to store a reference to this stream as well as the image so I can dispose of it later. I only have need of that stream once so I want to get rid of it :)
Is it possible to create the image and then kill of the stream there and then?
The reason the stream needs to be open is the following:
GDI+, and therefore the System.Drawing namespace, may defer the decoding of raw image bits until the bits are required by the image. Additionally, even after the image has been decoded, GDI+ may determine that it is more efficient to discard the memory for a large Bitmap and to re-decode later. Therefore, GDI+ must have access to the source bits for the image for the life of the Bitmap or the Image object.
The documented workaround is to create either a non-indexed image using Graphics.DrawImage or to create an indexed Bitmap from the original image as described here:
Bitmap and Image constructor dependencies
According to the documentation of Image.FromStream, the stream must be kept open while the image is in use. Therefore, even if closing worked (and there's nothing to say you can't close a stream before it's disposed, as far as the stream object itself goes) it may not be a very reliable approach.
You could copy the image to another image object, and use that. However, this is likely to be more memory intensive than just keeping the stream open.
You could save the stream to a temporary file and use the Image.FromFile method. Or simply don't embed the image, keep it as a file and load it from this file at runtime.
I'am sure this will help someone :)
I used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

Categories