Silverlight: converting a byte[] to a BitmapImage ends in "catastrophic failure"

2.5k views Asked by At

I am trying to modify a BitmapImage in Silverlight, but happen to run into a "catastrophic failure"!

First I load an image and add it to the LayoutRoot.

BitmapImage source = new BitmapImage(new Uri("image.jpg", UriKind.Relative));
Image imageElement = new Image();
imageElement.Name = "imageElement";
imageElement.Source = source;
imageElement.Stretch = Stretch.None;
LayoutRoot.Children.Add(imageElement);

This works fine and the image is shown on the screen correctly.

Next I want to modify the image (for example: after a button click).

In the button click method, first, I get the image out of the LayoutRoot and then modify it by using a WriteableBitmap class:

Image imageElement = (Image) LayoutRoot.Children[1];
WriteableBitmap writeableBitmap = new WriteableBitmap(imageElement, null);
writeableBitmap.ForEach((x,y,color) => Color.FromArgb((byte)(color.A / 2), color.R, color.G, color.B));

Next i save it into a byte array buffer using the given method:

byte[] buffer = writeableBitmap.ToByteArray();  

This also looks good. The buffer shows all ARGB values and even the alpha values are half the usual value with 127, just as it should be!

In the next step I want to load the modified data back into BitmapImage and finally into an Image and add it again into the LayoutRoot:

BitmapImage modifiedSource = null;
try
{
    using (MemoryStream stream = new MemoryStream(buffer))
    {
        stream.Seek(0, SeekOrigin.Begin);
        BitmapImage b = new BitmapImage();
        b.SetSource(stream);
        modifiedSource = b;
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.ToString());
}

I found this code piece here: byte[] to BitmapImage in silverlight

As a last step I would simply create an Image again and add it to the LayoutRoot (just as I did it in the beginning:

Image modifiedImageElement = new Image();
modifiedImageElement.Name = "newImageElement";
modifiedImageElement.Source = modifiedSource;
modifiedImageElement.Stretch = Stretch.None;
LayoutRoot.Children.Add(modifiedImageElement);

But the final part is never reached because there occurs a "catastrophic failure" on the

b.SetSource(stream);

line, saying:

{System.Exception: Catastrophic failure (Ausnahme von HRESULT: 0x8000FFFF (E_UNEXPECTED))
   at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
   at MS.Internal.XcpImports.BitmapSource_SetSource(BitmapSource bitmapSource, CValue& byteStream)
   at System.Windows.Media.Imaging.BitmapSource.SetSourceInternal(Stream streamSource)
   at System.Windows.Media.Imaging.BitmapImage.SetSourceInternal(Stream streamSource)
   at System.Windows.Media.Imaging.BitmapSource.SetSource(Stream streamSource)
   at SilverlightApplication1.MainPage.button1_Click(Object sender, RoutedEventArgs e)}

I don't know what went wrong. I found an article here Silverlight: BitmapImage from stream throws exception (Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))), which happens to have the same exception, but as I read it, it seemed that he had this problem only when he was uploading a lot of images, and it worked fine for him for a little amount of images. So I am still clueless on how to solve this issue?

Do you guys maybe have any advice? Thanks!

2

There are 2 answers

3
Luke Woodward On BEST ANSWER

I think that you are getting an crash because the byte array that you reconstruct your image from is a 'raw' array of ARGB values, whereas the Source property is expecting a byte-stream that makes up a valid PNG or JPG file. Raw ARGB data is highly unlikely to be a valid PNG or JPG file as it will almost certainly not contain the valid header required by each of these formats.

I couldn't reproduce a crash; instead, the BitmapImages that were being created when I ran your code had PixelWidth and PixelHeight both zero. That could well be because I'm using a different image to the one you're using. Either way, crash or no crash, it's not desired behaviour.

If you want to load the modified data back into an Image, you don't need to create a byte array. Just create an Image from the WriteableBitmap object:

        Image modifiedImage = new Image()
        {
            Source = writeableBitmap,
            Stretch = Stretch.None
        };

I used this to add a copy of the image below the original one. The modified image had a 'washed-out' look compared to the original, which is exactly what I would expect if I halve all of the alpha-channel values.

If you really do need to convert a byte array back to an image, you can use the FromByteArray extension method within WriteableBitmapEx. You can then create an Image as described above.

0
Emond On

I ran into this exception before:

  1. When passing an unsupported image type to silverlight: BMP, ... Only JPG and PNG are supported. See the MSDN
  2. When passing incorrect data (not all of the stream or incorrectly formatted)