зеркало из https://github.com/mono/SkiaSharp.git
Added support for converting to/from HSV and HSL
This commit is contained in:
Родитель
a76f50b6cb
Коммит
555a626395
|
@ -82,6 +82,8 @@ namespace SkiaSharp
|
|||
}
|
||||
|
||||
public partial struct SKColor {
|
||||
private const float EPSILON = 0.001f;
|
||||
|
||||
public static readonly SKColor Empty;
|
||||
|
||||
private uint color;
|
||||
|
@ -101,6 +103,21 @@ namespace SkiaSharp
|
|||
color = (uint)(0xff000000u | (red << 16) | (green << 8) | blue);
|
||||
}
|
||||
|
||||
public SKColor WithRed (byte red)
|
||||
{
|
||||
return new SKColor (red, Green, Blue, Alpha);
|
||||
}
|
||||
|
||||
public SKColor WithGreen (byte green)
|
||||
{
|
||||
return new SKColor (Red, green, Blue, Alpha);
|
||||
}
|
||||
|
||||
public SKColor WithBlue (byte blue)
|
||||
{
|
||||
return new SKColor (Red, Green, blue, Alpha);
|
||||
}
|
||||
|
||||
public SKColor WithAlpha (byte alpha)
|
||||
{
|
||||
return new SKColor (Red, Green, Blue, alpha);
|
||||
|
@ -111,6 +128,214 @@ namespace SkiaSharp
|
|||
public byte Green => (byte)((color >> 8) & 0xff);
|
||||
public byte Blue => (byte)((color) & 0xff);
|
||||
|
||||
public static SKColor FromHsl (float h, float s, float l, byte a = 255)
|
||||
{
|
||||
// convert from percentages
|
||||
h = h / 360f;
|
||||
s = s / 100f;
|
||||
l = l / 100f;
|
||||
|
||||
// RGB results from 0 to 255
|
||||
var r = l * 255f;
|
||||
var g = l * 255f;
|
||||
var b = l * 255f;
|
||||
|
||||
// HSL from 0 to 1
|
||||
if (Math.Abs (s) > EPSILON)
|
||||
{
|
||||
float v2;
|
||||
if (l < 0.5f)
|
||||
v2 = l * (1f + s);
|
||||
else
|
||||
v2 = (l + s) - (s * l);
|
||||
|
||||
var v1 = 2f * l - v2;
|
||||
|
||||
r = 255 * HueToRgb (v1, v2, h + (1f / 3f));
|
||||
g = 255 * HueToRgb (v1, v2, h);
|
||||
b = 255 * HueToRgb (v1, v2, h - (1f / 3f));
|
||||
}
|
||||
|
||||
return new SKColor ((byte)r, (byte)g, (byte)b, a);
|
||||
}
|
||||
|
||||
private static float HueToRgb (float v1, float v2, float vH)
|
||||
{
|
||||
if (vH < 0f)
|
||||
vH += 1f;
|
||||
if (vH > 1f)
|
||||
vH -= 1f;
|
||||
|
||||
if ((6f * vH) < 1f)
|
||||
return (v1 + (v2 - v1) * 6f * vH);
|
||||
if ((2f * vH) < 1f)
|
||||
return (v2);
|
||||
if ((3f * vH) < 2f)
|
||||
return (v1 + (v2 - v1) * ((2f / 3f) - vH) * 6f);
|
||||
return (v1);
|
||||
}
|
||||
|
||||
public static SKColor FromHsv(float h, float s, float v, byte a = 255)
|
||||
{
|
||||
// convert from percentages
|
||||
h = h / 360f;
|
||||
s = s / 100f;
|
||||
v = v / 100f;
|
||||
|
||||
// RGB results from 0 to 255
|
||||
var r = v;
|
||||
var g = v;
|
||||
var b = v;
|
||||
|
||||
// HSL from 0 to 1
|
||||
if (Math.Abs (s) > EPSILON)
|
||||
{
|
||||
h = h * 6f;
|
||||
if (Math.Abs (h - 6f) < EPSILON)
|
||||
h = 0f; // H must be < 1
|
||||
|
||||
var hInt = (int)h;
|
||||
var v1 = v * (1f - s);
|
||||
var v2 = v * (1f - s * (h - hInt));
|
||||
var v3 = v * (1f - s * (1f - (h - hInt)));
|
||||
|
||||
if (hInt == 0)
|
||||
{
|
||||
r = v;
|
||||
g = v3;
|
||||
b = v1;
|
||||
}
|
||||
else if (hInt == 1)
|
||||
{
|
||||
r = v2;
|
||||
g = v;
|
||||
b = v1;
|
||||
}
|
||||
else if (hInt == 2)
|
||||
{
|
||||
r = v1;
|
||||
g = v;
|
||||
b = v3;
|
||||
}
|
||||
else if (hInt == 3)
|
||||
{
|
||||
r = v1;
|
||||
g = v2;
|
||||
b = v;
|
||||
}
|
||||
else if (hInt == 4)
|
||||
{
|
||||
r = v3;
|
||||
g = v1;
|
||||
b = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
r = v;
|
||||
g = v1;
|
||||
b = v2;
|
||||
}
|
||||
}
|
||||
|
||||
// RGB results from 0 to 255
|
||||
r = r * 255f;
|
||||
g = g * 255f;
|
||||
b = b * 255f;
|
||||
|
||||
return new SKColor ((byte)r, (byte)g, (byte)b, a);
|
||||
}
|
||||
|
||||
public void ToHsl (out float h, out float s, out float l)
|
||||
{
|
||||
// RGB from 0 to 255
|
||||
var r = (Red / 255f);
|
||||
var g = (Green / 255f);
|
||||
var b = (Blue / 255f);
|
||||
|
||||
var min = Math.Min (Math.Min (r, g), b); // min value of RGB
|
||||
var max = Math.Max (Math.Max (r, g), b); // max value of RGB
|
||||
var delta = max - min; // delta RGB value
|
||||
|
||||
// default to a gray, no chroma...
|
||||
h = 0f;
|
||||
s = 0f;
|
||||
l = (max + min) / 2f;
|
||||
|
||||
// chromatic data...
|
||||
if (Math.Abs (delta) > EPSILON)
|
||||
{
|
||||
if (l < 0.5f)
|
||||
s = delta / (max + min);
|
||||
else
|
||||
s = delta / (2f - max - min);
|
||||
|
||||
var deltaR = (((max - r) / 6f) + (delta / 2f)) / delta;
|
||||
var deltaG = (((max - g) / 6f) + (delta / 2f)) / delta;
|
||||
var deltaB = (((max - b) / 6f) + (delta / 2f)) / delta;
|
||||
|
||||
if (Math.Abs (r - max) < EPSILON) // r == max
|
||||
h = deltaB - deltaG;
|
||||
else if (Math.Abs (g - max) < EPSILON) // g == max
|
||||
h = (1f / 3f) + deltaR - deltaB;
|
||||
else // b == max
|
||||
h = (2f / 3f) + deltaG - deltaR;
|
||||
|
||||
if (h < 0f)
|
||||
h += 1f;
|
||||
if (h > 1f)
|
||||
h -= 1f;
|
||||
}
|
||||
|
||||
// convert to percentages
|
||||
h = h * 360f;
|
||||
s = s * 100f;
|
||||
l = l * 100f;
|
||||
}
|
||||
|
||||
public void ToHsv (out float h, out float s, out float v)
|
||||
{
|
||||
// RGB from 0 to 255
|
||||
var r = (Red / 255f);
|
||||
var g = (Green / 255f);
|
||||
var b = (Blue / 255f);
|
||||
|
||||
var min = Math.Min (Math.Min (r, g), b); // min value of RGB
|
||||
var max = Math.Max (Math.Max (r, g), b); // max value of RGB
|
||||
var delta = max - min; // delta RGB value
|
||||
|
||||
// default to a gray, no chroma...
|
||||
h = 0;
|
||||
s = 0;
|
||||
v = max;
|
||||
|
||||
// chromatic data...
|
||||
if (Math.Abs (delta) > EPSILON)
|
||||
{
|
||||
s = delta / max;
|
||||
|
||||
var deltaR = (((max - r) / 6f) + (delta / 2f)) / delta;
|
||||
var deltaG = (((max - g) / 6f) + (delta / 2f)) / delta;
|
||||
var deltaB = (((max - b) / 6f) + (delta / 2f)) / delta;
|
||||
|
||||
if (Math.Abs (r - max) < EPSILON) // r == max
|
||||
h = deltaB - deltaG;
|
||||
else if (Math.Abs (g - max) < EPSILON) // g == max
|
||||
h = (1f / 3f) + deltaR - deltaB;
|
||||
else // b == max
|
||||
h = (2f / 3f) + deltaG - deltaR;
|
||||
|
||||
if (h < 0f)
|
||||
h += 1f;
|
||||
if (h > 1f)
|
||||
h -= 1f;
|
||||
}
|
||||
|
||||
// convert to percentages
|
||||
h = h * 360f;
|
||||
s = s * 100f;
|
||||
v = v * 100f;
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return string.Format (CultureInfo.InvariantCulture, "#{0:x2}{1:x2}{2:x2}{3:x2}", Alpha, Red, Green, Blue);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Xamarin.iOS" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Xamarin.TVOS" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
|
|
|
@ -106,6 +106,9 @@
|
|||
<Compile Include="..\Tests\SKPathTest.cs" >
|
||||
<Link>SKPathTest.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Tests\SKColorTest.cs" >
|
||||
<Link>SKColorTest.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\samples\SharedDemo\content-font.ttf">
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
|
||||
using SKOtherColor = System.Tuple<float, float, float>;
|
||||
using ToOtherColor = System.Tuple<SkiaSharp.SKColor, System.Tuple<float, float, float>, string>;
|
||||
|
||||
namespace SkiaSharp.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SKColorTest : SKTest
|
||||
{
|
||||
private const float EPSILON = 0.01f;
|
||||
|
||||
[Test]
|
||||
public void ColorWithComponent()
|
||||
{
|
||||
var color = new SKColor();
|
||||
Assert.AreEqual(0, color.Red);
|
||||
Assert.AreEqual(0, color.Green);
|
||||
Assert.AreEqual(0, color.Blue);
|
||||
Assert.AreEqual(0, color.Alpha);
|
||||
|
||||
var red = color.WithRed(255);
|
||||
Assert.AreEqual(255, red.Red);
|
||||
Assert.AreEqual(0, red.Green);
|
||||
Assert.AreEqual(0, red.Blue);
|
||||
Assert.AreEqual(0, red.Alpha);
|
||||
|
||||
var green = color.WithGreen(255);
|
||||
Assert.AreEqual(0, green.Red);
|
||||
Assert.AreEqual(255, green.Green);
|
||||
Assert.AreEqual(0, green.Blue);
|
||||
Assert.AreEqual(0, green.Alpha);
|
||||
|
||||
var blue = color.WithBlue(255);
|
||||
Assert.AreEqual(0, blue.Red);
|
||||
Assert.AreEqual(0, blue.Green);
|
||||
Assert.AreEqual(255, blue.Blue);
|
||||
Assert.AreEqual(0, blue.Alpha);
|
||||
|
||||
var alpha = color.WithAlpha(255);
|
||||
Assert.AreEqual(0, alpha.Red);
|
||||
Assert.AreEqual(0, alpha.Green);
|
||||
Assert.AreEqual(0, alpha.Blue);
|
||||
Assert.AreEqual(255, alpha.Alpha);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ColorRgbToHsl()
|
||||
{
|
||||
var tuples = new List<ToOtherColor> {
|
||||
new ToOtherColor(new SKColor(000, 000, 000), new SKOtherColor(000f, 000.0f, 000.0f), "Black"),
|
||||
new ToOtherColor(new SKColor(255, 000, 000), new SKOtherColor(000f, 100.0f, 050.0f), "Red"),
|
||||
new ToOtherColor(new SKColor(255, 255, 000), new SKOtherColor(060f, 100.0f, 050.0f), "Yellow"),
|
||||
new ToOtherColor(new SKColor(255, 255, 255), new SKOtherColor(000f, 000.0f, 100.0f), "White"),
|
||||
new ToOtherColor(new SKColor(128, 128, 128), new SKOtherColor(000f, 000.0f, 050.2f), "Gray"),
|
||||
new ToOtherColor(new SKColor(128, 128, 000), new SKOtherColor(060f, 100.0f, 025.1f), "Olive"),
|
||||
new ToOtherColor(new SKColor(000, 128, 000), new SKOtherColor(120f, 100.0f, 025.1f), "Green"),
|
||||
new ToOtherColor(new SKColor(000, 000, 128), new SKOtherColor(240f, 100.0f, 025.1f), "Navy"),
|
||||
};
|
||||
|
||||
foreach (var item in tuples)
|
||||
{
|
||||
// values
|
||||
SKColor rgb = item.Item1;
|
||||
SKOtherColor other = item.Item2;
|
||||
|
||||
// to HSL
|
||||
float h, s, l;
|
||||
rgb.ToHsl(out h, out s, out l);
|
||||
|
||||
Assert.AreEqual(other.Item1, h, EPSILON, item.Item3 + " H");
|
||||
Assert.AreEqual(other.Item2, s, EPSILON, item.Item3 + " S");
|
||||
Assert.AreEqual(other.Item3, l, EPSILON, item.Item3 + " L");
|
||||
|
||||
// to RGB
|
||||
SKColor back = SKColor.FromHsl(other.Item1, other.Item2, other.Item3);
|
||||
|
||||
Assert.AreEqual(rgb.Red, back.Red, item.Item3 + " R");
|
||||
Assert.AreEqual(rgb.Green, back.Green, item.Item3 + " G");
|
||||
Assert.AreEqual(rgb.Blue, back.Blue, item.Item3 + " B");
|
||||
Assert.AreEqual(rgb.Alpha, back.Alpha, item.Item3 + " A");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ColorRgbToHsv()
|
||||
{
|
||||
var tuples = new List<ToOtherColor> {
|
||||
new ToOtherColor(new SKColor(000, 000, 000), new SKOtherColor(000f, 000.0f, 000.0f), "Black"),
|
||||
new ToOtherColor(new SKColor(255, 000, 000), new SKOtherColor(000f, 100.0f, 100.0f), "Red"),
|
||||
new ToOtherColor(new SKColor(255, 255, 000), new SKOtherColor(060f, 100.0f, 100.0f), "Yellow"),
|
||||
new ToOtherColor(new SKColor(255, 255, 255), new SKOtherColor(000f, 000.0f, 100.0f), "White"),
|
||||
new ToOtherColor(new SKColor(128, 128, 128), new SKOtherColor(000f, 000.0f, 050.2f), "Gray"),
|
||||
new ToOtherColor(new SKColor(128, 128, 000), new SKOtherColor(060f, 100.0f, 050.2f), "Olive"),
|
||||
new ToOtherColor(new SKColor(000, 128, 000), new SKOtherColor(120f, 100.0f, 050.2f), "Green"),
|
||||
new ToOtherColor(new SKColor(000, 000, 128), new SKOtherColor(240f, 100.0f, 050.2f), "Navy"),
|
||||
};
|
||||
|
||||
foreach (var item in tuples)
|
||||
{
|
||||
// values
|
||||
SKColor rgb = item.Item1;
|
||||
SKOtherColor other = item.Item2;
|
||||
|
||||
// to HSV
|
||||
float h, s, v;
|
||||
rgb.ToHsv(out h, out s, out v);
|
||||
|
||||
Assert.AreEqual(other.Item1, h, EPSILON, item.Item3 + " H");
|
||||
Assert.AreEqual(other.Item2, s, EPSILON, item.Item3 + " S");
|
||||
Assert.AreEqual(other.Item3, v, EPSILON, item.Item3 + " V");
|
||||
|
||||
// to RGB
|
||||
SKColor back = SKColor.FromHsv(other.Item1, other.Item2, other.Item3);
|
||||
|
||||
Assert.AreEqual(rgb.Red, back.Red, item.Item3 + " R");
|
||||
Assert.AreEqual(rgb.Green, back.Green, item.Item3 + " G");
|
||||
Assert.AreEqual(rgb.Blue, back.Blue, item.Item3 + " B");
|
||||
Assert.AreEqual(rgb.Alpha, back.Alpha, item.Item3 + " A");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче