如何创建反转的PNG图像?

4
我正在创建一张基于我的底图的PNG图片,从底图上可以保存成PNG格式的图片。这是参考信息。
Graphics g = e.Graphics;
 ....
g.DrawLine(pen, new Point(x, y), new Point(x1, y1));
 .....
base.OnPaint(e);

using (var bmp = new Bitmap(500, 50))
{
    base.DrawToBitmap(bmp, new Rectangle(0, 0, 500, 50));
    bmp.Save(outPath);
}

这是一张单色透明图片,现在我要如何将其反转成填充任何颜色的PNG图像,并使实际图像部分保持透明?有什么可能性吗?

详细说明:透明部分将变成不透明,填充部分将变为透明。


我使用向量来编写极快的代码。 查看我的帖子以获取更多信息 - Reaven Clan
4个回答

8

如果你愿意使用unsafe代码,那么有一种更快的方法:

private unsafe void Invert(Bitmap bmp)
{
    int w = bmp.Width, h = bmp.Height;
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

    int* bytes = (int*)data.Scan0;
    for ( int i = w*h-1; i >= 0; i-- )
        bytes[i] = ~bytes[i];
    bmp.UnlockBits(data);
}

注意,此操作不考虑颜色,因此也会将颜色反转。如果您希望使用特定的颜色,则需要稍微修改代码。


2
添加了一个链接。基本上,这是一段使用指针的代码(就像那个 int* 一样)。.NET运行时无法验证此代码不会做一些愚蠢的事情,比如写入未分配的内存,因此被称为“不安全”。因为如果你不小心的话,它可能会破坏程序内存。要编译此代码,您需要在项目选项中启用不安全代码(默认情况下关闭),我认为还有一些安全方面的影响(不安全代码不能在部分受信任的程序集中工作或其他什么)。 - Vilx-
"unsafe" 代码并不一定是坏的。它可以提供很好的性能提升,就像在这种情况下一样。你只需要小心使用,并意识到安全方面的影响。 - Vilx-
未正确反转。 - Gray Programmerz

7

编辑(感谢Thomas的注释)

public void ApplyInvert()  
{  
    byte A, R, G, B;  
    Color pixelColor;  

    for (int y = 0; y < bitmapImage.Height; y++)  
    {  
        for (int x = 0; x < bitmapImage.Width; x++)  
        {  
            pixelColor = bitmapImage.GetPixel(x, y);  
            A = (byte)(255 - pixelColor.A); 
            R = pixelColor.R;  
            G = pixelColor.G;  
            B = pixelColor.B;  
            bitmapImage.SetPixel(x, y, Color.FromArgb((int)A, (int)R, (int)G, (int)B));  
        }  
    }  
}

从这里开始:C#中的图像处理:反转图像

不,我认为这是用于反转颜色(负片),我的问题是反转透明图像。因此,透明将变为不透明,填充区域将变为透明。 - manny
1
@manny 使用上述代码,但只翻转 A 组件 (A = 255 - pixelColor.A;),保留 R、G 和 B。 (并删除所有的强制类型转换,如果将 A、R、G 和 B 定义为 int,则不需要它们。) - Thomas
1
@Thomas 是的,非常完美,我已经得到了我的结果。谢谢你,Thomas。 - manny

7

对于任何想要快速反转位图颜色但不使用不安全方法的人:

public static void BitmapInvertColors(Bitmap bitmapImage)
{
    var bitmapRead   = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppPArgb);
    var bitmapLength = bitmapRead.Stride * bitmapRead.Height;
    var bitmapBGRA   = new byte[bitmapLength];
    Marshal.Copy(bitmapRead.Scan0, bitmapBGRA, 0, bitmapLength);
    bitmapImage.UnlockBits(bitmapRead);

    for (int i = 0; i < bitmapLength; i += 4)
    {
        bitmapBGRA[i]     = (byte)(255 - bitmapBGRA[i]);
        bitmapBGRA[i + 1] = (byte)(255 - bitmapBGRA[i + 1]);
        bitmapBGRA[i + 2] = (byte)(255 - bitmapBGRA[i + 2]);
        //        [i + 3] = ALPHA.
    }

    var bitmapWrite = bitmapImage.LockBits(new Rectangle(0, 0, bitmapImage.Width, bitmapImage.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
    Marshal.Copy(bitmapBGRA, 0, bitmapWrite.Scan0, bitmapLength);
    bitmapImage.UnlockBits(bitmapWrite);
}

Bitmap的GetPixel和SetPixel非常慢,这种方法的工作原理是将Bitmap像素复制到字节数组中,然后可以循环遍历并更改,最后再将像素复制回去。


0
当你说将透明部分反转为颜色时,你是否将实际颜色存储在PNG图像中,并将其设置为完全透明?许多程序将优化png通过从透明度中删除颜色数据,因此您无法将其反转。
颜色可以转换为透明度 但是透明度(没有底层颜色)无法转换为颜色。
如果你很幸运的话,你的PNG文件将不会被优化,而仍然保留原始颜色数据,但是如果你是根据用户输入来执行此操作,则对于高百分比情况下它不起作用。

是的,我的图像只有单色,要么是黑色要么是白色,所以反转后颜色不变,我在担心 alpha。 - manny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接