469,927 Members | 1,708 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,927 developers. It's quick & easy.

Image from file (release handle)

I have a method that I use to get a System.Drawing.Image from a file without
keeping a handle on the file open (so I can delete the file). Here is the
code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws the
dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve
Jan 10 '08 #1
14 15797
According to reflector Image.FromStream() and Image.FromFile() are both
calling the same internal GDI methods. Well, not the same but they ARE GDI
methods (I think) It's hard to explain. What I'm saying is that they both
look like they work the same way.

Sheesh!

So then I had this bright idea!
<code>
Image i = Bitmap.FromFile(filename);
Guard.ReferenceNotNull(i, "Failed loading Image from file: " + filename);

Image j = i.Clone() as Image;
i.Dispose();
return j;
</code>

It doesn't allow me to delete the file either "File locked by another
process...."
if I dispose j as well, then I can delete the file. So it appears that
close still keep some reference to the source object? That doesn't sound
right.

And finally:
<code>
Image i = Bitmap.FromFile(filename);
Guard.ReferenceNotNull(i, "Failed loading Image from file: " + filename);

// try painting one into the other
Image freeCopy = new Bitmap(i);
i.Dispose();
return freeCopy;
</code>

This drops all the frames from the tiff. I can delete the source file, but
th resultant Image is junk.

The only last option I have is to load the tiff, grab all the frames into an
Image[], dispose of the source tiff Image, delete the source file and just
work with the Image[] array. This will work for my needs, but I imagine for
other it won't.

If anyone has any ideas or suggestion I would really like to hear them.

-Steve
"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
>I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file). Here
is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve

Jan 10 '08 #2
On Thu, 10 Jan 2008 00:22:05 -0800, Steve K. <no***@nowhere.comwrote:
[...]
If anyone has any ideas or suggestion I would really like to hear them.
Is it safe to assume that you hadn't seen my reply when you wrote that
post?

The behaviors you've seen with the things you've tried all seem
unsurprising to me. It wouldn't make sense for the object class to read
in the entire TIFF implicitly, even when you clone it. It's just too
inefficient to make that the general behavior.

Hopefully something in my previous post helps.

Pete
Jan 10 '08 #3
This is what I'm using to read images w/o locking the file.

public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
FileAccess.Read))
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
GC.Collect();
return theImage;
}
Hope it works for you.

RobinS.
GoldMail, Inc.
------------------------
"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
>I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file). Here
is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve
Jan 10 '08 #4
On Thu, 10 Jan 2008 00:42:23 -0800, Steve K. <no***@nowhere.comwrote:
In a frantic solution-finding flurry I came up with a hack of sorts, I'm
still not sure what I think of it. Check it out:
That's essentially the same as copying the file into a MemoryStream,
except that it's even worse because it will decompress the file data into
memory. At least if you copy the file into a MemoryStream, whatever
compression is used in the TIFF (if any) still benefits you.

I'm glad you got a solution that works, just to prove it can be done. But
I don't think that's going to be the way you want to go, ultimately. :)

Pete
Jan 10 '08 #5
"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Thu, 10 Jan 2008 00:22:05 -0800, Steve K. <no***@nowhere.comwrote:
>[...]
If anyone has any ideas or suggestion I would really like to hear them.

Is it safe to assume that you hadn't seen my reply when you wrote that
post?
Hi Peter, yes, I sent this before seeing your reply.
Your post made a lot of sense, thank you again.
>
The behaviors you've seen with the things you've tried all seem
unsurprising to me. It wouldn't make sense for the object class to read
in the entire TIFF implicitly, even when you clone it. It's just too
inefficient to make that the general behavior.

Hopefully something in my previous post helps.

Pete

Jan 10 '08 #6
Hi Robin,

Thanks for the reply, that is what I've been doing as well for most other
image types. It's the TIFF that is the problem, as Peter pointed out the a
TIFF loaded into an Image still needs access to it's source stream.

Thanks,
Steve

"RobinS" <ro****@imnottelling.comwrote in message
news:AP******************************@comcast.com. ..
This is what I'm using to read images w/o locking the file.

public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
FileAccess.Read))
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
GC.Collect();
return theImage;
}
Hope it works for you.

