如何在C#UWP中使用原始像素数据合并图层?

时间:2017-10-08 16:34:56

标签: c# windows graphics uwp

因为通用Windows平台不支持展平位图"图层"默认情况下,我一直在创建一个算法(基于一个找到的here)来获取每个图层的每个像素,并将它们叠加在另一个上。问题在于,因为我使用Alpha来允许图像具有透明像素,所以我不确定如何正确合并像素,使其看起来好像是一个位于另一个之上的位置。

到目前为止,这是我的代码:

private unsafe SoftwareBitmap CompileImage()
    {
        SoftwareBitmap softwareBitmap = new SoftwareBitmap(BitmapPixelFormat.Bgra8, Width, Height);

        using (BitmapBuffer buffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Write))
        {
            using (var reference = buffer.CreateReference())
            {
                byte* dataInBytes;
                uint capacity;
                ((IMemoryBufferByteAccess)reference).GetBuffer(out dataInBytes, out capacity);

                BitmapPlaneDescription bufferLayout = buffer.GetPlaneDescription(0);

                for (int index = 0; index < layers.Length; index++)
                {
                    for (int i = 0; i < bufferLayout.Height; i++)
                    {
                        for (int j = 0; j < bufferLayout.Width; j++)
                        {
                            if(index == 0)
                            {
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 0] =
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 0]; //B
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 1] =
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 1]; //G
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 2] =
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 2]; //R
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 3] =
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 3]; //A
                            }
                            else if(index > 0)
                            {

                                //Attempts to "Average" pixel data
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 0] =
                                    (byte)(dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 0] *
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 0] / 2);
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 1] =
                                    (byte)(dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 1] *
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 1] / 2);
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 2] =
                                    (byte)(dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 2] *
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 2] / 2);
                                dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 3] =
                                    (byte)(dataInBytes[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 3] *
                                    layers[index].pixelData[bufferLayout.StartIndex + bufferLayout.Stride * i + 4 * j + 3] / 2);
                            }
                        }
                    }
                }
            }
        }
        return softwareBitmap;
    }

当前算法将获取每个图层中每个像素的平均BGRA值,并返回结果。这不是我打算做的。我该如何纠正呢?提前致谢

1 个答案:

答案 0 :(得分:0)

要应用Alpha混合,您可以将前一个颜色乘以反α,将当前颜色乘以alpha,当然您应该以0-1的比例(这就是为什么图形卡可以使用浮动颜色)。< / p>

每个例子,假设你有三个层,A,B和C,你用A作为基础,然后将它与B混合:(伪代码)

//bAlpha is thge alpha value of the current pixel from B in byte value
var alpha = bAlpha / 255.0f; 
var invAlpha = 1.0f - alpha;

//aRGB is the RGB value of the pixel on the layer A
//bRGB is the RGB value of the pixel on the layer B
var abRGB = aRGB * invAlpha + bRGB * alpha;

现在你应用第三层:

//cAlpha is thge alpha value of the current pixel from C in byte value
alpha = cAlpha / 255.0f;
invAlpha = 1.0f - alpha;

//abRGB is the RGB value of the previously mixed layers
//cRGB is the RGB value of the pixel on the layer C
var abcRGB = abRGB * invAlpha + cRGB * alpha;

当然所有这些都是在ARGB模式下,还有pARGB,其颜色已经预乘,所以你只需要将前一个颜色乘以反α并添加当前颜色。

//bAlpha is the alpha value of the current pixel from B in byte value
var invAlpha = 1.0f - (bAlpha / 255.0f);

//aRGB is the RGB value of the pixel on the layer A
//bRGB is the RGB value of the pixel on the layer B
var abRGB = aRGB * invAlpha + bRGB;

invAlpha = 1.0f - (cAlpha / 255.0f);

//abRGB is the RGB value of the previously mixed layers
//cRGB is the RGB value of the pixel on the layer C
var abcRGB = abRGB * invAlpha + cRGB;