Charles Petzold



The LoadJpeg Advantage on Windows Phone

March 17, 2012
New York, N.Y.

Windows Phone includes a class named Extensions in the System.Windows.Media.Imaging namespace that contains two extension methods for WriteableBitmap named LoadJpeg and SaveJpeg. The first one loads a JPEG from a Stream into a WriteableBitmap, and the second saves the contents of a WriteableBitmap to a Stream.

Although I was overjoyed with the SaveJpeg method and used it a few times in my book, the LoadJpeg method seemed unnecessary because BitmapSource — the parent class to BitmapImage and WriteableBitmap — defines a SetSource method that alos accepts a Stream object for creating the image, and not only that, but it works with PNG files as well!

Today I found out that LoadJpeg has a definite benefit when loading large images.

For an MSDN Magazine article to be published in the June issue, I needed to download a 3811×2099 JPEG and create either a BitmapImage or WriteableBitmap from it. I used WebClient and wrote some test code to see if the download and bitmap creation worked OK:

void OnWebClientOpenReadCompleted(object sender, 
                                  OpenReadCompletedEventArgs args)
{
    if (!args.Cancelled && args.Error == null && args.Result != null)
    {
        BitmapImage bitmap = new BitmapImage();
        bitmap.SetSource(args.Result);
        Debug.WriteLine("{0} x {1}", bitmap.PixelWidth, bitmap.PixelHeight);
    }
}

What printed was "1906 x 1050". BitmapImage apparently does not want to deal with large images, and so cut it down to something it felt more comfortable with, discarding 75% of the pixels.

I then tried WriteableBitmap. Surely specifying the size of the image in the WriteableBitmap constructor would guarantee success:

void OnWebClientOpenReadCompleted(object sender, 
                                  OpenReadCompletedEventArgs args)
{
    if (!args.Cancelled && args.Error == null && args.Result != null)
    {
        WriteableBitmap bitmap = new WriteableBitmap(3811, 2099);
        bitmap.SetSource(args.Result);
        Debug.WriteLine("{0} x {1}", bitmap.PixelWidth, bitmap.PixelHeight);
    }
}

Nope: Once again I got "1906 x 1050".

At this point, I was already considering incorporating a JPEG decoder into the program so I could split it into several images, etc, because I really wanted the high-resolution image. I had forgotten about the extension methods in Windows Phone until I glimpsed them while trying to find some documentation about image restrictions. Surely an extension method couldn't work where a builtin method failed, but it was worth a try:

void OnWebClientOpenReadCompleted(object sender, 
                                  OpenReadCompletedEventArgs args)
{
    if (!args.Cancelled && args.Error == null && args.Result != null)
    {
        WriteableBitmap bitmap = new WriteableBitmap(3811, 2099);
        bitmap.LoadJpeg(args.Result);
        Debug.WriteLine("{0} x {1}", bitmap.PixelWidth, bitmap.PixelHeight);
    }
}

And much to my amazement it printed "3811 x 2099"!

It's hard to imagine what the difference is between SetSource and LoadJpeg, but for now I'll just acept it.