我正在开发一个项目,在购物车中,用户可以为某个项目选择某种颜色。
问题是有大量的颜色可供选择,但制造商只提供了一个产品图片。现在我需要想出一种基于用户选择来改变该产品颜色的方法。这与进入汽车制造商网站非常相似......当您点击颜色时,图像会以该颜色更新。
任何想法如何实现这一目标?
注意:我最初的想法是使用photoshop来创建一个透明图像,该图像只有produc的阴影细节(周围区域是实心/不透明),然后以编程方式将此透明图像与另一个具有所选颜色的图像合并。理论上可以做到......我只是想知道某人之前是否已经这样做过和/或是否有更好的方法......比如使用photoshop过滤器等:)
答案 0 :(得分:3)
您正在考虑的那个可能是最好的选择。而不是在服务器端合并图像(假设它是Asp.net代码)使用javascript将图像放在主图像上。最好的方法是加载所有彩色图像和主图像,并将彩色图像放在主要图像上。使用PNG格式可获得更好的透明图像。
当您知道自己拥有固定数量的颜色选项时,每次用户更改颜色时都不必使用服务器资源。
答案 1 :(得分:1)
如果需要着色的部分在色调方面在原件中是唯一的(并且您可以通过Photoshop或其他东西在源图像中更改它而使其独特),这应该可以解决问题。它通过锁定输入位图(因此可以操纵每个像素),然后将每个像素转换为HSB,以便可以调整像素的色调(“颜色”)如果它落在某个特定范围内色调范围。这将产生很好的效果,因为阴影和轻微差异等渐变也会正确着色。
着色代码:
Bitmap bmp = ...
byte minHue = 0;
byte maxHue = 10;
byte newHue = 128;
...
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);
HSBColor.cs(来自ZedGraph):
/// <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;
}
}
答案 2 :(得分:0)
Scene7为你做这件事,但费用非常高。
答案 3 :(得分:0)
我认为这个链接对你有帮助,这个Dll 非常强大的图像处理功能。
http://www.codeproject.com/KB/GDI-plus/Image_Processing_Lab.aspx
答案 4 :(得分:0)
您可以使用ColourMap[]
数组轻松地将一个图像中的颜色映射到一组新颜色 - 问题是源颜色和目标颜色。
我使用这样的代码,使用单一颜色的地图(黑色),具有不同的透明度alpha级别(尽管您可以以相同的方式使用灰度图像),然后将比例尺中的每种颜色映射到新的比例:
// 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");
}
这适用于简单的图标,但您可能需要相当复杂的地图来处理任何照片质量。