diff --git a/XFColorPickerControl/XFColorPickerControl/Controls/ColorPicker.xaml.cs b/XFColorPickerControl/XFColorPickerControl/Controls/ColorPicker.xaml.cs
index c0df5c6..64e8a4e 100644
--- a/XFColorPickerControl/XFColorPickerControl/Controls/ColorPicker.xaml.cs
+++ b/XFColorPickerControl/XFColorPickerControl/Controls/ColorPicker.xaml.cs
@@ -1,4 +1,6 @@
using System;
+using System.Diagnostics;
+using System.Linq;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;
@@ -27,10 +29,18 @@ public static readonly BindableProperty PickedColorProperty
public Color PickedColor
{
get { return (Color)GetValue(PickedColorProperty); }
- private set { SetValue(PickedColorProperty, value); }
+ set
+ {
+ if (!PickedColor.Equals(value))
+ {
+ SetValue(PickedColorProperty, value);
+ _lastTouchPoint = new SKPoint() { X = int.MaxValue, Y = int.MaxValue };
+ SkCanvasView.InvalidateSurface();
+ PickedColorChanged?.Invoke(this, PickedColor);
+ }
+ }
}
-
public static readonly BindableProperty GradientColorStyleProperty
= BindableProperty.Create(
nameof(GradientColorStyle),
@@ -48,7 +58,6 @@ public GradientColorStyle GradientColorStyle
set { SetValue(GradientColorStyleProperty, value); }
}
-
public static readonly BindableProperty ColorListProperty
= BindableProperty.Create(
nameof(ColorList),
@@ -75,7 +84,6 @@ public string[] ColorList
set { SetValue(ColorListProperty, value); }
}
-
public static readonly BindableProperty ColorListDirectionProperty
= BindableProperty.Create(
nameof(ColorListDirection),
@@ -113,7 +121,6 @@ public double PointerCircleDiameterUnits
set { SetValue(PointerCircleDiameterUnitsProperty, value); }
}
-
public static readonly BindableProperty PointerCircleBorderUnitsProperty
= BindableProperty.Create(
nameof(PointerCircleBorderUnits),
@@ -133,14 +140,26 @@ public double PointerCircleBorderUnits
set { SetValue(PointerCircleBorderUnitsProperty, value); }
}
-
- private SKPoint _lastTouchPoint = new SKPoint();
+ private SKPoint _lastTouchPoint = new SKPoint() { X = int.MaxValue, Y = int.MaxValue};
public ColorPicker()
{
InitializeComponent();
}
+ ///
+ /// I found this algorythm at https://stackoverflow.com/a/33782458/648919
+ /// It's simple enough but really effective!
+ ///
+ private double ColorDistance(SKColor c1, SKColor c2)
+ {
+ int rmean = (c1.Red + c2.Red) / 2;
+ int r = c1.Red - c2.Red;
+ int g = c1.Green - c2.Green;
+ int b = c1.Blue - c2.Blue;
+ return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
+ }
+
private void SkCanvasView_OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
var skImageInfo = e.Info;
@@ -199,7 +218,7 @@ private void SkCanvasView_OnPaintSurface(object sender, SKPaintSurfaceEventArgs
// Picking the Pixel Color values on the Touch Point
// Represent the color of the current Touch point
- SKColor touchPointColor;
+ SKColor touchPointColor = SKColors.White;
// Efficient and fast
// https://forums.xamarin.com/discussion/92899/read-a-pixel-info-from-a-canvas
@@ -209,6 +228,70 @@ private void SkCanvasView_OnPaintSurface(object sender, SKPaintSurfaceEventArgs
// get the pixel buffer for the bitmap
IntPtr dstpixels = bitmap.GetPixels();
+ // If color isn't set by touch, we need to find a color location on bitmap
+ if (_lastTouchPoint.X.Equals(int.MaxValue) && _lastTouchPoint.Y.Equals(int.MaxValue))
+ {
+ // read the surface into the bitmap
+ var res = skSurface.ReadPixels(skImageInfo, dstpixels, skImageInfo.RowBytes, 0, 0);
+ touchPointColor = PickedColor.ToSKColor();
+ var bpp = bitmap.BytesPerPixel;
+
+ // Get rid of SKBitmap getters
+ var pixels = new byte[bitmap.ByteCount];
+ bitmap.Bytes.CopyTo(pixels, 0);
+
+ // Let's try to find our color coordinates
+ var exactMatch = false;
+ var minDistance = double.MaxValue;
+
+ for (int y = 0; y < skCanvasHeight; y++)
+ {
+ for (int x = 0; x < skCanvasWidth; x++)
+ {
+ var c = new SKColor(pixels[(y * skCanvasWidth + x) * bpp + 2],
+ pixels[(y * skCanvasWidth + x) * bpp + 1],
+ pixels[(y * skCanvasWidth + x) * bpp + 0]);
+
+ // Check for exact color mach first
+ if (c.Equals(touchPointColor))
+ {
+ _lastTouchPoint.X = x;
+ _lastTouchPoint.Y = y;
+ exactMatch = true;
+ break;
+ }
+ else
+ {
+ var dist = ColorDistance(touchPointColor, c);
+ if (dist < 5)
+ {
+ _lastTouchPoint.X = x;
+ _lastTouchPoint.Y = y;
+ exactMatch = true;
+ break;
+ }
+ else if (minDistance > dist)
+ {
+ minDistance = dist;
+ _lastTouchPoint.X = x;
+ _lastTouchPoint.Y = y;
+
+#if false
+ // Small optimization based on RL tests; btw, it works
+ // fast enough even without these lines if (minDistance < 15)
+ {
+ exactMatch = true;
+ break;
+ }
+#endif
+ }
+ }
+ }
+
+ if (exactMatch) break;
+ }
+ }
+
// read the surface into the bitmap
skSurface.ReadPixels(skImageInfo,
dstpixels,
@@ -253,8 +336,7 @@ private void SkCanvasView_OnPaintSurface(object sender, SKPaintSurfaceEventArgs
}
// Set selected color
- PickedColor = touchPointColor.ToFormsColor();
- PickedColorChanged?.Invoke(this, PickedColor);
+ SetValue(PickedColorProperty, touchPointColor.ToFormsColor());
}
private void SkCanvasView_OnTouch(object sender, SKTouchEventArgs e)
@@ -272,6 +354,7 @@ private void SkCanvasView_OnTouch(object sender, SKTouchEventArgs e)
// update the Canvas as you wish
SkCanvasView.InvalidateSurface();
+ PickedColorChanged?.Invoke(this, PickedColor);
}
}
diff --git a/XFColorPickerControl/XFColorPickerControl/MainPage.xaml b/XFColorPickerControl/XFColorPickerControl/MainPage.xaml
index 18a0857..f3b043d 100644
--- a/XFColorPickerControl/XFColorPickerControl/MainPage.xaml
+++ b/XFColorPickerControl/XFColorPickerControl/MainPage.xaml
@@ -12,14 +12,12 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
- #ff0000
-
- #ffff00
-
- #00ff00
-
- #00ffff
-
- #0000ff
-
- #ff00ff
-
- #ff0000
-
-
diff --git a/XFColorPickerControl/XFColorPickerControl/MainPage.xaml.cs b/XFColorPickerControl/XFColorPickerControl/MainPage.xaml.cs
index 711bd1a..824be0b 100644
--- a/XFColorPickerControl/XFColorPickerControl/MainPage.xaml.cs
+++ b/XFColorPickerControl/XFColorPickerControl/MainPage.xaml.cs
@@ -1,10 +1,9 @@
using System;
-using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.Reflection;
using Xamarin.Forms;
+using XFColorPickerControl.Controls;
namespace XFColorPickerControl
{
@@ -13,9 +12,27 @@ namespace XFColorPickerControl
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
+ public class ColorItem
+ {
+ public string Name { get; set; }
+ public Color Value { get; set; }
+ }
public MainPage()
{
InitializeComponent();
+
+ var allColors = typeof(Color)
+ .GetRuntimeFields()
+ .Where(f => f.FieldType == typeof(Color))
+ .Select(prop => new ColorItem
+ {
+ Name = prop.Name,
+ Value = (Color)prop.GetValue(null)
+ })
+ .ToList();
+
+ SystemColorPicker.ItemsSource = allColors;
+ SystemColorPicker.SelectedIndex = 0;
}
private void ColorPicker_PickedColorChanged(object sender, Color colorPicked)
@@ -26,9 +43,30 @@ private void ColorPicker_PickedColorChanged(object sender, Color colorPicked)
ColorPickerHolderFrame.BackgroundColor = colorPicked;
if (colorPicked.Luminosity < 0.5)
- SelectedColorValueLabel.TextColor = Xamarin.Forms.Color.White;
+ SelectedColorValueLabel.TextColor = Color.White;
else
- SelectedColorValueLabel.TextColor = Xamarin.Forms.Color.SlateGray;
+ SelectedColorValueLabel.TextColor = Color.SlateGray;
}
- }
+
+ private void TestColorPicker_PickedColorChanged(object sender, Color e)
+ {
+ ColorPicker.PickedColor = e;
+ }
+
+ private void SystemColorPicker_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ var color = (SystemColorPicker.SelectedItem as ColorItem).Value;
+
+ ColorPicker.PickedColor = color;
+
+ // Use the selected color
+ SystemSelectedColorDisplayFrame.BackgroundColor = color;
+ SystemSelectedColorValueLabel.Text = color.ToHex();
+
+ if (color.Luminosity < 0.5)
+ SystemSelectedColorValueLabel.TextColor = Color.White;
+ else
+ SystemSelectedColorValueLabel.TextColor = Color.SlateGray;
+ }
+ }
}