Pages

Friday, 14 February 2014

Save WriteableBitmap as StorageFile in WinRT app

WriteableBitmap is quite useful when app requires image processing. It provides a BitmapSource, which can be written & manipulated. Ultimately that bitmap source is supplied to image control of Windows 8 app. Majorly WritableBitmap is more used with WriteableBitmapEx library, which is a collection of extension methods for the WriteableBitmap.

But we won't go for manipulating images using WriteableBitmap or WriteableBitmapEx, but we step forward to the next step, which is saving it as file i.e. StorageFile. It's obvious that end user will definitely wants to share or save the modified image or better say WriteableBitmap. So we will need to convert WriteableBitmap to StorageFile.

Before going to code directly, let me explain API used in that. For image encoding WinRT offers BitmapEncoder class. For image encoding we have to select BitmapEncoderGuid which is basically format of image viz JPEG, PNG, TIFF, etc. It's actually unique identifier for each bitmap encoder.

We will first export WriteableBitmap's pixel buffer into byte array. After that we will initialize the bitmap encoder with Guid & destination file stream. At last we will set the pixel data to bitmap encoder. Bitmap encoder's SetPixelData(...) gets various parameters to write the pixels in various ways. Check out the method metadata given below. At last we will have the file ready. Let's check out the code.

Metadata of method and enum.

// Summary:
//     Specifies the alpha mode of pixel data.
public enum BitmapAlphaMode
{
    // Summary:
    //     The alpha value has been premultiplied. Each color is first scaled by the
    //     alpha value. The alpha value itself is the same in both straight and premultiplied
    //     alpha. Typically, no color channel value is greater than the alpha channel
    //     value. If a color channel value in a premultiplied format is greater than
    //     the alpha channel, the standard source-over blending math results in an additive
    //     blend.
    Premultiplied = 0,
    //
    // Summary:
    //     The alpha value has not been premultiplied. The alpha channel indicates the
    //     transparency of the color.
    Straight = 1,
    //
    // Summary:
    //     The alpha value is ignored.
    Ignore = 2,
}


// Summary:
//     Specifies the pixel format of pixel data. Each enumeration value defines
//     a channel ordering, bit depth, and type.
public enum BitmapPixelFormat
{
    // Summary:
    //     The pixel format is unknown.
    Unknown = 0,
    //
    // Summary:
    //     The pixel format is R16B16G16A16 unsigned integer.
    Rgba16 = 12,
    //
    // Summary:
    //     The pixel format is R8G8B8A8 unsigned integer.
    Rgba8 = 30,
    //
    // Summary:
    //     The pixel format is B8G8R8A8 unsigned integer.
    Bgra8 = 87,
}

// Summary:
//     Sets the frame bitmap pixel data using the parameters specified in the arguments.
//
// Parameters:
//   pixelFormat:
//     The pixel format of the pixel data.
//
//   alphaMode:
//     The alpha mode of the pixel data.
//
//   width:
//     The width, in pixels, of the pixel data.
//
//   height:
//     The height, in pixels, of the pixel data.
//
//   dpiX:
//     The horizontal resolution, in dots per inch, of the pixel data.
//
//   dpiY:
//     The vertical resolution, in dots per inch, of the pixel data.
//
//   pixels:
//     The pixel data.
public void SetPixelData(BitmapPixelFormat pixelFormat, BitmapAlphaMode alphaMode, uint width, uint height, double dpiX, double dpiY, byte[] pixels);

The code to convert WriteableBitmap object to StorageFile in WinRT app

using System.Runtime.InteropServices.WindowsRuntime;

private async Task<StorageFile> WriteableBitmapToStorageFile(WriteableBitmap WB, FileFormat fileFormat)
{
    string FileName = "MyFile.";
    Guid BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
    switch (fileFormat)
    {
        case FileFormat.Jpeg:
            FileName += "jpeg";
            BitmapEncoderGuid = BitmapEncoder.JpegEncoderId;
            break;

        case FileFormat.Png:
            FileName += "png";
            BitmapEncoderGuid = BitmapEncoder.PngEncoderId;
            break;

        case FileFormat.Bmp:
            FileName += "bmp";
            BitmapEncoderGuid = BitmapEncoder.BmpEncoderId;
            break;

        case FileFormat.Tiff:
            FileName += "tiff";
            BitmapEncoderGuid = BitmapEncoder.TiffEncoderId;
            break;

        case FileFormat.Gif:
            FileName += "gif";
            BitmapEncoderGuid = BitmapEncoder.GifEncoderId;
            break;
    }

    var file = await Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFileAsync(FileName, CreationCollisionOption.GenerateUniqueName);
    using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoderGuid, stream);
        Stream pixelStream = WB.PixelBuffer.AsStream();
        byte[] pixels = new byte[pixelStream.Length];
        await pixelStream.ReadAsync(pixels, 0, pixels.Length);

        encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore,
                            (uint)WB.PixelWidth,
                            (uint)WB.PixelHeight,
                            96.0,
                            96.0,
                            pixels);
        await encoder.FlushAsync();
    }
    return file;
}

private enum FileFormat
{
    Jpeg,
    Png,
    Bmp,
    Tiff,
    Gif
}

Don't forget to add System.Runtime.InteropServices.WindowsRuntime namespace.

I hope this blog post would be helpful to you. I request you to share it as much as you can. If you need any help shout out me on Twitter & Facebook or comment below. I will catch you ASAP. Cheers!
Web Informer Button