How to get pixel data in the default format (XAML)
[ This article is for Windows 8.x and Windows Phone 8.x developers writing Windows Runtime apps. If you’re developing for Windows 10, see the latest documentation ]
We show you how to use a BitmapDecoder object to get pixel data from an image. The pixels are packaged as a byte array and the BitmapDecoder object automatically selects the best format to use.
BitmapDecoder can automatically determine the best fit pixel format for the image and provide pixel data in that format. This can be useful if you are loading images stored in a format, such as JPEG-XR, that supports greater than 8 bit-per-channel precision. If you have BitmapDecoder determine the optimal pixel format, you must detect and handle every possible combination of pixel format and alpha mode, as these are determined at runtime when the image is decoded.
Note
If you want to get the pixel data in a particular format, see How to get pixel data in a particular format.
What you need to know
Technologies
Prerequisites
- We assume you know how to create a basic Windows Runtime app using C++, C#, or Visual Basic. For more info, see Create a "Hello, world" app (XAML).
- You have a BitmapDecoder object. How to decode an image walks you through that process.
Instructions
Step 1: Get a decoder object
Write the beginning a function that receives a BitmapDecoder object.
async void GetDefaultPixelData(Windows.Graphics.Imaging.BitmapDecoder decoder)
{
The decoder lets you access the pixel data. If you don't have a decoder object yet, see How to decode an image.
Step 2: Get a pixel data provider object
Call the GetPixelDataAsync method with no parameters. When GetPixelDataAsync returns, the pixel data is allocated and ready to use.
var pixelDataProvider = await decoder.GetPixelDataAsync();
In this case, the pixel format and alpha mode are automatically determined, EXIF orientation is applied and the pixel data is color managed to sRGB. See GetPixelDataAsync for more info.
Step 3: Handle each pixel format and alpha mode combination
Because the pixel format and alpha mode of the returned pixel data is determined at runtime, your app must detect and handle each potential combination, with its own unique code path. You can determine the pixel format and alpha mode of the returned pixel data by querying the BitmapPixelFormat and BitmapAlphaMode properties on the BitmapDecoder.
In this example, we walk each pixel’s color channel values. So, you must handle different pixel bit depths and channel orderings.
The ProcessPixelArray method, which has two overloads, is part of your app’s code and is defined in the next step.
var rawPixels = pixelDataProvider.DetachPixelData();
switch (decoder.BitmapPixelFormat)
{
case Windows.Graphics.Imaging.BitmapPixelFormat.Rgba16:
ushort[] rgba16pixels = new ushort[rawPixels.Length / 2];
// This involves an additional in-memory copy of the pixel data.
System.Buffer.BlockCopy(rawPixels, 0, rgba16pixels, 0, rawPixels.Length);
ProcessPixelArray(
rgba16pixels,
decoder.OrientedPixelWidth,
decoder.OrientedPixelHeight,
1, // Green channel offset
2 // Blue channel offset
);
break;
case Windows.Graphics.Imaging.BitmapPixelFormat.Rgba8:
ProcessPixelArray(
rawPixels,
decoder.OrientedPixelWidth,
decoder.OrientedPixelHeight,
1, // Green channel offset
2 // Blue channel offset
);
break;
case Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8:
ProcessPixelArray(
rawPixels,
decoder.OrientedPixelWidth,
decoder.OrientedPixelHeight,
1, // Green channel offset
0 // Blue channel offset
);
break;
// BitmapAlphaMode is ignored by our processing algorithm.
}
}
Note In this example, we handle the Rgba16 pixel format by copying the data into an ushort array. This results in a second in-memory copy of the pixel data. If you are editing a very large image, this will increase the memory consumption of your app.
Step 4: Loop through the pixels
Implement the ProcessPixelArray methods needed to handle each pixel format combination. The code here zeroes out the green and blue channels, leaving the red and alpha channels.
// Applies a simple processing algorithm to a ushort array of pixel data.
void ProcessPixelArray(ushort[] pixels, uint width, uint height, uint gOffset, uint bOffset)
{
for (uint i = 0; i < height; i++)
{
for (uint j = 0; j < width; j++)
{
pixels[(i * height + j) * 4 + gOffset] = 0; // Green channel
pixels[(i * height + j) * 4 + bOffset] = 0; // Blue channel
}
}
}
// Applies a simple processing algorithm to a byte array of pixel data.
void ProcessPixelArray(byte[] pixels, uint width, uint height, uint gOffset, uint bOffset)
{
for (uint i = 0; i < height; i++)
{
for (uint j = 0; j < width; j++)
{
pixels[(i * height + j) * 4 + gOffset] = 0; // Green channel
pixels[(i * height + j) * 4 + bOffset] = 0; // Blue channel
}
}
}
Note The zero parameter overload of GetPixelDataAsync always applies EXIF orientation if the flag is present in the image. So, when getting the dimensions of the image it is important to use the OrientedPixelWidth and OrientedPixelHeight properties, instead of pixelWidth and PixelHeight. The OrientedPixelWidth and OrientedPixelHeight properties reflect any change in dimensions resulting from EXIF orientation.