add Gravatar

This commit is contained in:
NaBian committed 2019-03-03 16:12:12 +08:00
1 parent 3a425d0058
commit 5d8e4e566a
35 files changed
+636 -93

No files matched your search

+42 -1
View File
@@ -1,4 +1,9 @@
using System.Windows;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using HandyControl.Data;
using HandyControl.Tools.Converter;
namespace HandyControl.Controls
{
@@ -10,5 +15,41 @@ namespace HandyControl.Controls
public static void SetCornerRadius(DependencyObject element, CornerRadius value) => element.SetValue(CornerRadiusProperty, value);
public static CornerRadius GetCornerRadius(DependencyObject element) => (CornerRadius)element.GetValue(CornerRadiusProperty);
public static readonly DependencyProperty CircularProperty = DependencyProperty.RegisterAttached(
"Circular", typeof(bool), typeof(BorderElement), new PropertyMetadata(ValueBoxes.FalseBox, OnCircularChanged));
private static void OnCircularChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Border border)
{
if ((bool)e.NewValue)
{
border.SetBinding(FrameworkElement.MinWidthProperty,
new Binding(FrameworkElement.ActualWidthProperty.Name) { Source = border });
border.SetBinding(FrameworkElement.MinHeightProperty,
new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
var binding = new MultiBinding
{
Converter = new BorderCircularConverter()
};
binding.Bindings.Add(new Binding(FrameworkElement.ActualWidthProperty.Name) {Source = border});
binding.Bindings.Add(new Binding(FrameworkElement.ActualHeightProperty.Name) { Source = border });
border.SetBinding(Border.CornerRadiusProperty, binding);
}
else
{
BindingOperations.ClearBinding(border, FrameworkElement.MinWidthProperty);
BindingOperations.ClearBinding(border, FrameworkElement.MinHeightProperty);
BindingOperations.ClearBinding(border, Border.CornerRadiusProperty);
}
}
}
public static void SetCircular(DependencyObject element, bool value)
=> element.SetValue(CircularProperty, value);
public static bool GetCircular(DependencyObject element)
=> (bool) element.GetValue(CircularProperty);
}
}
@@ -12,6 +12,6 @@ namespace HandyControl.Controls
=> element.SetValue(HighlightBrushProperty, value);
public static Brush GetHighlightBrush(DependencyObject element)
=> (Brush) element.GetValue(HighlightBrushProperty);
=> (Brush) element.GetValue(HighlightBrushProperty);
}
}
@@ -0,0 +1,7 @@
namespace HandyControl.Controls
{
public interface IGravatarGenerator
{
object GetGravatar(string id);
}
}
+9
View File
@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HandyControl.Controls
{
public class Badge : ContentControl
{
}
}
+9
View File
@@ -0,0 +1,9 @@
using System.Windows.Controls;
namespace HandyControl.Controls
{
public class Dialog : ContentControl
{
}
}
+51
View File
@@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using HandyControl.Tools;
namespace HandyControl.Controls
{
public class Gravatar : ContentControl
{
public static readonly DependencyProperty GeneratorProperty = DependencyProperty.Register(
"Generator", typeof(IGravatarGenerator), typeof(Gravatar), new PropertyMetadata(new GithubGravatarGenerator()));
public IGravatarGenerator Generator
{
get => (IGravatarGenerator) GetValue(GeneratorProperty);
set => SetValue(GeneratorProperty, value);
}
public static readonly DependencyProperty IdProperty = DependencyProperty.Register(
"Id", typeof(string), typeof(Gravatar), new PropertyMetadata(default(string), OnIdChanged));
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (Gravatar) d;
if (ctl.Source != null) return;
ctl.Content = ctl.Generator.GetGravatar((string)e.NewValue);
}
public string Id
{
get => (string) GetValue(IdProperty);
set => SetValue(IdProperty, value);
}
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register(
"Source", typeof(ImageSource), typeof(Gravatar), new PropertyMetadata(default(ImageSource), OnSourceChanged));
private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (Gravatar)d;
ctl.Background = new ImageBrush((ImageSource)e.NewValue);
}
public ImageSource Source
{
get => (ImageSource) GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
}
}
+15
View File
@@ -86,6 +86,7 @@
<Compile Include="Controls\Attach\PanelElement.cs" />
<Compile Include="Controls\Attach\VisualElement.cs" />
<Compile Include="Controls\Base\HeaderedSelectableItem.cs" />
<Compile Include="Controls\Base\IGravatarGenerator.cs" />
<Compile Include="Controls\Base\ISelectable.cs" />
<Compile Include="Controls\Base\RegularItemsControl.cs" />
<Compile Include="Controls\Base\SelectableItem.cs" />
@@ -108,10 +109,13 @@
<Compile Include="Controls\Attach\TitleElement.cs" />
<Compile Include="Controls\Button\ContextMenuButton.cs" />
<Compile Include="Controls\Button\ContextMenuToggleButton.cs" />
<Compile Include="Controls\Other\Badge.cs" />
<Compile Include="Controls\Other\Carousel.cs" />
<Compile Include="Controls\Cover\CoverView\CoverView.cs" />
<Compile Include="Controls\Other\ChatBubble.cs" />
<Compile Include="Controls\Other\Dialog.cs" />
<Compile Include="Controls\Other\GotoTop.cs" />
<Compile Include="Controls\Other\Gravatar.cs" />
<Compile Include="Controls\Transfer\Transfer.cs" />
<Compile Include="Controls\Transfer\TransferGroup.cs" />
<Compile Include="Controls\Transfer\TransferItem.cs" />
@@ -174,8 +178,11 @@
<Compile Include="Data\ResourceToken.cs" />
<Compile Include="Data\SystemVersionInfo.cs" />
<Compile Include="Tools\Converter\Boolean2StrConverter.cs" />
<Compile Include="Tools\Converter\BorderClipConverter.cs" />
<Compile Include="Tools\Converter\BorderCircularConverter.cs" />
<Compile Include="Tools\Converter\Int2StrConverter.cs" />
<Compile Include="Tools\Extension\EnumerableExtension.cs" />
<Compile Include="Tools\GithubGravatarGenerator.cs" />
<Compile Include="Tools\Helper\ColorHelper.cs" />
<Compile Include="Tools\GifImageAnimator.cs" />
<Compile Include="Data\GrowlInfo.cs" />
@@ -384,6 +391,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\Base\GravatarBaseStyle.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\Base\ProgressButtonBaseStyle.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -436,6 +447,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\Gravatar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Styles\GroupBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
+61 -80
View File
@@ -1,95 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
Microsoft ResX Schema
Version 1.3
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">1.3</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1">this is my long string</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
[base64 mime encoded serialized .NET Framework object]
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
[base64 mime encoded string representing a byte array form of the .NET Framework object]
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
@@ -108,13 +89,13 @@
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Confirm" xml:space="preserve">
<value>Confirm</value>
@@ -15,5 +15,7 @@
<converter:Object2BooleanConverter x:Key="Object2BooleanConverter"/>
<converter:Boolean2StrConverter x:Key="Boolean2StrConverter"/>
<converter:Int2StrConverter x:Key="Int2StrConverter"/>
<converter:BorderClipConverter x:Key="BorderClipConverter"/>
<converter:BorderCircularConverter x:Key="BorderCircularConverter"/>
</ResourceDictionary>
@@ -0,0 +1,22 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:HandyControl.Controls">
<Style x:Key="GravatarBaseStyle" TargetType="controls:Gravatar">
<Setter Property="Width" Value="72"/>
<Setter Property="Height" Value="72"/>
<Setter Property="Background" Value="{DynamicResource SecondaryRegionBrush}"/>
<Setter Property="controls:BorderElement.CornerRadius" Value="4"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Gravatar">
<Border ClipToBounds="True" CornerRadius="{Binding Path=(controls:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Margin="{TemplateBinding Padding}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
+22 -1
View File
@@ -1,6 +1,11 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:HandyControl.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Basic/Converters.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!--用于包裹一个区域-->
<Style x:Key="BorderRegionStyle" TargetType="Border">
<Setter Property="Padding" Value="10"/>
@@ -21,4 +26,20 @@
<Setter Property="Background" Value="{DynamicResource ThirdlyTextBrush}"/>
</Style>
<Style x:Key="BorderCircular" TargetType="Border">
<Setter Property="controls:BorderElement.Circular" Value="True"/>
</Style>
<Style x:Key="BorderClip" BasedOn="{StaticResource BorderCircular}" TargetType="Border">
<Setter Property="Clip">
<Setter.Value>
<MultiBinding Converter="{StaticResource BorderClipConverter}">
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
+29
View File
@@ -0,0 +1,29 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:HandyControl.Controls">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Base/GravatarBaseStyle.xaml"/>
<ResourceDictionary Source="Border.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style BasedOn="{StaticResource GravatarBaseStyle}" TargetType="controls:Gravatar"/>
<Style x:Key="GravatarCircle" BasedOn="{StaticResource GravatarBaseStyle}" TargetType="controls:Gravatar">
<Setter Property="Padding" Value="16"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Gravatar">
<Border Style="{StaticResource BorderClip}" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Margin="{TemplateBinding Padding}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="GravatarCircleImg" BasedOn="{StaticResource GravatarCircle}" TargetType="controls:Gravatar">
<Setter Property="Padding" Value="0"/>
</Style>
</ResourceDictionary>
+1
View File
@@ -58,6 +58,7 @@
<ResourceDictionary Source="Transfer.xaml"/>
<ResourceDictionary Source="ChatBubble.xaml"/>
<ResourceDictionary Source="GotoTop.xaml"/>
<ResourceDictionary Source="Gravatar.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
@@ -0,0 +1,31 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace HandyControl.Tools.Converter
{
public class BorderCircularConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is double width && values[1] is double height)
{
if (width < double.Epsilon || height < double.Epsilon)
{
return new CornerRadius();
}
var min = Math.Min(width, height);
return new CornerRadius(min/2);
}
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
@@ -0,0 +1,36 @@
//referenced from https://stackoverflow.com/a/5650367/9639378
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace HandyControl.Tools.Converter
{
public class BorderClipConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 3 && values[0] is double width && values[1] is double height && values[2] is CornerRadius radius)
{
if (width < double.Epsilon || height < double.Epsilon)
{
return Geometry.Empty;
}
var clip = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft);
clip.Freeze();
return clip;
}
return DependencyProperty.UnsetValue;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
@@ -0,0 +1,119 @@
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using HandyControl.Controls;
namespace HandyControl.Tools
{
public class GithubGravatarGenerator : IGravatarGenerator
{
private const int RenderDataMaxLength = 15;
public object GetGravatar(string id)
{
var hashcode = GetHashCode(id);
var renderData = GetRenderData(hashcode);
var renderBrush = GetRenderBrush(hashcode);
var geometryGroup = new GeometryGroup();
void AddRec(int i, int j, bool hidden = false)
{
var rec = new RectangleGeometry(new Rect(new Point(i, j), hidden ? new Size() : new Size(1, 1)));
geometryGroup.Children.Add(rec);
}
var index = 0;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 5; j++, index++)
{
AddRec(i, j, renderData[index] == 0);
}
}
for (int j = 0; j < 5; j++, index++)
{
AddRec(2, j, renderData[index] == 0);
}
index -= 10;
for (int i = 3; i < 5; i++)
{
for (int j = 0; j < 5; j++, index++)
{
AddRec(i, j, renderData[index] == 0);
}
index -= 10;
}
var path = new Path
{
Data = geometryGroup,
Fill = renderBrush,
VerticalAlignment = VerticalAlignment.Top
};
RenderOptions.SetEdgeMode(path, EdgeMode.Aliased);
return path;
}
private string GetHashCode(string id)
{
var md5 = MD5.Create();
var bytes = Encoding.ASCII.GetBytes(id);
var hash = md5.ComputeHash(bytes);
var stringBuilder = new StringBuilder();
foreach (var item in hash)
{
stringBuilder.Append(item.ToString("X2"));
}
return stringBuilder.ToString();
}
private int[] GetRenderData(string hashcode)
{
var arr = new int[RenderDataMaxLength];
for (int i = 0; i < RenderDataMaxLength; i++)
{
var c = hashcode[i];
var v = (int) c;
arr[i] = v % 2;
}
return arr;
}
private Brush GetRenderBrush(string hashcode)
{
var v = (double)int.Parse(hashcode.Substring(hashcode.Length - 7), NumberStyles.HexNumber);
var scale = v / 0xfffffff;
var color = Hsl2Rgb(scale);
return new SolidColorBrush(color);
}
//adapted from https://github.com/stewartlord/identicon.js/blob/4fad7cafec1b7a4d896015e084e861625ef5d64f/identicon.js#L110
private Color Hsl2Rgb(double h, double s = 0.7, double b = 0.5)
{
h *= 6;
var arr = new[]
{
b += s *= b < .5 ? b : 1 - b,
b - h % 1 * s * 2,
b -= s *= 2,
b,
b + h % 1 * s,
b + s
};
var hValue = (int) Math.Floor(h);
return Color.FromRgb((byte) (arr[hValue % 6] * 255), (byte) (arr[(hValue | 16) % 6] * 255),
(byte) (arr[(hValue | 8) % 6] * 255));
}
}
}