【问题标题】:Alpha masking in c# System.Drawing?c# System.Drawing 中的 Alpha 遮罩?
【发布时间】:2011-04-08 22:15:30
【问题描述】:

我正在尝试使用System.Drawing.Graphics 对象绘制图像,其源为Bitmap 和alpha 蒙版Bitmap。 目前我循环 X 和 Y 并使用 GetPixelSetPixel 将源颜色和蒙版 alpha 写入第三个 Bitmap,然后渲染它。 然而,这是非常低效的,我想知道是否有更快的方法来实现这一点?

我想要的效果是这样的:

网格图案代表透明度;你可能知道。

【问题讨论】:

  • 既然你说你正在使用 System.Drawing.Graphics,这可能是题外话,但这里有一个 WPF 中不透明蒙版的链接,它将利用硬件加速:msdn.microsoft.com/en-us/library/…跨度>
  • 离题,但仍然令人着迷 - 谢谢!

标签: c# alpha masking


【解决方案1】:

是的,更快的方法是使用Bitmap.LockBits 并使用指针算法来检索值,而不是GetPixelSetPixel。当然,缺点是您必须使用不安全的代码;如果你犯了一个错误,你可能会在你的程序中导致一些非常糟糕的崩溃。但是如果你保持简单和独立,那应该没问题(嘿,如果我能做到,你也可以做到)。

例如,您可以这样做(未经测试,使用风险自负):

Bitmap mask = ...;
Bitmap input = ...;

Bitmap output = new Bitmap(input.Width, input.Height, PixelFormat.Format32bppArgb);
var rect = new Rectangle(0, 0, input.Width, input.Height);
var bitsMask = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsInput = input.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
var bitsOutput = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
unsafe
{
    for (int y = 0; y < input.Height; y++)
    {
        byte* ptrMask = (byte*) bitsMask.Scan0 + y * bitsMask.Stride;
        byte* ptrInput = (byte*) bitsInput.Scan0 + y * bitsInput.Stride;
        byte* ptrOutput = (byte*) bitsOutput.Scan0 + y * bitsOutput.Stride;
        for (int x = 0; x < input.Width; x++)
        {
            ptrOutput[4 * x] = ptrInput[4 * x];           // blue
            ptrOutput[4 * x + 1] = ptrInput[4 * x + 1];   // green
            ptrOutput[4 * x + 2] = ptrInput[4 * x + 2];   // red
            ptrOutput[4 * x + 3] = ptrMask[4 * x];        // alpha
        }
    }
}
mask.UnlockBits(bitsMask);
input.UnlockBits(bitsInput);
output.UnlockBits(bitsOutput);

output.Save(...);

此示例从掩码图像中的 蓝色 通道导出输出中的 alpha 通道。如果需要,我相信您可以将其更改为使用蒙版的红色或 Alpha 通道。

【讨论】:

  • 是的,但速度非常快。您可能使用的任何其他实现同样必须遍历像素。
  • 嗯,它有效,而且肯定比我以前的方法快,谢谢!
  • 我需要这个来做一些不相关的事情,它就像一个冠军,谢谢!
  • 请注意,您不需要需要使用不安全的代码 - 您可以使用 Marshal.Copy 复制到/从 BitmapData.Scan0 托管指针 (IntPtr),然后操作托管字节数组。开销很小。
  • FastBitmap 做了类似的事情
【解决方案2】:

根据您的要求,这可能会容易得多:

  • 反转蒙版,使圆圈透明,其余部分透明 来自输入位图中未使用的颜色(如示例中的红色)
  • 使用 Graphics.FromImage(image).DrawImage(mask)...
  • 将图像上的蒙版颜色设置为透明 (image.MakeTransparent(Color.Red))

此方法的唯一缺点是它需要您确保图像中没有使用遮罩颜色。 不知道这比手动方式慢还是快。

【讨论】:

  • 在我的场景(大位图)中,这将是最快的
猜你喜欢
  • 2010-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 1970-01-01
  • 2015-03-23
  • 2012-12-30
相关资源
最近更新 更多