C# System.Drawing 中的 Alpha 掩码?

发布于 2024-09-18 03:38:08 字数 382 浏览 4 评论 0原文

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

我追求的效果如下所示:

Effect I'm after

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

I'm trying to draw an image, with a source Bitmap and an alpha mask Bitmap, using the System.Drawing.Graphics object.
At the moment I loop X and Y and use GetPixel and SetPixel to write the source color and mask alpha to a third Bitmap, and then render that.
However this is very inefficient and I am wondering if there is an faster way to achieve this?

The effect I'm after looks like this:

Effect I’m after

The grid pattern represents transparency; you probably knew that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

勿忘心安 2024-09-25 03:38:09

是的,更快的方法是使用 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(...);

此示例从遮罩图像中的 blue 通道导出输出中的 alpha 通道。我确信您可以根据需要将其更改为使用遮罩的红色或 Alpha 通道。

Yes, the faster way to do this is to use Bitmap.LockBits and use pointer arithmetic to retrieve the values instead of GetPixel and SetPixel. The downside, of course, is that you have to use unsafe code; if you make a mistake, you can cause some really bad crashes in your program. But if you keep it simple and self-contained, it should be fine (hey, if I can do, you can do it too).

For example, you could do something like this (not tested, use at your own risk):

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(...);

This example derives the alpha channel in the output from the blue channel in the mask image. I’m sure you can change it to use the mask’s red or alpha channel if required.

樱&纷飞 2024-09-25 03:38:09

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

  • 反转您的蒙版,使圆圈透明,其余部分是
    使用输入位图中未使用的颜色(例如示例中的红色)
  • 使用以下命令在图像顶部绘制蒙版
    Graphics.FromImage(image).DrawImage(mask)...
  • 将图像上的蒙版颜色设置为透明
    (image.MakeTransparent(Color.Red))

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

Depending on your requirements this may be much easier:

  • Invert your mask so that the circle is transparent and the rest is
    from a color not used in your input bitmap (like red in your example)
  • Draw your mask on top of your image using
    Graphics.FromImage(image).DrawImage(mask)...
  • Set the mask color as transparent on your image
    (image.MakeTransparent(Color.Red))

The only drawback of this method is that it needs you to make sure the mask color is not used in your image.
I don't know if this is slower or faster than the manual way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文