C# 更改图像颜色

C# 更改图像颜色,c#,gdi+,gdi,C#,Gdi+,Gdi,我正在做一个项目,用户可以在购物车中为商品选择某种颜色 问题是有很多颜色可供选择,但制造商只提供了一个产品图像。现在我需要想出一种方法,根据用户的选择来改变这个产品的颜色。这与汽车制造商网站上的内容非常相似。。。当您单击一种颜色时,图像将用该颜色更新 有什么办法可以实现这一点吗 注意:我最初的想法是使用photoshop生成一个tranparent图像,该图像只包含产品的阴影细节(周围区域为实心/不透明),然后通过编程将此透明图像与另一个具有选定颜色的图像合并。理论上这是可以做到的。。。我只是想

我正在做一个项目,用户可以在购物车中为商品选择某种颜色

问题是有很多颜色可供选择,但制造商只提供了一个产品图像。现在我需要想出一种方法,根据用户的选择来改变这个产品的颜色。这与汽车制造商网站上的内容非常相似。。。当您单击一种颜色时,图像将用该颜色更新

有什么办法可以实现这一点吗


注意:我最初的想法是使用photoshop生成一个tranparent图像,该图像只包含产品的阴影细节(周围区域为实心/不透明),然后通过编程将此透明图像与另一个具有选定颜色的图像合并。理论上这是可以做到的。。。我只是想知道是否有人已经这样做过,或者是否有更好的方法。。。例如使用photoshop滤镜等:)

为您这样做,但成本相当高。

为您这样做,但成本相当高。

您正在考虑的可能是最好的选择。使用javascript将图像放置在主图像上,而不是在服务器端合并图像(假设它是Asp.net代码)。最好的方法是加载所有彩色图像和主图像,并将彩色图像放置在主图像上。使用PNG格式可以获得更好的透明图像


当您知道有固定数量的颜色选项时,您不必每次都使用服务器资源,每个用户都会更改颜色。

您正在考虑的可能是最好的选择。使用javascript将图像放置在主图像上,而不是在服务器端合并图像(假设它是Asp.net代码)。最好的方法是加载所有彩色图像和主图像,并将彩色图像放置在主图像上。使用PNG格式可以获得更好的透明图像


当您知道有固定数量的颜色选项时,您不必每次都使用服务器资源每个用户更改颜色。

如果需要着色的部分在原始图像中的色调是唯一的(您可以通过Photoshop或其他方式在源图像中更改它来使其唯一),这应该可以做到。它的工作原理是锁定一个输入位图(这样每个像素都可以被操作),然后将每个像素转换为HSB,这样,如果像素的色调在一定的色调范围内,则可以调整其色调(“颜色”)。这将有一个很好的效果,因为渐变(如阴影和轻微变化)也将正确着色

着色代码:

Bitmap bmp = ...
byte minHue = 0;
byte maxHue = 10;
byte newHue = 128;

