将HSV循环代码从Delphi转换为C#

我正在尝试将函数转换为从Delphi到C#创建HSV Circle,但结果不是正确的。

我的目标是为Windows Phone 7做一个应用程序,我只使用WP7.1 SDK和WriteableBitmapEx库。

delphi代码:

 FUNCTION CreateHueSaturationCircle(CONST size: INTEGER; CONST ValueLevel: INTEGER; CONST BackgroundColor: TColor): TBitmap; VAR dSquared: INTEGER; H,S,V: INTEGER; i: INTEGER; j: INTEGER; Radius: INTEGER; RadiusSquared: INTEGER; row: pRGBTripleArray; X: INTEGER; Y: INTEGER; BEGIN RESULT := TBitmap.Create; RESULT.PixelFormat := pf24bit; RESULT.Width := size; RESULT.Height := size; // Fill with background color RESULT.Canvas.Brush.Color := BackGroundColor; RESULT.Canvas.FillRect(RESULT.Canvas.ClipRect); Radius := size DIV 2; RadiusSquared := Radius * Radius; V := ValueLevel; FOR j := 0 TO RESULT.Height - 1 DO BEGIN Y := Size - 1 - j - Radius; {Center is Radius offset} row := RESULT.Scanline[Size - 1 - j]; FOR i := 0 TO RESULT.Width - 1 DO BEGIN X := i - Radius; dSquared := X * X + Y * Y; IF dSquared  360 THEN H := H - 360; row[i] := HSVtoRGBTriple(H,S,V) END END; END; END; FUNCTION HSVtoRGBTriple(CONST H,S,V: INTEGER): TRGBTriple; CONST divisor: INTEGER = 255 * 60; VAR f: INTEGER; hTemp: INTEGER; p,q,t: INTEGER; VS: INTEGER; BEGIN IF S = 0 THEN RESULT := RGBtoRGBTriple(V, V, V) // achromatic: shades of gray ELSE BEGIN // chromatic color IF H = 360 THEN hTemp := 0 ELSE hTemp := H; f := hTemp MOD 60; // f is IN [0, 59] hTemp := hTemp DIV 60; // h is now IN [0,6) VS := V * S; p := V - VS DIV 255; // p = v * (1 - s) q := V - (VS*f) DIV divisor; // q = v * (1 - s*f) t := V - (VS*(60 - f)) DIV divisor; // t = v * (1 - s * (1 - f)) CASE hTemp OF 0: RESULT := RGBtoRGBTriple(V, t, p); 1: RESULT := RGBtoRGBTriple(q, V, p); 2: RESULT := RGBtoRGBTriple(p, V, t); 3: RESULT := RGBtoRGBTriple(p, q, V); 4: RESULT := RGBtoRGBTriple(t, p, V); 5: RESULT := RGBtoRGBTriple(V, p, q); ELSE RESULT := RGBtoRGBTriple(0,0,0) // should never happen; // avoid compiler warning END END END 

Delphi代码的结果:

德尔福img

我的C#代码:

  public struct HSV { public float h; public float s; public float v; } public void createHsvCircle() { int size = 300; wb = new WriteableBitmap(size, size); wb.Clear(GraphicsUtils.WhiteColor); int radius = size / 2; int radiusSquared = radius * radius; int x; int y; int dSquared; HSV hsv; hsv.v = 255F; for (int j = 0; j < size; j++) { y = size - 1 - j - radius; for (int i = 0; i < size; i++) { x = i - radius; dSquared = x * x + y * y; if (dSquared  360) { hsv.h -= 360; } Color color = GraphicsUtils.HsvToRgb(hsv); wb.SetPixel(i, j, color); } } } wb.Invalidate(); } public static Color HsvToRgb(float h, float s, float v) { h = h / 360; if (s > 0) { if (h >= 1) h = 0; h = 6 * h; int hueFloor = (int)Math.Floor(h); byte a = (byte)Math.Round(RGB_MAX * v * (1.0 - s)); byte b = (byte)Math.Round(RGB_MAX * v * (1.0 - (s * (h - hueFloor)))); byte c = (byte)Math.Round(RGB_MAX * v * (1.0 - (s * (1.0 - (h - hueFloor))))); byte d = (byte)Math.Round(RGB_MAX * v); switch (hueFloor) { case 0: return Color.FromArgb(RGB_MAX, d, c, a); case 1: return Color.FromArgb(RGB_MAX, b, d, a); case 2: return Color.FromArgb(RGB_MAX, a, d, c); case 3: return Color.FromArgb(RGB_MAX, a, b, d); case 4: return Color.FromArgb(RGB_MAX, c, a, d); case 5: return Color.FromArgb(RGB_MAX, d, a, b); default: return Color.FromArgb(RGB_MAX, 0, 0, 0); } } else { byte d = (byte)(v * RGB_MAX); return Color.FromArgb(255, d, d, d); } } public static Color HsvToRgb(HSV hsv) { return HsvToRgb(hsv.h, hsv.s, hsv.v); } 

