合并多个图像 [英] Merging multiple Images

查看:22
本文介绍了合并多个图像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将多个图像合并为一个图像.问题是大多数具有此类功能的库在 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();

这篇关于合并多个图像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