如何将黑色以外的颜色设置为使用makeTransparent()创建的图像

时间:2014-08-27 18:50:40

标签: c# image image-processing gdi

我正在使用c#Bitmap对象上的MakeTransparent()函数调用将图像转换为透明图像。调用此方法时,它会通过设置Alpha通道将背景颜色转换为透明,但然后将背景颜色转换为黑色。

我需要找到一种将背景颜色转换回白色或原始颜色的快速方法,因为我偶尔需要将图像展平为非Alpha通道启用格式。

让透明似乎没有任何标记或重载允许你告诉它单独留下背景颜色,并且逐像素地改变图像是低效的方法。任何人都有任何建议或GDI技巧来解决这个问题?

2 个答案:

答案 0 :(得分:0)

使用托管代码接口似乎不是一种快速的方法。使用单独的像素操作,或使用非托管代码更新像素似乎是唯一真正的选择。

答案 1 :(得分:0)

这实际上可以在托管代码中使用Marshal.Copy从位图对象复制支持字节数组,然后编辑它,然后将其复制回来。

所以基本上,考虑到这种一般方法,你只需逐行检查像素,检测哪些像素具有你想要替换的颜色,并将它们的字母字节设置为0.

请注意" ARGB"指的是一个读取像素的Int32值内的组件的顺序。由于该值是little-endian,因此给定偏移处的字节的实际顺序是相反的; B =偏移+ 0,G =偏移+ 1,R =偏移+ 2,A =偏移+ 3。

/// <summary>
/// Clears the alpha value of all pixels matching the given colour.
/// </summary>
public static Bitmap MakeTransparentKeepColour(Bitmap image, Color clearColour)
{
    Int32 width = image.Width;
    Int32 height = image.Height;
    // Paint on 32bppargb, so we're sure of the byte data format
    Bitmap bm32 = new Bitmap(width, height, PixelFormat.Format32bppArgb);
    using (Graphics gr = Graphics.FromImage(bm32))
        gr.DrawImage(image, new Rectangle(0, 0, width, height));

    BitmapData sourceData = bm32.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bm32.PixelFormat);
    Int32 stride = sourceData.Stride;
    // Copy the image data into a local array so we can use managed functions to manipulate it.
    Byte[] data = new Byte[stride * height];
    Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
    Byte colR = clearColour.R;
    Byte colG = clearColour.G;
    Byte colB = clearColour.B;
    for (Int32 y = 0; y < height; y++)
    {
        Int32 inputOffs = y * stride;
        for (Int32 x = 0; x < width; x++)
        {
            if (data[inputOffs + 2] == colR && data[inputOffs + 1] == colG && data[inputOffs] == colB)
                data[inputOffs + 3] = 0;
            inputOffs += 4;
        }
    }
    // Copy the edited image data back.
    Marshal.Copy(data, 0, sourceData.Scan0, data.Length);
    bm32.UnlockBits(sourceData);
    return bm32;
}

这可以通过公差级别而不是精确匹配来轻松增强,例如Math.Abs(data[inputOffs + 2] - colR) < tolerance,或者通过将字节实际转换为颜色对象并进行其他类型的近似(如色调/饱和度/亮度)。