Processing photos

High resolution photos, such as resolution of 7712x4352 photos, use a considerable amount of memory when loaded to a bitmap. Each pixel takes four bytes of memory, so the whole image takes 128 megabytes when uncompressed. Another issue with high resolution photos is rendering, as the image does not fit to the maximum texture size of 4096x4096 pixels on Windows Phone 8 so it gets cropped. However, this is nothing to worry about as there are a number of ways to work with big images.

Displaying captured photos

If you just want to display a newly capture high resolution photo on the screen, the easiest way to do this is by using BitmapImage that can take the JPEG data stream in directly. Note, however, that BitmapImage cannot display the high resolution photo in its full resolution, but instead it provides an easy way to render a scaled down version.

First, let's have a simple page with an Image element in it for displaying the preview.

<!-- Simple preview page -->
<phone:PhoneApplicationPage x:Class="PreviewPage" ... >
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid x:Name="ContentPanel">
            <Image x:Name="PreviewImage"/>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>  

Then, on the C# side of the page we can use the BitmapImage's int DecodePixelWidth and int DecodePixelHeight properties to configure the size of the bitmap that is created when we set the JPEG data stream to the bitmap in the void BitmapImage.SetSource(Stream streamSource) method call. In order to know whether the stream contains a portrait or landscape photo you can use the ImageProviderInfo from Nokia Imaging SDK.

using Nokia.Graphics.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;

...

public partial class PreviewPage : PhoneApplicationPage
{
    ...

    private BitmapImage _bitmap = new BitmapImage();

    public PreviewPage()
    {
        InitializeComponent();

        PreviewImage.Source = _bitmap;

        ...
    }

    ...

    private void InitializePreview(Stream stream)
    {
        // Find out the image orientation using the Nokia Imaging SDK, and set BitmapImage
        // decode options accordingly

        stream.Position = 0;

        using (StreamImageSource source = new StreamImageSource(stream))
        {
            ImageProviderInfo info = null;

            Task.Run(async () => { info = await source.GetInfoAsync(); }).Wait();

            if (info.ImageSize.Width >= info.ImageSize.Height)
            {
                _bitmap.DecodePixelWidth = 1536;
                _bitmap.DecodePixelHeight = 0;
            }
            else
            {
                _bitmap.DecodePixelWidth = 0;
                _bitmap.DecodePixelHeight = 1536;
            }

            // Set stream as bitmap source

            stream.Position = 0;

            _bitmap.SetSource(stream);
        }
    }

    ...
}   

If you need to convert your image data instance between Stream and IBuffer, here's how you can do it easily:

using System.Runtime.InteropServices.WindowsRuntime; // MemoryStream extensions

...

public class Utilities
{
    ...

    /// <summary>
    /// Returns a buffer with the contents of the given stream.
    /// <param name="stream">Source stream</param>
    /// <returns>Buffer with the contents of the given stream</returns>
    /// </summary>
    public static IBuffer StreamToBuffer(Stream stream)
    {
        var memoryStream = stream as MemoryStream;

        if (memoryStream == null)
        {
            using (memoryStream = new MemoryStream())
            {
                stream.Position = 0;
                stream.CopyTo(memoryStream);

                try
                {
                    // Some stream types do not support flushing

                    stream.Flush();
                }
                catch (Exception ex)
                {
                }

                return memoryStream.GetWindowsRuntimeBuffer();
            }
        }
        else
        {
            return memoryStream.GetWindowsRuntimeBuffer();
        }
    }

    /// <summary>
    /// Returns a stream with the contents of the given buffer.
    /// <param name="stream">Source buffer</param>
    /// <returns>Stream with the contents of the given stream</returns>
    /// </summary>
    public static Stream BufferToStream(IBuffer buffer)
    {
        return buffer.AsStream();
    }

    ...
}

In addition to using BitmapImage this way, it is also easy to do the downscaling yourself using the Nokia Imaging SDK. Nokia Imaging SDK enables you to specify, for example, the maximum buffer size (bytes) and the maximum image size (pixels) for the operation, and provides you with a new data buffer that you can also use for other purposes than just displaying the downscaled photo on the screen - like for saving and sharing.

using Nokia.Graphics.Imaging;

...

public class Utilities
{
    ...

    /// <summary>
    /// Asynchronously scales an image so that the resulting JPEG data does not exceed maxBytes in size and
    /// also does not exceed the dimensions given in maxSize.
    /// <param name="image">Image to scale</param>
    /// <param name="maxBytes">Maximum size in bytes for the buffer to be returned</param>
    /// <param name="maxSize">Maximum size in pixels for the scaled image</param>
    /// <returns>JPEG data buffer of the resulting scaled photo/returns>
    /// </summary>
    private static async Task<IBuffer> ScaleAsync(IBuffer image, uint maxBytes, Size maxSize)
    {
        using (var source = new BufferImageSource(image))
        {
            var info = await source.GetInfoAsync();

            if (info.ImageSize.Width * info.ImageSize.Height > maxSize)
            {
                var resizeConfiguration = new AutoResizeConfiguration(maxBytes, maxSize,
                    new Size(0, 0), AutoResizeMode.Automatic, 0, ColorSpace.Yuv420);

                return await Nokia.Graphics.Imaging.JpegTools.AutoResizeAsync(buffer, resizeConfiguration);
            }
            else
            {
                return image;
            }
        }
    }

    ...
}  

To display the photo in full resolution you can create multiple bitmaps, each smaller or equal to the maximum texture size of 4096x4096 pixels. Also reframing the original high resolution photo in order to display only parts of it is easy using the Nokia Imaging SDK.

using Nokia.Graphics.Imaging;
using Windows.Foundation;

...

public class Utilities
{
    ...

    /// <summary>
    /// Asynchronously reframes the photo and returns the result as a JPEG data buffer.
    /// <param name="image">Photo to reframe</param>
    /// <param name="area">Reframing area</param>
    /// <returns>JPEG data buffer of the resulting reframed photo/returns>
    /// </summary>
    public static async Task<IBuffer> Reframe(IBuffer image, Rect area)
    {
        using (var source = new BufferImageSource(image))
        using (var effect = new FilterEffect(source))
        {
            effect.Filters = new List<IFilter>()
            {
                new ReframingFilter()
                {
                    ReframingArea = area
                }
            };

            using (var renderer = new JpegRenderer(effect))
            {
                return await renderer.RenderAsync();
            }
        }
    }

    /// <summary>
    /// Asynchronously reframes the photo and renders the result to the given bitmap.
    /// <param name="image">Photo to reframe</param>
    /// <param name="area">Reframing area</param>
    /// <param name="bitmap">Bitmap to render the resulting reframed photo to</param>
    /// </summary>
    public static async Task Reframe(IBuffer image, Rect area, WriteableBitmap bitmap)
    {
        using (var source = new BufferImageSource(image))
        using (var effect = new FilterEffect(source))
        {
            effect.Filters = new List<IFilter>()
            {
                new ReframingFilter()
                {
                    ReframingArea = area
                }
            };

            using (var renderer = new WriteableBitmapRenderer(effect, bitmap))
            {
                await renderer.RenderAsync();
            }
        }
    }

    ...
}  

Last updated 12 November 2013

Back to top

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×