Friday, December 24, 2010

Silverlight: loading a WriteableBitmap from file

I’ve just spent quite some time trying to do something that seems very simple: embedding an image in a Silverlight application and loading this image into a WriteableBitmap (because I need to read the values of the individual pixels).

My first attempt was to add the image to my project as a resource and use the following code:

Uri uri = new Uri("Images/Texture.jpg", UriKind.Relative);
BitmapImage imageSource = new BitmapImage(uri);
WriteableBitmap bitmap = new WriteableBitmap(imageSource);  // EXCEPTION

However, an exception is thrown on the last line. Luckily the internet came to the rescue, and these two great site suggest basically the same solution:

  • Using BitmapCreateOptions.None to make sure the bitmap begins to load immediately.
  • Subscribing to events to know when the image has actually loaded.

However the proposed solution did not work in my case because the image fails to load with an AG_E_NETWORK_ERROR error.

In the end I took a different approach: I load the resource using Application.GetResourceStream so I’m sure that the data is completely loaded before it is handed to the WriteableBitmap. This is the code:

StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/Texture.jpg", UriKind.Relative));
 
BitmapImage src = new BitmapImage();
src.SetSource(sri.Stream);
WriteableBitmap image = new WriteableBitmap(src);

In my case it has the advantage of being synchronous which makes the overall code much simpler (but I understand that asynchronous behavior may often be better in a web-context).

When adding your image to your Silverlight project, the build action should be set to ‘Content’ instead of ‘Resource’. This means that the image will not be included in the dll, but it will be stored in the xap-file. You can check this by renaming the xap-file to zip and looking at the content.

So there are some non-intuitive steps involved when trying to accomplish this simple task. Hopefully this post can be helpful if someone else has this problem.

3 comments:

Michael Bakker said...

Thanks! This code snippet saved me a lot of time!

Dmitri Sinitson said...

Another one(WP7.1):

StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/Texture.jpg", UriKind.Relative));
return Microsoft.Phone.PictureDecoder.DecodeJpeg(sri.Stream);

Anonymous said...

Thank you so much!
It really helped me!