简体   繁体   English

在c#System.Drawing中使用Alpha掩码?

[英]Alpha masking in c# System.Drawing?

I'm trying to draw an image, with a source Bitmap and an alpha mask Bitmap , using the System.Drawing.Graphics object. 我正在尝试使用System.Drawing.Graphics对象绘制带有源Bitmap和alpha蒙版Bitmap的图像。 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. 目前我循环X和Y并使用GetPixelSetPixel将源颜色和掩码alpha写入第三个Bitmap ,然后渲染它。 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: 我之后的效果看起来像这样:

效果我在追求

The grid pattern represents transparency; 网格图案代表透明度; you probably knew that. 你可能知道这一点。

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 . 是的,更快的方法是使用Bitmap.LockBits并使用指针算法来检索值而不是GetPixelSetPixel 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. 此示例从掩模图像中的蓝色通道输出alpha输出。 I'm sure you can change it to use the mask's red or alpha channel if required. 我确定你可以改变它,以便在需要时使用面具的红色或alpha通道。

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)... 使用Graphics.FromImage(image).DrawImage(mask)在图像上绘制蒙版...
  • Set the mask color as transparent on your image (image.MakeTransparent(Color.Red)) 在图像上将蒙版颜色设置为透明(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. 我不知道这比手动方式更慢还是更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM