Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading a file to a Bitmap but leaving the original file intact

How to do this in C#?

If I use Bitmap.FromFile(), the original file is locked.

If I use Bitmap.FromStream(), the original file is not locked, but the documentation says "You must keep the stream open for the lifetime of the Image." This probably means that the file is still linked to the image object, (for example, perhaps if the file change so do the object or vice versa).

what i want to do is just reading the bitmap and save it to an object and after that there is no link whatsoever between the file and the Image object

like image 576
Louis Rhys Avatar asked Aug 02 '10 10:08

Louis Rhys


2 Answers

Some background info on this behavior: Bitmap uses a memory-mapped file to access the pixels in the bitmap. That's a very basic facility in the Windows API, it allows very efficient mapping of memory to file data. Data is read from the file only when the program read the memory, the virtual memory pages don't take any space in the Windows paging file.

The exact same mechanism is used to load .NET assemblies. It is the memory mapping that puts a lock on the file. Which is basically why assemblies are locked when they are used in a .NET program. The Image.Dispose() method releases the lock. Fighting the lock often indicates that you are forgetting to dispose your bitmaps. Very important, forgetting to call Dispose() doesn't often cause problems for .NET classes, except for Bitmap since it can need so much (unmanaged) memory.

Yes, FromStream() prevents the class from making this optimization. The cost is significant, you'll need double the memory when the bitmap is loaded. This will be a problem when the bitmap is large, you're skirting OOM when the program has been running for a while (fragmenting the address space) and its not running on a 64-bit operating system. Definitely avoid doing this if the bitmap's Width x Height x 4 >= 45 MB, give or take.

Some code, you don't have to jump through the CopyStream hoop:

    public static Image LoadImageNoLock(string path) {
        var ms = new MemoryStream(File.ReadAllBytes(path)); // Don't use using!!
        return Image.FromStream(ms);
    }

Note that you don't want to dispose the MemoryStream, you'll get a hard to diagnose "generic error" when the bitmap gets used if you do. Caused by the Image class lazy-reading the stream.

like image 110
Hans Passant Avatar answered Oct 11 '22 08:10

Hans Passant


Read the file into memory by copying it from a FileStream into a MemoryStream. (Search for CopyStream in Stack Overflow to find plenty of examples of how to do that safely. Basically loop while reading, writing each chunk to the memory stream, until there's no more data to read.) Then rewind the MemoryStream (set Position = 0) and then pass that to Bitmap.FromStream.

like image 21
Jon Skeet Avatar answered Oct 11 '22 09:10

Jon Skeet