none
Image.FromFile vs. Image.FromStream

    Question

  • Hi,

    I came across a strange problem while reading GIF animated images using the Image.FromStream method

    Here is the code that I wrote....

     
                
    Code Snippet

    try

    {

    using (StreamReader strm = new StreamReader(@"C:\myAnim.gif"))
    {
    //Image img = Image.FromFile(@"C:\myAnim.gif");

              Image img = Image.FromStream(strm.BaseStream);
              picImages.Image = img;

    }

    }
    catch (Exception ex)
    {

    MessageBox.Show(ex.ToString());

    }



    Now the funny part is the exception doesn't occur when the image is read or the PictureBox.Image property is set. i.e. no message box from the catch block.

    However a runtime exception does occur. Here is the stack trace:
    --------------------------------------------------------------------
    System.Runtime.InteropServices.ExternalException was unhandled
      Message="A generic error occurred in GDI+."
      Source="System.Drawing"
      ErrorCode=-2147467259
      StackTrace:
           at System.Drawing.Image.SelectActiveFrame(FrameDimension dimension, Int32 frameIndex)
           at System.Drawing.ImageAnimator.ImageInfo.UpdateFrame()
           at System.Drawing.ImageAnimator.UpdateFrames()
           at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
           at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
           at System.Windows.Forms.Control.WmPaint(Message& m)
           at System.Windows.Forms.Control.WndProc(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
           at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
           at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
           at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
           at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
           at System.Windows.Forms.Application.Run(Form mainForm)
           at FolderImageBrowser.Program.Main() in E:\Projects\FolderImageBrowser\FolderImageBrowser\Program.cs:line 18
           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException:

    --------------------------------------------------------------------

    I could use the Image.FromFile method but then the image cannot be deleted.

    Am I doing something wronng or am I supposed to do something more than just reading from a stream (specific to GIF animations).

    Any information will be helpful

    Thanks


    Thursday, May 01, 2008 12:10 PM

Answers

  • Wriju Bharadwaj,

     

    Based on your post, I can reproduce your problem on my test machine. I am using Windows Server 2003 and Visual Studio 2008. This is an ExternalException, "A generic error occurred in GDI+" at Application.Run(new Form1()). I can still get the exception when the PictureBox.Image property set as import the gif file. However, when I replace the gif animated image to jpg, the project runs fine. I would like to provide you the comments as follows:

     

    1. Important remark in Image.FromStream method document: You must keep the stream open for the lifetime of the Image. The stream is reset to zero if this method is called successively with the same stream.

     

    There is thread Display animated GIF in PictureBox with the fix by ssta to add the Image.Dispose method.

     

    2. When either a Bitmap object or an Image object is constructed from a file, the file remains locked for the lifetime of the object. As a result, you cannot change an image and save it back to the same file where it originated.


    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.

    To retain access to the source bits, GDI+ locks any source file, and forces the application to maintain the life of any source stream, for the life of the Bitmap or the Image object. You can get the further related workaround in KB 814675

     

    Hope that can help you.

    Wednesday, May 07, 2008 6:10 AM
  • You cannot use a StreamReader, it was designed to read text, not binary data.  Use a FileStream instead.
    Wednesday, May 07, 2008 10:17 AM

All replies

  • Wriju Bharadwaj,

     

    Based on your post, I can reproduce your problem on my test machine. I am using Windows Server 2003 and Visual Studio 2008. This is an ExternalException, "A generic error occurred in GDI+" at Application.Run(new Form1()). I can still get the exception when the PictureBox.Image property set as import the gif file. However, when I replace the gif animated image to jpg, the project runs fine. I would like to provide you the comments as follows:

     

    1. Important remark in Image.FromStream method document: You must keep the stream open for the lifetime of the Image. The stream is reset to zero if this method is called successively with the same stream.

     

    There is thread Display animated GIF in PictureBox with the fix by ssta to add the Image.Dispose method.

     

    2. When either a Bitmap object or an Image object is constructed from a file, the file remains locked for the lifetime of the object. As a result, you cannot change an image and save it back to the same file where it originated.


    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.

    To retain access to the source bits, GDI+ locks any source file, and forces the application to maintain the life of any source stream, for the life of the Bitmap or the Image object. You can get the further related workaround in KB 814675

     

    Hope that can help you.

    Wednesday, May 07, 2008 6:10 AM
  • You cannot use a StreamReader, it was designed to read text, not binary data.  Use a FileStream instead.
    Wednesday, May 07, 2008 10:17 AM
  • I talk about this same issue here: http://seanmcilvenna.com/blog/10-review/16-image-formatting-in-c-gdi

    Well, perhaps not the same, but very similar... FromStream doesn't work in several cases for me and so far I haven't found a solution.
    Tuesday, May 19, 2009 8:45 PM
  • > You must keep the stream open for the lifetime of the Image

    Wow, this caveat is not obvious.  Thanks.  Your statement seems to suggest that one must also use a stream capable of seeking, although the documentation doesn't say that.
    Tuesday, May 19, 2009 10:41 PM