3

Due to the fact that the windows phone can't handle gif, I write a little method, but it seems that it has a little error.
The code below always throws a exception when it runs to (JPG and PNG part)bitimg.SetSource(e.Result);
As it said, does it mean that I can't use the e.Result because it is disposed? But how could this happen, the method hasn't stop, why will the compiler dispose it?

Why and how to solve it?

Error Info:

{System.ObjectDisposedException: Cannot access a disposed object. Object name: 'MS.Internal.InternalMemoryStream'. at MS.Internal.InternalMemoryStream.Seek(Int64 offset, SeekOrigin origin) at ImageTools.IO.Gif.GifDecoder.Decode(ExtendedImage image, Stream stream) at xicihutong.ViewModel.RichTextBoxBindingBehavior.<>c__DisplayClass7.b__4(Object s, OpenReadCompletedEventArgs e) at System.Net.WebClient.OnOpenReadCompleted(OpenReadCompletedEventArgs e) at System.Net.WebClient.OpenReadOperationCompleted(Object arg)}

image.Loaded += (s1, e1) =>
{
    WebClient wc = new WebClient();
    wc.AllowReadStreamBuffering = true;
    wc.OpenReadCompleted += (s, e) =>
    {
        if (e.Error == null && !e.Cancelled)
        {
            //Check the type of the Image
            ImageTypeCheck.ImageType incomingIMGType = ImageTypeCheck.getImageType(e.Result);

            BitmapImage bitimg = new BitmapImage();
            bitimg.CreateOptions = BitmapCreateOptions.BackgroundCreation;

            switch (incomingIMGType)
            {
                //handle GIF for windows phone
                case ImageTypeCheck.ImageType.Gif:
                    Decoders.AddDecoder<GifDecoder>();
                    Encoders.AddEncoder<JpegEncoder>();
                    GifDecoder gif = new GifDecoder();
                    JpegEncoder jpg = new JpegEncoder();
                    ImageTools.ExtendedImage extImg = new ImageTools.ExtendedImage();
                    gif.Decode(extImg, e.Result);
                    using (MemoryStream stream = new MemoryStream())
                    {
                        jpg.Encode(extImg, stream);
                        bitimg.SetSource(stream);
                        image.Source = bitimg;
                    }
                    break;
                case ImageTypeCheck.ImageType.Bmp:
                case ImageTypeCheck.ImageType.Null:
                    break;
                case ImageTypeCheck.ImageType.Jpg:
                case ImageTypeCheck.ImageType.Png:
                    try
                    {
                        bitimg.SetSource(e.Result);
                        image.Source = bitimg;
                    }
                    catch (Exception ex)
                    {
                        App.print(ex.Message);
                    }
                    break;
            }
        }
    };
    wc.OpenReadAsync(new Uri(item, UriKind.Absolute), wc);

}

==================================

using System.IO;

namespace xicihutong.DataServiceAgent
{
    class ImageTypeCheck
    {
        /// <summary>
        /// define
        /// </summary>
        public enum ImageType
        {
            Null,Png,Jpg,Gif,Bmp
        }


        public static ImageType getImageType(Stream stream)
        {
            ImageType type = ImageType.Null;

            byte[] header = new byte[8];
            stream.Read(header, 0, 8);

            //Check if PNG then do something;
            //Check if JPG then do something;
            //Check if GIF then do something;

            stream.Close();

            return type;
        }
    }
}
Albert Gao
  • 3,653
  • 6
  • 40
  • 69
  • Where do GifDecoder and JpegEncoder come from? – Justin Niessner May 30 '13 at 18:58
  • I know this has nothing to do with answer. But why don't you make your code more readable? This will definitely helps folks to contribute than they skip. – S.N May 30 '13 at 18:59
  • @JustinNiessner they'are helper method from ImageTools – Albert Gao May 30 '13 at 19:01
  • @AlbertGao Could you show the code of the `ImageTypeCheck.getImageType` method? It seems very likely that this method is closing the stream. – Kevin Gosse May 30 '13 at 19:04
  • @nair sorry, have edited! – Albert Gao May 30 '13 at 19:04
  • @KooKiz You are absolutely right.... – Albert Gao May 30 '13 at 19:11
  • I presume, your GifDecoder seems to be the culprit. Can you check the gif.Decode(extImg, e.Result) method implementation? It seems, Decode method return ObjectDisposedException. Ref: http://typedescriptor.net/browse/members/1197621-MS.Internal.InternalMemoryStream.Seek(Int64,SeekOrigin) (Not sure about how authentic it is but definitely food for thought) – S.N May 30 '13 at 19:11

1 Answers1

4

As you pointed yourself, the ImageTypeCheck.getImageType method is closing the stream.

How were you supposed to find the issue?

  1. The error message clearly indicates that the stream has been disposed. All that left was finding the culprit.
  2. The callstack shows that the ImageTools.IO.Gif.GifDecoder.Decode was being called when the error was thrown. So it happened before that.
  3. Luckily, there's only one method using the stream before the GifDecoder, and that is ImageTypeCheck.getImageType

To fix the issue, just remove the stream.Close from the ImageTypeCheck.getImageType method, and replace it with a Seek to go back to the beginning of the stream (the GifDecoder expects the stream to be positioned at the start of the picture).

stream.Seek(0, SeekOrigin.Begin);
Kevin Gosse
  • 38,392
  • 3
  • 78
  • 94
  • You are my hero, I just comment that line and a new bug happens, use your suggestion to fix it. I couldn't thank you more, the boss won't blame me tomorrow :P – Albert Gao May 30 '13 at 19:25
  • a little more digging, so Does it mean every time I use a stream, the Position of the stream will be changed and saved unless I close the stream or use Seek method to set it. and if you don't close or seek, next one who read the stream will be start at that previous position? – Albert Gao May 30 '13 at 19:41