1

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!

Community
  • 1
  • 1
Thomas Mondel
  • 1,944
  • 3
  • 20
  • 25
  • There seems to be something wrong with the "byte[] to BitmapImage in silverlight" example you copied from... If it is a raw byte array, not an image file, how are the dimensions of the image determined? It looks like that sample would only work if the stream were bytes from an image file (JPG or PNG). – iCollect.it Ltd Aug 13 '12 at 14:52

2 Answers2

3

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.

Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
  • you were right about the width and height values and your solution worked fine for me! thank you! – Thomas Mondel Aug 14 '12 at 08:03
  • Exactly. I also blogged about that here: http://kodierer.blogspot.de/2009/11/convert-encode-and-decode-silverlight.html - Rene (author WriteableBitmapEx) – Rene Schulte Aug 14 '12 at 09:38
  • @ReneSchulte: Cool. Since you are the author: do you maybe have any idea about this issue [WriteableBitmapEx GetPixel() returns wrong value](http://stackoverflow.com/questions/11974359/writeablebitmapex-getpixel-returns-wrong-value) too? Any kind of advice is very appreciated! – Thomas Mondel Aug 15 '12 at 21:41
1

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)
Emond
  • 50,210
  • 11
  • 84
  • 115