5401


下記画像のように、ひし形パレットとカスタムパレットのカラーダイアログを使用したいのですがなかなか見当たりません。  
このダイアログの実装方法など分かる方がいましたらご教授をお願いします。

[![カラーダイアログ](https://i.stack.imgur.com/c7t06.png)](https://i.stack.imgur.com/c7t06.png)  
(出典: [s-msft.com](https://i-msdn.sec.s-msft.com/dynimg/IC33311.png))


CC BY-SA 4.0
2015-01-27T03:15:28.223
5396
2020-12-24T00:00:24.947
2020-12-24T00:00:24.947
19769
7626
question
c# wpf
ひし形パレットとカスタムパレットのカラーダイアログを探しています


これは[HSV(HSI、HSL、HSB、HLS)などと呼ばれる色空間](https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93)です。[色相環](https://ja.wikipedia.org/wiki/%E8%89%B2%E7%9B%B8)を立体にしたものと言えば理解しやすいでしょうか。Wikipediaには2種類が言及されていますが、細かいバリエーションはさらに多いです。

質問の図の左はHS平面、右はHV平面を表したものです。HSVからRGBへの変換は六角錐モデルの場合

[code]

    public static class Hsv3
    {
        private static byte ToByte(double d)
        {
            if (d < 0)
            {
                return 0;
            }
            else if (d > 255)
            {
                return 255;
            }
            return (byte)Math.Round(d);
        }
        public static Color ToRgb(double H, double S, double V)
        {
            var v = ToByte(255 * V);
            if (S == 0)
            {
                return Color.FromRgb(v, v, v);
            }
            var hr = H / (2 * Math.PI);
            var hd = (float)(6 * (hr - Math.Floor(hr)));
            var h = (int)Math.Floor(hd);
            var p = ToByte(v * (1 - S));
            var q = ToByte(v * (1 - S * (hd - h)));
            var t = ToByte(v * (1 - S * (1 - hd + h)));
    
            switch (h)
            {
                case 0:
                    return Color.FromRgb(v, t, p);
                case 1:
                    return Color.FromRgb(q, v, p);
                case 2:
                    return Color.FromRgb(p, v, t);
                case 3:
                    return Color.FromRgb(p, q, v);
                case 4:
                    return Color.FromRgb(t, p, v);
                default:
                    return Color.FromRgb(v, p, q);
            }
        }
    }
    
[/code]

というような感じです。

上記を利用したカラーピッカーを簡単に作ると

## XAML

[code]

    <Canvas
        Name="canvas"
        Width="256"
        Height="256"
        Margin="8"
        MouseUp="canvas_MouseUp" />
    <Image
        Name="image"
        Width="256"
        Height="256"
        Margin="8"
        MouseUp="image_MouseUp" />
    
[/code]

## コードビハインド

[code]

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            // 6角形
            {
                // 個々の6角形の形状を作成
                var hexRadius = 10;
                var sg = new StreamGeometry();
                using (var c = sg.Open())
                {
                    for (var i = 0; i < 6; i++)
                    {
                        var p = new Point(hexRadius * Math.Sin(i * Math.PI / 3), hexRadius * Math.Cos(i * Math.PI / 3));
                        if (i == 0)
                        {
                            c.BeginFigure(p, true, true);
                        }
                        else
                        {
                            c.LineTo(p, true, false);
                        }
                    }
                }
                sg.Freeze();
    
                // 6角形を6個の正三角形に分けます
                for (var h1 = 0; h1 < 6; h1++)
                {
                    // 単位移動量の計算
                    var sx = Math.Sqrt(3) * hexRadius * Math.Cos(h1 * Math.PI / 3);
                    var sy = Math.Sqrt(3) * hexRadius * Math.Sin(h1 * Math.PI / 3);
                    var h2x = Math.Sqrt(3) * hexRadius * Math.Cos((h1 + 2) * Math.PI / 3);
                    var h2y = Math.Sqrt(3) * hexRadius * Math.Sin((h1 + 2) * Math.PI / 3);
    
                    // 彩度(半径方向)の繰り返し
                    for (var s = 0; s < 7; s++)
                    {
                        // 色相(角度方向)の繰り返し
                        for (var h2 = 0; h2 < s || (h1 == 0 && s == 0 && h2 == 0); h2++)
                        {
                            // RGBの計算
                            var rgb = Hsv3.ToRgb((h1 + (h2 / (double)s)) * Math.PI / 3, s / 6.0, 1);
                             
    
                            // 中心位置の計算
                            var cx = 128 + s * sx + h2 * h2x;
                            var cy = 128 + s * sy + h2 * h2y;
    
                            // 6角形の追加
                            var path = new Path();
                            path.Data = sg;
                            path.Fill = new SolidColorBrush() { Color = rgb };
                            Canvas.SetLeft(path, cx);
                            Canvas.SetTop(path, cy);
                            canvas.Children.Add(path);
                        }
                    }
                }
            }
            {
                var data = new byte[4 * 256 * 256];
                var i = 0;
                // 明度(縦方向)の繰り返し
                for (var v = 255; v >= 0; v--)
                {
                    // 色相(横方向)の繰り返し
                    for (var h = 0; h < 256; h++)
                    {
                        var rgb = Hsv3.ToRgb(h * 2 * Math.PI / 255, 1, v / 255.0);
                        data[i++] = rgb.B;
                        data[i++] = rgb.G;
                        data[i++] = rgb.R;
                        data[i++] = rgb.A;
                    }
                }
    
                var bmp = new WriteableBitmap(256, 256, 96, 96, PixelFormats.Bgra32, null);
                bmp.WritePixels(new Int32Rect(0, 0, 256, 256), data, 256 * 4, 0);
                bmp.Freeze();
    
                image.Source = bmp;
            }
        }
    
        private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // 対象Pathの取得
            var p = e.OriginalSource as Path;
            if (p == null)
            {
                return;
            }
            var scb = p.Fill as SolidColorBrush;
    
            if (scb == null)
            {
                return;
            }
    
            // 色の表示
            MessageBox.Show(scb.Color.ToString());
        }
        private void image_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // 位置計算
            var p = e.GetPosition(image);
            var h = (int)Math.Round(p.X);
            var v = (int)Math.Round(p.Y);
    
            if (0 <= h && h < 256 && 0 <= v && v < 256)
            {
                // WriteableBitmapから値を得るのは面倒なので直接計算します
                var rgb = Hsv3.ToRgb(h * 2 * Math.PI / 255, 1, 1 - v / 255.0);
    
                // 色の表示
                MessageBox.Show(rgb.ToString());
            }
        } 
    }
    
[/code]

といった感じでしょうか。  
![表示例](https://i.stack.imgur.com/EA4GO.jpg)


CC BY-SA 3.0
2015-01-27T04:51:15.280
5401
2015-01-28T10:21:38.190
2020-06-17T08:14:45.997
-1
5750
5396
answer