BitmapData bmpData=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),
ImageLockMode.ReadWrite,bmp.PixelFormat);
IntPtr ptr=bmpData.Scan0;
int bytes=bmpData.Stride*bmpData.Height;
字节[]rgbValues=新字节[字节];
System.Runtime.InteropServices.Marshal.Copy(ptr,rgbvalue,0,字节);
对于(int c=0;cminHue&&hsb.H
HSBColor.cs(来自ZedGraph):

//
///色调饱和度亮度颜色类,用于存储颜色值和管理转换
///往返于结构中的RGB颜色。
/// 
/// 
///此类基于来自的代码http://www.cs.rit.edu/~ncs/color/作者尤金·维什涅夫斯基。
///此结构将色调、饱和度、亮度和alpha值作为
///从0到255的值。色调表示360度的一小部分
///可用颜色空间的大小。饱和度是颜色强度,其中0表示灰度
///255是最彩色的。对于亮度,0表示黑色,255表示255
///代表白色。
/// 
[可序列化]
公共结构HSBColor
{
/// 
///颜色色调值,范围从0到255。
/// 
/// 
///此属性实际上是将色轮上的360度重新缩放为255度
///可能的值。因此,每42.5个单位是一个新的扇区,如下所示
///约定:红色=0,黄色=42.5,绿色=85,青色=127.5,蓝色=170,品红色=212.5
/// 
公共字节H;
/// 
///颜色饱和度(强度)值,范围从0(灰度)到255(最彩色)。
/// 
公共字节;
/// 
///亮度值,范围从0(黑色)到255(白色)。
/// 
公共字节B;
/// 
///alpha值(不透明度),范围从0(透明)到255(不透明)。
/// 
公共字节A;
/// 
///构造函数从色调、饱和度和
///亮度值
/// 
///颜色色调值,范围从0到255
///颜色饱和度(强度)值,范围为0(灰度)
///至255(最彩色)
///亮度值,范围从0(黑色)到255(白色)
公共HSB颜色(内部h、内部s、内部b)
{
this.H=(字节)H;
this.S=(字节)S;
this.B=(字节)B;
这个.A=255;
}
/// 
///构造函数从色调、饱和度、,
///亮度和alpha值
/// 
///颜色色调值,范围从0到255
///颜色饱和度(强度)值,范围为0(灰度)
///至255(最彩色)
///亮度值,范围从0(黑色)到255(白色)
///alpha值(不透明度),范围从0(透明)到
///255(不透明)
公共HSB颜色(整数a、整数h、整数s、整数b)
:此(h、s、b)
{
this.A=(字节)A;
}
/// 
///构造函数从系统中加载结构
///结构。
/// 
///rgb结构con
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
    ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmpData.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
for (int c = 0; c < rgbValues.Length; c += 4)
{
    HSBColor hsb = new HSBColor(Color.FromArgb(
        rgbValues[c + 3], rgbValues[c + 2],
        rgbValues[c + 1], rgbValues[c]));
if(hsb.H > minHue && hsb.H < maxHue)
    {
        hsb.H = Convert.ToByte(newHue);
    }
    Color color = hsb.ToRGB();
    rgbValues[c] = color.B;
    rgbValues[c + 1] = color.G;
    rgbValues[c + 2] = color.R;
    rgbValues[c + 3] = color.A;
}
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);
/// <summary>
/// Hue-Saturation-Brightness Color class to store a color value, and to manage conversions
/// to and from RGB colors in the <see cref="Color" /> struct.
/// </summary>
/// <remarks>
/// This class is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// This struct stores the hue, saturation, brightness, and alpha values internally as
/// <see cref="byte" /> values from 0 to 255.  The hue represents a fraction of the 360 degrees
/// of color space available. The saturation is the color intensity, where 0 represents gray scale
/// and 255 is the most colored.  For the brightness, 0 represents black and 255
/// represents white.
/// </remarks>
[Serializable]
public struct HSBColor
{
    /// <summary>
    /// The color hue value, ranging from 0 to 255.
    /// </summary>
    /// <remarks>
    /// This property is actually a rescaling of the 360 degrees on the color wheel to 255
    /// possible values.  Therefore, every 42.5 units is a new sector, with the following
    /// convention:  red=0, yellow=42.5, green=85, cyan=127.5, blue=170, magenta=212.5
    /// </remarks>
    public byte H;
    /// <summary>
    /// The color saturation (intensity) value, ranging from 0 (gray scale) to 255 (most colored).
    /// </summary>
    public byte S;
    /// <summary>
    /// The brightness value, ranging from 0 (black) to 255 (white).
    /// </summary>
    public byte B;
    /// <summary>
    /// The alpha value (opacity), ranging from 0 (transparent) to 255 (opaque).
    /// </summary>
    public byte A;

    /// <summary>
    /// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation and
    /// brightness values
    /// </summary>
    /// <param name="h">The color hue value, ranging from 0 to 255</param>
    /// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
    /// to 255 (most colored)</param>
    /// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
    public HSBColor(int h, int s, int b)
    {
        this.H = (byte)h;
        this.S = (byte)s;
        this.B = (byte)b;
        this.A = 255;
    }

    /// <summary>
    /// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation,
    /// brightness, and alpha values
    /// </summary>
    /// <param name="h">The color hue value, ranging from 0 to 255</param>
    /// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
    /// to 255 (most colored)</param>
    /// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
    /// <param name="a">The alpha value (opacity), ranging from 0 (transparent) to
    /// 255 (opaque)</param>
    public HSBColor(int a, int h, int s, int b)
        : this(h, s, b)
    {
        this.A = (byte)a;
    }

    /// <summary>
    /// Constructor to load an <see cref="HSBColor" /> struct from a system
    /// <see cref="Color" /> struct.
    /// </summary>
    /// <param name="color">An rgb <see cref="Color" /> struct containing the equivalent
    /// color you want to generate</param>
    public HSBColor(Color color)
    {
        this = FromRGB(color);
    }


    /// <summary>
    /// Implicit conversion operator to convert directly from an <see cref="HSBColor" /> to
    /// a <see cref="Color" /> struct.
    /// </summary>
    /// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
    /// <returns>An equivalent <see cref="Color" /> struct that can be used in the GDI+
    /// graphics library</returns>
    public static implicit operator Color(HSBColor hsbColor)
    {
        return ToRGB(hsbColor);
    }

    /// <summary>
    /// Convert an <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
    /// </summary>
    /// <remarks>
    /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
    /// </remarks>
    /// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
    /// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
    public static Color ToRGB(HSBColor hsbColor)
    {
        Color rgbColor = Color.Black;

        // Determine which sector of the color wheel contains this hue
        // hsbColor.H ranges from 0 to 255, and there are 6 sectors, so 42.5 per sector
        int sector = (int)Math.Floor((double)hsbColor.H / 42.5);
        // Calculate where the hue lies within the sector for interpolation purpose
        double fraction = (double)hsbColor.H / 42.5 - (double)sector;

        double sFrac = (double)hsbColor.S / 255.0;
        byte p = (byte)(((double)hsbColor.B * (1.0 - sFrac)) + 0.5);
        byte q = (byte)(((double)hsbColor.B * (1.0 - sFrac * fraction)) + 0.5);
        byte t = (byte)(((double)hsbColor.B * (1.0 - sFrac * (1.0 - fraction))) + 0.5);


        switch (sector)
        {
            case 0:         // red - yellow
                rgbColor = Color.FromArgb(hsbColor.A, hsbColor.B, t, p);
                break;
            case 1:         // yellow - green
                rgbColor = Color.FromArgb(hsbColor.A, q, hsbColor.B, p);
                break;
            case 2:         // green - cyan
                rgbColor = Color.FromArgb(hsbColor.A, p, hsbColor.B, t);
                break;
            case 3:         // cyan - blue
                rgbColor = Color.FromArgb(hsbColor.A, p, q, hsbColor.B);
                break;
            case 4:         // blue - magenta
                rgbColor = Color.FromArgb(hsbColor.A, t, p, hsbColor.B);
                break;
            case 5:
            default:        // magenta - red
                rgbColor = Color.FromArgb(hsbColor.A, hsbColor.B, p, q);
                break;
        }

        return rgbColor;
    }

    /// <summary>
    /// Convert this <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
    /// </summary>
    /// <remarks>
    /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
    /// </remarks>
    /// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
    public Color ToRGB()
    {
        return ToRGB(this);
    }

    /// <summary>
    /// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
    /// </summary>
    /// <remarks>
    /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
    /// </remarks>
    /// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
    public HSBColor FromRGB()
    {
        return FromRGB(this);
    }

    /// <summary>
    /// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
    /// </summary>
    /// <remarks>
    /// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
    /// </remarks>
    /// <param name="rgbColor">The <see cref="Color" /> struct to be converted</param>
    /// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
    public static HSBColor FromRGB(Color rgbColor)
    {
        double r = (double)rgbColor.R / 255.0;
        double g = (double)rgbColor.G / 255.0;
        double b = (double)rgbColor.B / 255.0;

        double min = Math.Min(Math.Min(r, g), b);
        double max = Math.Max(Math.Max(r, g), b);

        HSBColor hsbColor = new HSBColor(rgbColor.A, 0, 0, 0);

        hsbColor.B = (byte)(max * 255.0 + 0.5);

        double delta = max - min;

        if (max != 0.0)
        {
            hsbColor.S = (byte)(delta / max * 255.0 + 0.5);
        }
        else
        {
            hsbColor.S = 0;
            hsbColor.H = 0;
            return hsbColor;
        }

        double h;
        if (r == max)
            h = (g - b) / delta;        // between yellow & magenta
        else if (g == max)
            h = 2 + (b - r) / delta;    // between cyan & yellow
        else
            h = 4 + (r - g) / delta;    // between magenta & cyan

        hsbColor.H = (byte)(h * 42.5);
        if (hsbColor.H < 0)
            hsbColor.H += 255;

        return hsbColor;
    }

}
// Get the source file and create a result bitmap of the same size
using (var source = Image.FromFile("old colour image.png", false))
using (var result = new Bitmap(source.Width, source.Height))
{
    // Build a colour map of old to new colour
    ColorMap[] colorMap = BuildArrayOfOldAndNewColours();

    // Build image attributes with the map
    var attr = new ImageAttributes();
    attr.SetRemapTable(colorMap);

    // Draw a rectangle the same size as the image
    var rect = new Rectangle(0, 0, source.Width, source.Height);

    // Draw the old image into the new one with one colour mapped to the other
    var g = Graphics.FromImage(result);
    g.DrawImage(source, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr);

    result.Save("new colour image.png");
}