问题描述
我正在尝试将多个图像合并为一个图像.问题是大多数具有此类功能的库在 Windows 8.1 应用程序中不可用.我宁愿不必使用外部库,例如 WriteableBitmapEx
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());
如果我将 bmp 设置为 Image UIElement 的来源,则什么也不会发生.我的想法是将 Pixeldata 作为字节数组获取,并将其逐行(每个图像的像素行,因此它们彼此相邻)写入内存流,然后用作 BitmapImage 的源.
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.
多亏了 Aditya 和 Romasz,我才能解决这个问题.问题是我必须将像素数据编码回图像.
Thanks to Aditya and Romasz I could solve this.The problem was that I had to encode the pixel data back to an image.
如果有人遇到同样的问题,下面的类会合并多张图片的像素数据并返回一个BitmapImage:
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];
}
}
}
}
这需要任意数量的图像并将它们彼此相邻放置,从左到右和从上到下的图像数量一样多.IE.对于 4 个图像,它将返回一个图像,它们像这样对齐:
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.
推荐答案
应该这样做:
byte[] PutOnCanvas(byte[] Canvas,byte[] Image,uint x,uint y,uint imageheight,uint imagewidth,uint CanvasWidth)
{
for (uint row = y; row < y+imageheight; row++)
for (uint col = x; col < x+imagewidth; col++)
for (int i = 0; i < 4; i++)
Canvas[(row * CanvasWidth + col) * 4 + i] = Image[((row-y) * imagewidth + (col - x)) * 4 + i];
return Canvas;
}
现在说我想并排放置两个 30x30 的图像(Image1 和 Image2 中的像素字节),并且它们之间的垂直边距为 10px.我会通过以下方式调用该函数:
Now say I want to put two images (pixelbytes in Image1 and Image2) of 30x30 side by side and have a vertical margin of 10px in between them. I would call the function in the following way:
byte[] Canvas = new byte[30 * 70 * 4];
Canvas=PutOnCanvas(Canvas,Image1,0,0,30,30,70);
Canvas=PutOnCanvas(Canvas,Image2,40,0,30,30,70);
然后将像素字节转换为 BMP 就大功告成了!
Then convert pixel bytes to BMP and you should be done!
这是将像素字节转换为图像的正确方法:
And this is the correct way to convert pixel bytes to image:
memStream.Size = 0;
var encoder = await BitmapEncoder.CreateAsync(Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId, memStream);
encoder.SetPixelData(
Windows.Graphics.Imaging.BitmapPixelFormat.Bgra8,
Windows.Graphics.Imaging.BitmapAlphaMode.Straight,
CanvasWidth, // pixel width
CanvasHeight, // pixel height
96, // horizontal DPI
96, // vertical DPI
PixelData);
try { await encoder.FlushAsync(); }
catch { }
memStream.Dispose();
这篇关于合并多个图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!