我的c#结果:

CSHARP

我做错了什么?

提前致谢。

用解决方案编辑

有了@Aybe的精彩答案,我可以从HSV做一个工作版本。

这是WP7 SDK的工作代码:

  public const double PI = 3.14159265358979323846264338327950288d; public void createHsvCircle(double value = 1.0d) { if (value  1.0d) throw new ArgumentOutOfRangeException("value"); var size = 1024; wb = new WriteableBitmap(size, size); // fill with white. var white = Colors.White; for (int index = 0; index < wb.Pixels.Length; index++) { wb.Pixels[index] = 0xFF << 24 | white.R << 16 | white.G << 8 | white.B; } var cx = size / 2; var cy = size / 2; var radius = cx; var radiusSquared = radius * radius; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { var x = i - cx; var y = j - cy; var distance = (double)x * x + y * y; if (distance  360.0d) { angle -= 360.0d; } var hue = angle / 360.0d; // hue must be into 0 to 1. var saturation = Math.Sqrt(distance) / radius; // saturation must be into 0 to 1. var hsv = new HSV(hue, saturation, value); var rgb = RGB.FromHsv(hsv.H, hsv.S, hsv.V); wb.Pixels[j * size + i] = 0xFF << 24 | rgb.R << 16 | rgb.G << 8 | rgb.B; } } } wb.Invalidate(); } public static RGB FromHsv(double hue, double saturation, double value) { if (hue  1.0d) throw new ArgumentOutOfRangeException("hue"); if (saturation  1.0d) throw new ArgumentOutOfRangeException("saturation"); if (value  1.0d) throw new ArgumentOutOfRangeException("value"); if (saturation == 0.0d) { var b1 = (byte)(value * 255); return new RGB(b1, b1, b1); } double r; double g; double b; var h = hue * 6.0d; if (h == 6.0d) { h = 0.0d; } int i = (int)Math.Floor(h); var v1 = value * (1.0d - saturation); var v2 = value * (1.0d - saturation * (h - i)); var v3 = value * (1.0d - saturation * (1.0d - (h - i))); switch (i) { case 0: r = value; g = v3; b = v1; break; case 1: r = v2; g = value; b = v1; break; case 2: r = v1; g = value; b = v3; break; case 3: r = v1; g = v2; b = value; break; case 4: r = v3; g = v1; b = value; break; default: r = value; g = v1; b = v2; break; } r = r * 255.0d; if (r > 255.0d) { r = 255.0d; } g = g * 255.0d; if (g > 255.0d) { g = 255.0d; } b = b * 255.0d; if (b > 255.0d) { b = 255.0d; } return new RGB((byte)r, (byte)g, (byte)b); } 

而现在,新的结果:

okimg

谢谢!

花了一个小时左右后,我在这个过程中学到了一些东西……

现在代码:(适用于任何规模)

这是HSL,但我给你了你有其他算法的url。

 using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; namespace ColorWheel { ///  /// Interaction logic for MainWindow.xaml ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void BuildWheel() { var width = 1024; var height = width; var cx = width/2; var cy = height/2; var colors = new int[width*height]; var gray = Colors.Gray.ToBgr32(); for (int index = 0; index < colors.Length; index++) colors[index] = gray; var radius = cx; var radiusSquared = radius*radius; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { var x = j - cx; var y = i - cy; var distanceSquared = (double) x*x + y*y; if (distanceSquared <= radiusSquared) // In circle { var h = Math.Atan2(x, y).ToDegrees() + 180.0d; // Angle var s = 1.0d; var l = (1.0d - ((1.0d/radiusSquared)*distanceSquared)); // 1 - (distance normalized) var hsl = new HSL((float) h, (float) s, (float) l); var rgb = RGB.FromHsl(hsl.H, hsl.S, hsl.L); colors[i*width + j] = rgb.R << 16 | rgb.G << 8 | rgb.B; } } } var bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, null); bitmap.WritePixels(new Int32Rect(0, 0, width, height), colors, width*4, 0); image.Source = bitmap; } private void Window_Loaded(object sender, RoutedEventArgs e) { BuildWheel(); } } public static class Helpers { public static double ToDegrees(this double radians) { return radians*57.2957795130823; // radians * (180.0d / Math.PI) } public static double ToRadians(this double degrees) { return degrees*0.0174532925199433; // degrees * (Math.PI / 180.0d) } } public static class ColorExtensions { public static Color FromBgr32(this Int32 color) { return Color.FromRgb((byte) ((color & 0xFF0000) >> 16), (byte) ((color & 0xFF00) >> 8), (byte) (color & 0xFF)); } public static int ToBgr32(this Color color) { return color.R << 16 | color.G << 8 | color.B; } } ///  /// Represents a color in an HSL space. ///  [StructLayout(LayoutKind.Sequential)] public struct HSL { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _h; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _s; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _l; ///  /// Returns the fully qualified type name of this instance. ///  ///  A  containing a fully qualified type name.  /// 2 public override string ToString() { return string.Format("H: {0}, S: {1}, L: {2}", _h, _s, _l); } ///  /// Create a new instance of  . ///  ///  Value of  component.  ///  Value of  component.  ///  Value of  component.  public HSL(double h, double s, double l) { _h = h; _s = s; _l = l; } ///  /// Gets the value of the hue component. ///  public double H { get { return _h; } } ///  /// Gets the value of the saturation component. ///  public double S { get { return _s; } } ///  /// Gets the value of the lightness component. ///  public double L { get { return _l; } } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (obj.GetType() != typeof (HSL)) return false; return Equals((HSL) obj); } public bool Equals(HSL other) { return other._h.Equals(_h) && other._l.Equals(_l) && other._s.Equals(_s); } ///  /// Create a new instance of  , from RGB values. ///  ///  Value of the red component.  ///  Value of the green component.  ///  Value of the blue component.  ///   instance created.  public static HSL FromRGB(byte red, byte green, byte blue) { var r1 = red/255.0d; var g1 = green/255.0d; var b1 = blue/255.0d; var min = Math.Min(r1, Math.Min(g1, b1)); var max = Math.Max(r1, Math.Max(g1, b1)); var l = (max + min)/2.0d; var s = 0.0d; var h = 0.0d; if (min == max) { h = 0.0d; s = 0.0d; } else { if (l < 0.5d) { s = (max - min)/(max + min); } else if (l >= 0.5d) { s = (max - min)/(2.0d - max - min); } if (r1 == max) { h = (g1 - b1)/(max - min); } else if (g1 == max) { h = 2.0d + (b1 - r1)/(max - min); } else if (b1 == max) { h = 4.0d + (r1 - g1)/(max - min); } } h *= 60.0d; if (h < 0.0d) h += 360.0d; return new HSL(h, s, l); } ///  /// Returns the hash code for this instance. ///  ///  A 32-bit signed integer that is the hash code for this instance.  /// 2 public override int GetHashCode() { unchecked { var result = _h.GetHashCode(); result = (result*397) ^ _l.GetHashCode(); result = (result*397) ^ _s.GetHashCode(); return result; } } public static BitmapSource GetHslPalette(int width = 360, int height = 100) { // Creates an HSL palette image like in Photoshop, etc ... var pixels = new int[width*height]; const double saturation = 1.0d; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var hue = (1.0d/width)*x*360.0d; var lightness = 1.0d - ((1.0f/height)*y); var rgb = RGB.FromHsl(hue, saturation, lightness); pixels[y*width + x] = 0xFF << 24 | rgb.R << 16 | rgb.G << 8 | rgb.B; } } return BitmapSource.Create(width, height, 96, 96, PixelFormats.Pbgra32, null, pixels, width*4); } public static bool operator ==(HSL left, HSL right) { return left.Equals(right); } public static bool operator !=(HSL left, HSL right) { return !left.Equals(right); } } ///  /// Represents a color in an RGB space. ///  [StructLayout(LayoutKind.Sequential)] public struct RGB { [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _r; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _g; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _b; ///  /// Create a new instance of  . ///  ///  Value of red component.  ///  Value of green component.  ///  Value of blue component.  public RGB(byte r, byte g, byte b) { _r = r; _g = g; _b = b; } ///  /// Returns the fully qualified type name of this instance. ///  ///  A  containing a fully qualified type name.  /// 2 public override string ToString() { return string.Format("R: {0}, G: {1}, B: {2}", _r, _g, _b); } ///  /// Gets the value of the red component. ///  public byte R { get { return _r; } } ///  /// Gets the value of the green component. ///  public byte G { get { return _g; } } ///  /// Gets the value of the blue component. ///  public byte B { get { return _b; } } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (obj.GetType() != typeof (RGB)) return false; return Equals((RGB) obj); } public bool Equals(RGB other) { return other._b == _b && other._g == _g && other._r == _r; } ///  /// Create a new instance of  , from HSL values. ///  ///  Hue, from 0.0 to 360.0.  ///  Saturation, from 0.0 to 1.0.  ///  Lightness, from 0.0 to 1.0.  ///   instance created.  public static RGB FromHsl(double hue, double saturation, double lightness) { if (hue < 0.0d || hue > 360.0d) throw new ArgumentOutOfRangeException("hue"); if (saturation < 0.0d || saturation > 1.0d) throw new ArgumentOutOfRangeException("saturation"); if (lightness < 0.0d || lightness > 1.0d) throw new ArgumentOutOfRangeException("lightness"); if (saturation == 0.0d) { var b1 = (byte) (lightness*255); return new RGB(b1, b1, b1); } var t2 = 0.0d; if (lightness < 0.5d) t2 = lightness*(1.0d + saturation); else if (lightness >= 0.5d) t2 = lightness + saturation - lightness*saturation; var t1 = 2.0d*lightness - t2; var h = hue/360.0d; var tr = h + 1.0d/3.0d; var tg = h; var tb = h - 1.0d/3.0d; tr = tr < 0.0d ? tr + 1.0d : tr > 1.0d ? tr - 1.0d : tr; tg = tg < 0.0d ? tg + 1.0d : tg > 1.0d ? tg - 1.0d : tg; tb = tb < 0.0d ? tb + 1.0d : tb > 1.0d ? tb - 1.0d : tb; double r; if (6.0d*tr < 1.0d) r = t1 + (t2 - t1)*6.0d*tr; else if (2.0d*tr < 1.0d) r = t2; else if (3.0d*tr < 2.0d) r = t1 + (t2 - t1)*((2.0d/3.0d) - tr)*6.0d; else r = t1; double g; if (6.0d*tg < 1.0d) g = t1 + (t2 - t1)*6.0d*tg; else if (2.0d*tg < 1.0d) g = t2; else if (3.0d*tg < 2.0d) g = t1 + (t2 - t1)*((2.0d/3.0d) - tg)*6.0d; else g = t1; double b; if (6.0d*tb < 1.0d) b = t1 + (t2 - t1)*6.0d*tb; else if (2.0d*tb < 1.0d) b = t2; else if (3.0d*tb < 2.0d) b = t1 + (t2 - t1)*((2.0d/3.0d) - tb)*6.0d; else b = t1; return new RGB((byte) (r*255), (byte) (g*255), (byte) (b*255)); } ///  /// Returns the hash code for this instance. ///  ///  A 32-bit signed integer that is the hash code for this instance.  /// 2 public override int GetHashCode() { unchecked { var result = _b.GetHashCode(); result = (result*397) ^ _g.GetHashCode(); result = (result*397) ^ _r.GetHashCode(); return result; } } public static bool operator ==(RGB left, RGB right) { return left.Equals(right); } public static bool operator !=(RGB left, RGB right) { return !left.Equals(right); } } } 

WP7设备上的位深度是不是默认为16位? 在我的Omnia 7上。 有一个控制此参数的注册表设置,但它可能并非在所有手机上都可用,您应该将颜色从24位抖动到16位,然后它将在所有手机上都可用。 我建议你看一下Microsoft.Xna.Framework.Graphics.PackedVector ,有一些构造函数,比如BGR565,它接受浮点作为输入。 并且满足您的所有颜色转换需求: http : //www.easyrgb.com/ ,几乎所有算法都用于在颜色空间之间进行转换。