RobinS.
GoldMail, Inc.
------------------------
"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
>>I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file).
Here is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve

Jan 10 '08 #7
I've dealt with similar problems when working with Tiffs in particular, and
with GeoTiffs specifically, since that is what sort I work with primarily. I
ended up writing my own Tiff class, which initially only parses the Tiff
tags using a StreamReader, and creates a Collection of "ImageFileDirectory"
instances, one for each image. The Image property of the ImageFileDirectory
class reopens a StreamReader and gets the image out of the file. This is
also useful with Tiffs that are tiles rather than stripped, as I haven't
found a .Net class that can parse tiled Tiff format images, but my class can
work with either. Also, because these images are so large, not loading the
entire file saves a good bit of memory.

I was then able to create several derivatives of the class, a GeoTiff class
that recognizes the GeoTiff tags and can parse the Geographic information in
them, and a couple of derivatives of that for parsing several varieties of
GeoTiffs.

The Adobe Tiff file format is an open specification.

--
HTH,

Kevin Spencer
Chicken Salad Surgeon
Microsoft MVP

"Steve K." <no***@nowhere.comwrote in message
news:%2***************@TK2MSFTNGP04.phx.gbl...
Hi Robin,

Thanks for the reply, that is what I've been doing as well for most other
image types. It's the TIFF that is the problem, as Peter pointed out the
a TIFF loaded into an Image still needs access to it's source stream.

Thanks,
Steve

"RobinS" <ro****@imnottelling.comwrote in message
news:AP******************************@comcast.com. ..
>This is what I'm using to read images w/o locking the file.

public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
FileAccess.Read))
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
GC.Collect();
return theImage;
}
Hope it works for you.

RobinS.
GoldMail, Inc.
------------------------
"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
>>>I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file).
Here is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve


Jan 10 '08 #8


"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file).
Here is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve
You stated in another post that your image data is coming directly from a
database blob field. Why don't you just take this data and write it to a
MemoryStream and then do a FromStream method call to create the image? This
way, you don't have to create/delete a file on the file system.

HTH,
Mythran
Jan 10 '08 #9
On Thu, 10 Jan 2008 01:45:51 -0800, Steve K. <no***@nowhere.comwrote:
Thanks for the reply, that is what I've been doing as well for most other
image types. It's the TIFF that is the problem, as Peter pointed out
the a
TIFF loaded into an Image still needs access to it's source stream.
Actually, the code Robin posted is exactly my second suggestion: it reads
the file entirely into a MemoryStream and uses that instead of the
original file as the source for the image.

It should work fine as long as the files aren't too big.

Pete
Jan 10 '08 #10

"RobinS" <ro****@imnottelling.comwrote in message
news:AP******************************@comcast.com. ..
This is what I'm using to read images w/o locking the file.

public static Image LoadImageFromFile(string fileName)
{
Image theImage = null;
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
FileAccess.Read))
{
byte[] img;
img = new byte[fileStream.Length];
fileStream.Read(img, 0, img.Length);
fileStream.Close();
theImage = Image.FromStream(new MemoryStream(img));
img = null;
}
GC.Collect();
return theImage;
}
Hope it works for you.

RobinS.
GoldMail, Inc.

Hi Robin,

I have a newbie question: Is the MemoryStream safe from GC as long as the
Image is holding onto it? Once the image is disposed (either by me
explicitly or by the GC) the stream will be closed?

Thanks again for posting the code,
Steve
Jan 11 '08 #11

"Mythran" <ki********@hotmail.comwrote in message
news:26**********************************@microsof t.com...
>

"Steve K." <no***@nowhere.comwrote in message
news:u4**************@TK2MSFTNGP03.phx.gbl...
>I have a method that I use to get a System.Drawing.Image from a file
without keeping a handle on the file open (so I can delete the file).
Here is the code:

<code>
public static Image ImageFromFileReleaseHandle(string filename)
{
FileStream fs = null;
try
{
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
return Image.FromStream(fs);
}
finally
{
fs.Close();
}
}
</code>

It's worked great for years... until I tried loading a multi-frame(page)
tiff. When loading a tif using the above method I'm unable to call
SetActiveFrame() to any frame index other than 0. When I do, it throws
the dreaded "Generic GDI+ Error..."

