【问题标题】:Programmatically replace transparent regions in an image with white fill?以编程方式用白色填充替换图像中的透明区域?
【发布时间】:2011-07-22 11:06:30
【问题描述】:

我有一个 PNG 图像,我正在通过 .NET 中的 System.Drawing API 对其进行操作。它有很大的透明区域,我想用白色填充替换透明区域——这样图像中就没有透明区域了。在图像编辑程序中很容易......但到目前为止,我在 C# 中没有成功。

有人可以指点一下吗?

【问题讨论】:

  • 这完全取决于您如何定义“透明”和“替换为白色填充”。 PNG 支持 alpha 透明度,因此在图形编辑程序中,您的白色最终会变成灰色,因为像素的颜色是黑色,透明度为 50%。
  • 我确信所有这些都是有用的解决方案,但我无法让它们发挥作用,并发现客户端提供了一个更简单的解决方案。在我的例子中,我将图像从 Flex 应用程序发送到 .NET 以保存到服务器,然后我转而使用 Flex/Flash API 重新着色图像,然后将其传送到服务器。

标签: c# png system.drawing system.drawing.imaging


【解决方案1】:

我不确定如何检测透明像素。我知道如果 Alpha 为 0,它是完全透明的,如果是 255,它是不透明的。我不确定您是否应该检查 Alpha == 0 或 Alpha != 255 ;如果您可以尝试并给我一个有用的反馈。

来自MSDN

alpha 分量指定 颜色的透明度:0 是完全 透明的,而 255 是完全不透明的。 同样,A 值为 255 表示 一种不透明的颜色。从 1 开始的 A 值 通过 254 代表一个 半透明的颜色。颜色 A 接近时变得更加不透明 255.

    void  Foo(Bitmap image)
    {
        for (int y = 0; y < image.Height; ++y)
        {
            for (int x = 0; x < image.Width; ++x)
            {
                // not very sure about the condition.                   
                if (image.GetPixel(x, y).A != 255)
                {
                    image.SetPixel(x,y,Color.White);
                }
            }
        }

    }

【讨论】:

【解决方案2】:

我的例子:

    public void FillPngWhite(Bitmap bmp)
    {
        if (bmp.PixelFormat != PixelFormat.Format32bppArgb)
            throw new ApplicationException("Not supported PNG image!");

        // Lock the bitmap's bits.  
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
        BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat);

        // Get the address of the first line.
        IntPtr ptr = bmpData.Scan0;

        // Declare an array to hold the bytes of the bitmap.
        int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
        byte[] rgbaValues = new byte[bytes];

        // Copy the RGB values into the array.
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbaValues, 0, bytes);

        // array consists of values RGBARGBARGBA

        for (int counter = 0; counter < rgbaValues.Length; counter += 4)
        {
            double t = rgbaValues[counter + 3]/255.0; // transparency of pixel between 0 .. 1 , easier to do math with this
            double rt = 1 - t; // inverted value of transparency

            // C = C * t + W * (1-t) // alpha transparency for your case C-color, W-white (255)
            // same for each color
            rgbaValues[counter] = (byte) (rgbaValues[counter]*t + 255*rt); // R color
            rgbaValues[counter + 1] = (byte)(rgbaValues[counter + 1] * t + 255 * rt); // G color
            rgbaValues[counter + 2] = (byte)(rgbaValues[counter + 2] * t + 255 * rt); // B color

            rgbaValues[counter + 3] = 255; // A = 255 => no transparency 
        }
        // Copy the RGB values back to the bitmap
        System.Runtime.InteropServices.Marshal.Copy(rgbaValues, 0, ptr, bytes);

        // Unlock the bits.
        bmp.UnlockBits(bmpData);
    }

这是不同的原因:

我使用LockBits 代替GetPixelSetPixel。它更快,但更难理解。这是来自MSDN

的一个小修改示例

正如我在对您问题的评论中所说,我正在考虑真正的 aplha 价值。这将使具有 50% 透明度 (128) 的黑色看起来像灰色而不是黑色。这样做的原因是“在图形编辑器中用白色替换 alpha”我想在你的图像下面创建一个新层,用白色填充,然后将两个层拼合在一起。这个例子会有同样的效果。

【讨论】:

    【解决方案3】:

    一旦你有了位图对象的句柄,就可以这样做:

    Bitmap yourImage = HOWEVER YOU LOAD YOUR IMAGE;
    int width = YOUR IMAGE WIDTH;
    int height = YOUR IMAGE HEIGHT;
    
    Color c;
    Color white = new Color(255,255,255,255)
    for(int w = 0; w < width; w++)
    for(int h = 0; h < height; h++)
    {
        c = yourImage.GetPixel(w,h);
        yourImage.SetPixel(w,h, ((((short)(c.A)) & 0x00FF) <= 0)? white:c); //replace 0 here with some higher tolerance if needed
    }
    

    【讨论】:

    • Color.A 范围从 0 到 255。为什么abs(c.A)
    • 取决于系统,这个介于 0 和 255 之间的值仅存储在 1 个字节中,可以签名意味着 255 将显示为 -1,254 将显示为 -2,依此类推跨度>
    • 实际上更好的方法是 (((short)(c.A)) & 0x00FF)
    • c.A 是字节类型,在 c# 中字节的范围是 0 到 255,不是吗? msdn.microsoft.com/en-us/library/5bdb6693(VS.80).aspx
    • 可能,但我认为它在过去是有问题的,所以我认为最好保持安全
    【解决方案4】:

    这可能过于简单化了您的问题,但如果它位于表单或其他现成的控件上,您可以简单地将背景涂成白色,然后再将图像放在顶部。

    【讨论】:

      猜你喜欢
      • 2012-02-07
      • 2012-06-22
      • 2022-10-14
      • 2020-12-30
      • 1970-01-01
      • 2015-02-03
      • 1970-01-01
      • 1970-01-01
      • 2015-04-25
      相关资源
      最近更新 更多