RGB⇔HSVの変換をするクラス
アプリを作ってて色を扱っていると、RGBではなくHSV表色系で色を扱いたいと思うときが多々あります。
WPFで使うColor構造体はRGBで色を扱うので、HSVで扱うHSVColor構造体を作り、
Color⇔HSVColor構造体を相互に変換できるようにしてみました。
変換の式はこの辺を参考に
http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
特に込み入ったことはせずに、変換式をそのまま書いてます。
ちなみに、Color構造体にToHSV()という拡張メソッドを追加しています。
こうすることで、以下の二つのメソッドでRGB⇔HSVの相互変換をできるようにしてます。
RGB⇒HSV・・・Color.ToHSV()メソッド
HSV⇒RGB・・・HSVColor.ToRGB()メソッド
HSVColor.cs
using System; using System.Linq; using System.Windows.Media; namespace HSVConverter.Common { public struct HSVColor { public float H { get; set; } public float S { get; set; } public float V { get; set; } public static HSVColor FromHSV(float h, float s, float v) { return new HSVColor() { H = h, S = s, V = v }; } public override string ToString() { return string.Format("H:{0}, S:{1}, V:{2}", H, S, V); } public Color ToRGB() { int Hi = ((int)(H / 60.0)) % 6; float f = H / 60.0f - (int)(H / 60.0); float p = V * (1 - S); float q = V * (1 - f * S); float t = V * (1 - (1 - f) * S); switch (Hi) { case 0: return FromRGB(V, t, p); case 1: return FromRGB(q, V, p); case 2: return FromRGB(p, V, t); case 3: return FromRGB(p, q, V); case 4: return FromRGB(t, p, V); case 5: return FromRGB(V, p, q); } // ここには来ない throw new InvalidOperationException(); } private Color FromRGB(float fr, float fg, float fb) { fr *= 255; fg *= 255; fb *= 255; byte r = (byte)((fr < 0) ? 0 : (fr > 255) ? 255 : fr); byte g = (byte)((fg < 0) ? 0 : (fg > 255) ? 255 : fg); byte b = (byte)((fb < 0) ? 0 : (fb > 255) ? 255 : fb); return Color.FromRgb(r, g, b); } } public static class ColorExtension { public static HSVColor ToHSV(this Color c) { float r = c.R / 255.0f; float g = c.G / 255.0f; float b = c.B / 255.0f; var list = new float[] { r, g, b }; var max = list.Max(); var min = list.Min(); float h, s, v; if (max == min) h = 0; else if (max == r) h = (60 * (g - b) / (max - min) + 360) % 360; else if (max == g) h = 60 * (b - r) / (max - min) + 120; else h = 60 * (r - g) / (max - min) + 240; if (max == 0) s = 0; else s = (max - min) / max; v = max; return new HSVColor() { H = h, S = s, V = v }; } } }
動作チェック
一応、動作確認用に、以下のようなRGB/HSVの変換アプリを作ってみました。
MainWindow.xaml
<Window x:Class="HSVConverter.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" Title="MainWindow" Width="400" Height="300"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <Rectangle x:Name="rctColor" Width="100" Height="100" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="#FFF4F4F5" Stroke="Black" /> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition Width="Auto" /> <ColumnDefinition /> </Grid.ColumnDefinitions> <UniformGrid HorizontalAlignment="Center" VerticalAlignment="Top" Columns="2"> <TextBlock Margin="5" HorizontalAlignment="Right" Text="R:" /> <xctk:ByteUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding RGBColor.R}" /> <TextBlock Margin="5" HorizontalAlignment="Right" Text="G:" /> <xctk:ByteUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding RGBColor.G}" /> <TextBlock Margin="5" HorizontalAlignment="Right" Text="B:" /> <xctk:ByteUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding RGBColor.B}" /> </UniformGrid> <Button x:Name="btnRgbToHsv" Grid.Column="1" Width="75" Margin="10" VerticalAlignment="Top" Click="btnRgbToHsv_Click" Content="4" FontFamily="Marlett" FontSize="16" /> <Button x:Name="btnHsvToRgb" Grid.Column="1" Width="75" Margin="10,50,10,0" VerticalAlignment="Top" Click="btnHsvToRgb_Click" Content="3" FontFamily="Marlett" FontSize="16" /> <UniformGrid Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Top" Columns="2"> <TextBlock Margin="5" HorizontalAlignment="Right" Text="H:" /> <xctk:SingleUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding HSVColor.H}" /> <TextBlock Margin="5" HorizontalAlignment="Right" Text="S:" /> <xctk:SingleUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding HSVColor.S}" /> <TextBlock Margin="5" HorizontalAlignment="Right" Text="V:" /> <xctk:SingleUpDown Width="60" Height="23" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" Value="{Binding HSVColor.V}" /> </UniformGrid> </Grid> </Grid> </Window>
MainWindow.xaml.cs
using HSVConverter.Common; using System.Windows; using System.Windows.Media; namespace HSVConverter { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { /// <summary> /// 左側のカラムのRGB値を保持 /// </summary> public Color RGBColor { get { return (Color)GetValue(RGBColorProperty); } set { SetValue(RGBColorProperty, value); } } // Using a DependencyProperty as the backing store for RGBColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty RGBColorProperty = DependencyProperty.Register("RGBColor", typeof(Color), typeof(MainWindow), new PropertyMetadata(Colors.Red)); /// <summary> /// 右側カラムのHSV値を保持 /// </summary> public HSVColor HSVColor { get { return (HSVColor)GetValue(HSVColorProperty); } set { SetValue(HSVColorProperty, value); } } // Using a DependencyProperty as the backing store for HSVColor. This enables animation, styling, binding, etc... public static readonly DependencyProperty HSVColorProperty = DependencyProperty.Register("HSVColor", typeof(HSVColor), typeof(MainWindow), new PropertyMetadata(Colors.Red.ToHSV())); public MainWindow() { InitializeComponent(); this.DataContext = this; rctColor.Fill = new SolidColorBrush(RGBColor); } private void btnRgbToHsv_Click(object sender, RoutedEventArgs e) { HSVColor = RGBColor.ToHSV(); rctColor.Fill = new SolidColorBrush(RGBColor); } private void btnHsvToRgb_Click(object sender, RoutedEventArgs e) { RGBColor = HSVColor.ToRGB(); rctColor.Fill = new SolidColorBrush(RGBColor); } } }