If I use System.Drawing.FromFile() I can work with the TIF no problem -
problem is I can't delete the source file.

So what I'm wondering is how is Image.FromFile() different than what I'm
doing? Does anyone know what, if anything that method is doing that is
special?

Any help greatly appreciated.

-Steve

You stated in another post that your image data is coming directly from a
database blob field. Why don't you just take this data and write it to a
MemoryStream and then do a FromStream method call to create the image?
This way, you don't have to create/delete a file on the file system.

HTH,
Mythran
Good point! :0)

As the MemoryStream seems to be the consensus and my own research is
indicating that is is indeed the best solution (for me) I will be going that
route.

Thanks everyone for the great ideas and support, this was a good thread,
lots of help.

Take care,
Steve
Jan 11 '08 #12
On Thu, 10 Jan 2008 21:56:30 -0800, Steve K. <no***@nowhere.comwrote:
I have a newbie question: Is the MemoryStream safe from GC as long as
the
Image is holding onto it? Once the image is disposed (either by me
explicitly or by the GC) the stream will be closed?
I would expect a call to Dispose() to release the MemoryStream, but in the
worst case you would have to release the reference to the Image itself.

In either case, you should not have to worry about maintaining a reference
to the MemoryStream yourself.

Pete
Jan 11 '08 #13
On Fri, 11 Jan 2008 00:17:48 -0800, Peter Duniho
<Np*********@nnowslpianmk.comwrote:
On Thu, 10 Jan 2008 21:56:30 -0800, Steve K. <no***@nowhere.comwrote:
>I have a newbie question: Is the MemoryStream safe from GC as long as
the
Image is holding onto it? Once the image is disposed (either by me
explicitly or by the GC) the stream will be closed?

I would expect a call to Dispose() to release the MemoryStream, but in
the worst case you would have to release the reference to the Image
itself.
To elaborate: if you'll recall, calling Dispose() on the Image releases
the file for deletion. So it stands to reason doing so would also release
a MemoryStream.

By the way, when something like this comes up and you want to investigate
so that you know for sure what the behavior is, you can take advantage of
the WeakReference class. For example, in this case you'd initialize an
instance of WeakReference with the MemoryStream, create the Image from the
MemoryStream, call Dispose() on the Image, and then force a garbage
collection using the GC class.

If the WeakReference target survives (check WeakReference.IsAlive), then
calling Dispose() isn't releasing the reference.

Obviously this is something you'd do in a test program. No point in
putting code like that in your actual useful program. :)

Pete
Jan 11 '08 #14

"Peter Duniho" <Np*********@nnowslpianmk.comwrote in message
news:op***************@petes-computer.local...
On Fri, 11 Jan 2008 00:17:48 -0800, Peter Duniho
<Np*********@nnowslpianmk.comwrote:
>On Thu, 10 Jan 2008 21:56:30 -0800, Steve K. <no***@nowhere.comwrote:
>>I have a newbie question: Is the MemoryStream safe from GC as long as
the
Image is holding onto it? Once the image is disposed (either by me
explicitly or by the GC) the stream will be closed?

I would expect a call to Dispose() to release the MemoryStream, but in
the worst case you would have to release the reference to the Image
itself.

To elaborate: if you'll recall, calling Dispose() on the Image releases
the file for deletion. So it stands to reason doing so would also release
a MemoryStream.

By the way, when something like this comes up and you want to investigate
so that you know for sure what the behavior is, you can take advantage of
the WeakReference class. For example, in this case you'd initialize an
instance of WeakReference with the MemoryStream, create the Image from the
MemoryStream, call Dispose() on the Image, and then force a garbage
collection using the GC class.

If the WeakReference target survives (check WeakReference.IsAlive), then
calling Dispose() isn't releasing the reference.

Obviously this is something you'd do in a test program. No point in
putting code like that in your actual useful program. :)

Pete
Right on, thanks Pete, that's some good debugging help and God knows I do a
lot of debugging!
Jan 11 '08 #15

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

reply views Thread by Jean-Sebastien Carle | last post: by
35 posts views Thread by Stan Sainte-Rose | last post: by
6 posts views Thread by Thomas Guettler | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.