C# 能否将位图图像中的一种颜色更改为另一种颜色?

C# 能否将位图图像中的一种颜色更改为另一种颜色?,c#,colors,bitmap,C#,Colors,Bitmap,对于Bitmap,有一种MakeTransparent方法,是否有一种类似的方法用于将一种颜色更改为另一种颜色 // This sets Color.White to transparent Bitmap myBitmap = new Bitmap(sr.Stream); myBitmap.MakeTransparent(System.Drawing.Color.White); 有什么可以做这样的事情吗 Bitmap myBitmap = new Bitmap(sr.Stream); myBi

对于
Bitmap
,有一种
MakeTransparent
方法,是否有一种类似的方法用于将一种颜色更改为另一种颜色

// This sets Color.White to transparent
Bitmap myBitmap = new Bitmap(sr.Stream);
myBitmap.MakeTransparent(System.Drawing.Color.White);
有什么可以做这样的事情吗

Bitmap myBitmap = new Bitmap(sr.Stream);
myBitmap.ChangeColor(System.Drawing.Color.Black, System.Drawing.Color.Gray);
您可以使用:

private void ChangeColor(Bitmap s, System.Drawing.Color source, System.Drawing.Color target)
{
    for (int x = 0; x < s.Width; x++)
    {
        for (int y = 0; y < s.Height; y++)
        {
            if (s.GetPixel(x, y) == source)
                s.SetPixel(x, y, target);
        }                
    }
}
private void ChangeColor(位图s、System.Drawing.Color源、System.Drawing.Color目标)
{
对于(int x=0;x
GetPixel和SetPixel是gdiplus.dll函数GdipBitmapGetPixel和GdipBitmapSetPixel的包装器

:

根据位图的格式,GdipBitmapGetPixel可能不会 返回与GdipBitmapSetPixel设置的值相同的值。例如 如果在像素格式为的位图对象上调用GdipBitmapSetPixel 为32bppPARGB时,像素的RGB分量被预乘。A. 对GdipBitmapGetPixel的后续调用可能会返回不同的值 因为四舍五入。另外,如果在位图上调用GdipBitmapSetPixel 颜色深度为每像素16位的对象,信息可以 在从32位转换到16位以及后续调用期间丢失 到GdipBitmapGetPixel可能返回不同的值


您需要一个库,它提供了一种无需处理像素即可修改图像颜色空间的方法。LeadTools有一个非常广泛的图像库,您可以使用它来支持颜色空间修改。

通过对Yorye Nathan评论的好奇,这是我通过修改创建的扩展

它可以将位图中的所有像素从一种颜色转换为另一种颜色

public static class BitmapExt
{
    public static void ChangeColour(this Bitmap bmp, byte inColourR, byte inColourG, byte inColourB, byte outColourR, byte outColourG, byte outColourB)
    {
        // Specify a pixel format.
        PixelFormat pxf = PixelFormat.Format24bppRgb;

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

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

        // Declare an array to hold the bytes of the bitmap. 
        // int numBytes = bmp.Width * bmp.Height * 3; 
        int numBytes = bmpData.Stride * bmp.Height;
        byte[] rgbValues = new byte[numBytes];

        // Copy the RGB values into the array.
        Marshal.Copy(ptr, rgbValues, 0, numBytes);

        // Manipulate the bitmap
        for (int counter = 0; counter < rgbValues.Length; counter += 3)
        {
            if (rgbValues[counter] == inColourR &&
                rgbValues[counter + 1] == inColourG &&
                rgbValues[counter + 2] == inColourB)

             {
                rgbValues[counter] = outColourR;
                rgbValues[counter + 1] = outColourG;
                rgbValues[counter + 2] = outColourB;
             }
        }

        // Copy the RGB values back to the bitmap
        Marshal.Copy(rgbValues, 0, ptr, numBytes);

        // Unlock the bits.
        bmp.UnlockBits(bmpData);
    }
}
公共静态类位图文本
{
公共静态void ChangeColour(此位图bmp、字节不着色、字节不着色、字节不着色、字节不着色、字节不着色、字节不着色)
{
//指定像素格式。
PixelFormat pxf=PixelFormat.Format24bppRgb;
//锁定位图的位。
矩形rect=新矩形(0,0,bmp.Width,bmp.Height);
位图数据bmpData=
bmp.LockBits(rect、ImageLockMode.ReadWrite、,
pxf);
//获取第一行的地址。
IntPtr ptr=bmpData.Scan0;
//声明一个数组以保存位图的字节。
//int numBytes=bmp.Width*bmp.Height*3;
int numBytes=bmpData.Stride*bmp.Height;
字节[]rgbValues=新字节[numBytes];
//将RGB值复制到数组中。
封送处理副本(ptr,rgb值,0,numBytes);
//操作位图
对于(int counter=0;counter
通过
bmp.ChangeColour调用(0128,0,0,0)

从以下位置提升代码:

公共静态类位图扩展
{
公共静态位图更改颜色(此位图图像,颜色从颜色,颜色到颜色)
{
ImageAttributes=新的ImageAttributes();
attributes.SetRemapTable(新的ColorMap[]
{
新颜色映射()
{
OldColor=fromColor,
NewColor=toColor,
}
},ColorAdjustType.位图);
使用(Graphics g=Graphics.FromImage(image))
{
g、 绘图图像(
形象,,
新矩形(Point.Empty、image.Size),
0,0,图像。宽度,图像。高度,
像素,
属性);
}
返回图像;
}
}

虽然我还没有对其进行基准测试,但这应该比在循环中执行GetPixel/SetPixel的任何解决方案都要快。它也有点简单。

效率低,答案很简单。因此,如果我有一张图片,我必须执行get
GetPixel
SetPixel
n次,其中n是像素数。因此,对于一个普通的图像,甚至是一个徽标,这可能是n=150k+…如果在语言中已经存在一个方法,那么它不会在背景中进行相同的迭代吗。。。谢谢帮助了我。您还可以修改代码以使用透明PNG。只需将像素格式更改为
PixelFormat.Format32bppArgb
,并将
计数器
增加4,而不是3。我需要这个,否则代码会弄乱透明的背景。谢谢。非常有用。但红色和蓝色的位是相反的使args
Color
objects;)更方便用户使用请注意,您确实应该从图像中获取像素格式并进行检查,而不仅仅是假设它。另一个注意:这会在遍历字节时忽略步幅。坏主意。逐行检查图像,否则,如果步幅与一行像素的精确数据长度不匹配,则操作将在第一行之后移动。步幅通常与四个字节的倍数对齐。