Reputation: 472
I have this function which converts the array of ushort to a grayscale image. I do the converts to convert the values to a byte-array and then use BitmapEncoder.
public static async Task<StorageFile> WriteableBitmapToStorageFile(ushort[,] image, bool isScaleValues, List<KeyValuePair<string, BitmapTypedValue>> metadata)
{
//Setup image
var imgHeight = image.GetLength(0);
var imgWidth = image.GetLength(1);
float maxVal = 1;
if (isScaleValues)
{
for (int i = 0; i < imgHeight; i++)
{
for (int j = 0; j < imgWidth; j++)
{
if (maxVal < image[i, j])
{
maxVal = image[i, j];
}
}
}
}
byte[] data = new byte[imgWidth * imgHeight];
if (image != null)
{
if (isScaleValues)
{
for (int x = 0; x < imgHeight; x++)
for (int y = 0; y < imgWidth; y++)
data[x * imgWidth + y] = (byte)(((double)UInt16.MaxValue * (double)image[x, y]) / (double)maxVal);
}
else
{
for (int x = 0; x < imgHeight; x++)
for (int y = 0; y < imgWidth; y++)
data[x * imgWidth + y] = (byte)image[x, y];
}
}
string FileName = "MyFile.png";
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(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Gray16, BitmapAlphaMode.Ignore,
(uint) imgWidth,
(uint) imgHeight,
2822.222222222222,
2822.222222222222,
data);
await encoder.BitmapProperties.SetPropertiesAsync(metadata);
await encoder.FlushAsync();
}
return file;
}
I get this exception at SetPixelData
:
An exception of type 'System.ArgumentException' occurred in mscorlib.ni.dll but was not handled in user code
WinRT information: Windows.Graphics.Imaging: The bitmap pixel format is unsupported.
Additional information: The parameter is incorrect.
Windows.Graphics.Imaging: The bitmap pixel format is unsupported.
The 2D ushort array is already 16-bit grayscale image with first dimension being the height and the 2nd being the width. Since grayscale is apparently not supported, I will need to save it as Rgba16, so the question is: How to convert grayscale to RBG?
AFAIK, I just need to set all R,G,B to the same value but how would I place the values in the array.
What is the RGBA16 format in binary?
Upvotes: 0
Views: 2668
Reputation: 15758
Since you have had a 2D ushort array contains 16 bpp grayscale pixels. I'd suggest you use this array to create a SoftwareBitmap with Gray16 pixel format first and then use SoftwareBitmap.Convert method to convert it to Rgba16 pixel format.
BitmapPixelFormat.Gray16 represent 16 bpp grayscale pixel format which means each pixel takes two bytes. So we need a byte array whose length is twice of the ushort array and use BitConverter.GetBytes(UInt16) method to convert ushort
to byte[]
. Following is a simple sample:
ushort[,] image = { { ushort.MinValue, ushort.MaxValue, ushort.MaxValue }, { ushort.MaxValue, ushort.MinValue, ushort.MaxValue }, { ushort.MaxValue, ushort.MaxValue, ushort.MinValue } };
var imgHeight = image.GetLength(0);
var imgWidth = image.GetLength(1);
byte[] data = new byte[image.Length * 2];
for (int i = 0; i < imgHeight; i++)
{
for (int j = 0; j < imgWidth; j++)
{
byte[] byteArray = BitConverter.GetBytes(image[i, j]);
data[i * imgWidth * 2 + j * 2] = byteArray[0];
data[i * imgWidth * 2 + j * 2 + 1] = byteArray[1];
}
}
//Create a SoftwareBitmap with 16 bpp grayscale pixel format
var softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Gray16, imgWidth, imgHeight);
softwareBitmap.CopyFromBuffer(data.AsBuffer());
//Convert pixel format to Rgba16 so that we can save it to the file
softwareBitmap = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Rgba16);
var outputFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("MyFile.png", CreationCollisionOption.GenerateUniqueName);
//Save softwareBitmap to file
using (IRandomAccessStream stream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
// Create an encoder with the desired format
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
// Set the software bitmap
encoder.SetSoftwareBitmap(softwareBitmap);
await encoder.FlushAsync();
}
Upvotes: 0