I'm trying to merge multiple Images into one image. Problem is that most libraries with such functionality are not available in a Windows 8.1 App. I'd prefer to not have to use external libraries such as WriteableBitmapEx
This is my current code which unfortunately doesn't work:
int count = 4;
int size = 150;
WriteableBitmap destination = new WriteableBitmap(300, 300);
BitmapFrame frame = await (await BitmapDecoder.CreateAsync(randomAccessStream)).GetFrameAsync(0);
PixelDataProvider pixelData = await frame.GetPixelDataAsync();
byte[] test = pixelData.DetachPixelData();
MemoryStream mem = new MemoryStream();
for (int row = 0; row < frame.PixelHeight; row++) {
for (int i = 0; i < count; i++)
{
mem.Write(test, row * (int)frame.PixelWidth * 4, (int)frame.PixelWidth * 4);
}
}
mem.Seek(0, SeekOrigin.Begin);
BitmapImage bmp = new BitmapImage();
bmp.SetSourceAsync(mem.AsRandomAccessStream());
If I set the bmp as the source of an Image UIElement nothing happens. My Idea was to get the Pixeldata as a byte array and to write it line by line (pixel row of each image, so they'd be next to each other) to a memory stream which is then used as the source of the BitmapImage.
Solved
Thanks to Aditya and Romasz I could solve this. The problem was that I had to encode the pixel data back to an image.
If anyone has the same Problem the following class merges the pixel data of multiple images and returns a BitmapImage:
public class ImageMerger
{
public static async Task<BitmapImage> MergeImages(int singleWidth, int singleHeight, params byte[][] pixelData)
{
int perRow = (int) Math.Ceiling(Math.Sqrt(pixelData.Length));
byte[] mergedImageBytes = new byte[singleHeight * singleWidth * perRow * perRow * 4];
for (int i = 0; i < pixelData.Length; i++ )
{
LoadPixelBytesAt(ref mergedImageBytes, pixelData[i], (i % perRow) * singleWidth, (i / perRow) * singleHeight, perRow * singleWidth, singleWidth, singleHeight);
}
InMemoryRandomAccessStream mem = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, mem);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)(singleHeight * perRow), (uint)(singleWidth * perRow), 91, 91, mergedImageBytes);
await encoder.FlushAsync();
BitmapImage bmp = new BitmapImage();
bmp.SetSourceAsync(mem);
return bmp;
}
private static void LoadPixelBytesAt(ref byte[] dest, byte[] src, int destX, int destY, int destW, int srcW, int srcH)
{
for (int i = 0; i < srcH; i++)
{
for (int j = 0; j < srcW; j++)
{
if (src.Length < ((i * srcW + j + 1) * 4)) return;
for (int p = 0; p < 4; p++)
dest[((destY + i) * destW + destX + j) * 4 + p] = src[(i * srcW + j) * 4 + p];
}
}
}
}
This takes any number of images and puts them next to each other with around as many images from left to right as from top to bottom. I.e. for 4 images it would return an image with them aligned like this:
1 2
3 4
Works for all of my images but one. There is one image that looks pretty weird after getting merged with others. Didn't figure out why yet.