using ColorMine.ColorSpaces;
using Colourful;
using Colourful.Conversion;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using Tango.Core.Commands;
using Tango.SharedUI;
namespace Tango.PPC.Jobs.Models
{
public class VisualOffsetModel : ViewModel
{
public enum TypeColorCorrection
{
Lightness = 1,
Chroma = 2,
Hue = 3,
}
public class VisualLCHOffset : ViewModel
{
public TypeColorCorrection ColorType { get; set; }
public int Offset { get; set; }
public double L { get; set; }
public double C { get; set; }
private double _h;
public double H
{
get { return _h; }
set { _h = value;
RaisePropertyChangedAuto();
}
}
public SolidColorBrush ColorBrush
{
get
{
Lch lch = new Lch() { L = L, C = C, H = H };
IRgb RGB = lch.ToRgb();
return new SolidColorBrush() { Color = Color.FromRgb(System.Convert.ToByte(RGB.R), System.Convert.ToByte(RGB.G), System.Convert.ToByte(RGB.B)) };
}
}
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
RaisePropertyChangedAuto();
}
}
public VisualLCHOffset(TypeColorCorrection colorType, int offset)
{
ColorType = colorType;
Offset = offset;
}
public void Init(Lch lch)
{
L = lch.L;
C = lch.C;
H = lch.H;
RaisePropertyChanged( nameof(ColorBrush));
}
}
#region Property
private double _l;
public double L
{
get { return _l; }
set
{
if (_l != value)
{
_l = value;
RaisePropertyChangedAuto();
}
}
}
private double _a;
public double A
{
get { return _a; }
set
{
if (_a != value)
{
_a = value;
RaisePropertyChangedAuto();
}
}
}
private double _b;
public double B
{
get { return _b; }
set
{
if (_b != value)
{
_b = value;
RaisePropertyChangedAuto();
}
}
}
public double C { get; set; }
public double H { get; set; }
private double _sourcel;
public double SourceL
{
get { return _sourcel; }
set {
if(_sourcel != value)
{
_sourcel = value;
RaisePropertyChangedAuto();
//ManualCorrection(LightnessOffset, ChromaOffset, HueOffset);
}
}
}
private double _sourcea;
public double SourceA
{
get { return _sourcea; }
set
{
if (_sourcea != value)
{
_sourcea = value;
RaisePropertyChangedAuto();
//ManualCorrection(LightnessOffset, ChromaOffset, HueOffset);
}
}
}
private double _sourceb;
public double SourceB
{
get { return _sourceb; }
set
{
if (_sourceb != value)
{
_sourceb = value;
RaisePropertyChangedAuto();
//ManualCorrection(LightnessOffset, ChromaOffset, HueOffset);
}
}
}
private double _sourceh;
public double SourceH
{
get { return _sourceh; }
set
{
if (_sourceh != value)
{
_sourceh = value;
RaisePropertyChangedAuto();
}
}
}
private double _sourcec;
public double SourceC
{
get { return _sourcec; }
set
{
if (_sourcec != value)
{
_sourcec = value;
RaisePropertyChangedAuto();
}
}
}
public double LightnessOffset { get; set; }
public double ChromaOffset { get; set; }
public double HueOffset { get; set; }
public VisualLCHOffset MinLightness { get; set; }
public VisualLCHOffset MaxLightness { get; set; }
public VisualLCHOffset MinChroma { get; set; }
public VisualLCHOffset MaxChroma { get; set; }
public VisualLCHOffset MinHue { get; set; }
public VisualLCHOffset MaxHue { get; set; }
public SolidColorBrush SourceColorBrush
{
get
{
//Lch lch = new Lch() { L = L, C = C, H = H };
//IRgb RGB = lch.ToRgb();
Lab lab = new Lab(SourceL, SourceA, SourceB);
Rgb rgb = new Rgb(lab.ToRgb());
return new SolidColorBrush() { Color = Color.FromRgb((byte)rgb.R, (byte)rgb.G, (byte)rgb.B) };
}
}
public SolidColorBrush ManualColorBrush
{
get
{
//Lch lch = new Lch() { L = L, C = C, H = H };
//IRgb rgb = lch.ToRgb();
if(LightnessOffset == 0 && ChromaOffset == 0 && HueOffset == 0)
{
return SourceColorBrush;
}
Lab lab = new Lab(L, A, B);
Rgb rgb = new Rgb(lab.ToRgb());
return new SolidColorBrush() { Color = Color.FromRgb((byte)rgb.R, (byte)rgb.G, (byte)rgb.B) };
}
}
private bool _isOutOfGamut;
///
/// Gets or sets a value indicating whether this instance is out of gamut.
///
public bool IsOutOfGamut
{
get { return _isOutOfGamut; }
set
{
if (_isOutOfGamut != value)
{
_isOutOfGamut = value;
RaisePropertyChangedAuto();
}
}
}
#endregion
public VisualOffsetModel()
{
MinLightness = new VisualLCHOffset(TypeColorCorrection.Lightness, -1);
MaxLightness = new VisualLCHOffset(TypeColorCorrection.Lightness, 1);
MinChroma = new VisualLCHOffset(TypeColorCorrection.Chroma, -1);
MaxChroma = new VisualLCHOffset(TypeColorCorrection.Chroma, 1);
MinHue = new VisualLCHOffset(TypeColorCorrection.Hue, -1);
MaxHue = new VisualLCHOffset(TypeColorCorrection.Hue, 1);
IsOutOfGamut = false;
}
public void InitLAB(double l, double a, double b, double c, double h)
{
L = l;
A = a;
B = b;
C = c;
H = h;
LightnessOffset = ChromaOffset = HueOffset = 0;
_sourcel = l;
RaisePropertyChanged(nameof(SourceL));
_sourcea = a;
RaisePropertyChanged(nameof(SourceA));
_sourceb = b;
RaisePropertyChanged(nameof(SourceB));
_sourcec = c;
RaisePropertyChanged(nameof(SourceC));
_sourceh = h;
RaisePropertyChanged(nameof(SourceH));
UpdateManualColors();
}
public void ClearAll(double l, double a, double b)
{
LightnessOffset = 0;
ChromaOffset = 0;
HueOffset = 0;
LabColor labColor = new LabColor(l, a, b);
var converter = new ColourfulConverter { WhitePoint = Illuminants.D65 };
var last_LCH = converter.ToLChab(labColor);
SourceL = l;
SourceA = a;
SourceB = b;
SourceC = last_LCH.C;
SourceH = last_LCH.h;
L = l;
A = a;
B = b;
C = last_LCH.C;
H = last_LCH.h;
IsOutOfGamut = false;
}
public void UpdateSourceLAB(double l, double a, double b)
{
LabColor labColor = new LabColor(l, a, b);
var converter = new ColourfulConverter { WhitePoint = Illuminants.D65 };
var last_LCH = converter.ToLChab(labColor);
SourceL = l;
SourceA = a;
SourceB = b;
SourceC = last_LCH.C;
SourceH = last_LCH.h;
}
public void UpdateLAB(double l, double a, double b)
{
LabColor labColor = new LabColor(l, a, b);
var converter = new ColourfulConverter { WhitePoint = Illuminants.D65 };
var last_LCH = converter.ToLChab(labColor);
L = l;
A = a;
B = b;
C = last_LCH.C;
H = last_LCH.h;
}
public void UpdateManualColors()
{
Lch lch = Correction(SourceL, SourceC, SourceH,-6, 0, 0);
MinLightness.Init(lch);
lch = Correction(SourceL, SourceC, SourceH, 6, 0, 0);
MaxLightness.Init(lch);
lch = Correction(SourceL, SourceC, SourceH, 0, -6, 0);
MinChroma.Init(lch);
lch = Correction(SourceL, SourceC, SourceH, 0, 6, 0);
MaxChroma.Init(lch);
lch = Correction(SourceL, SourceC, SourceH, 0, 0, -6);
MinHue.Init(lch);
lch = Correction(SourceL, SourceC, SourceH, 0, 0, 6);
MaxHue.Init(lch);
RaisePropertyChanged(nameof(SourceColorBrush));
RaisePropertyChanged(nameof(ManualColorBrush));
}
///
/// Manuals the correction. During change lightnessOffset, chromaOffset or hueOffset in app caused to change LAB of visual correction.
///
/// The lightness offset.
/// The chroma offset.
/// The hue offset.
public void ManualCorrection( double lightnessOffset, double chromaOffset, double hueOffset)
{
Lch lch = Correction(SourceL, SourceC, SourceH, lightnessOffset, chromaOffset, hueOffset);
L = lch.L;
A = lch.C * Math.Cos(lch.H * (Math.PI / 180));
B = lch.C * Math.Sin(lch.H * (Math.PI / 180));
RaisePropertyChanged(nameof(SourceColorBrush));
RaisePropertyChanged(nameof(ManualColorBrush));
}
///
/// Calculate Lch on the specified lightness offset.
///
/// The lightness offset.
/// The chroma offset.
/// The hue offset.
///
public Lch Correction(double lch_l, double lch_c, double lch_h, double lightnessOffset, double chromaOffset, double hueOffset)
{
double L1 = lch_l;
double C1 = lch_c;
double H1 = lch_h;
if (H1 < 0)
H1 += 360;
double refX_C = C1;
///lightness
double SL = 0;
if (L1 < 16)
SL = 0.511;
else
SL = L1 * 0.040975 / (1 + 0.01765 * L1);
L1 += lightnessOffset * 2 * SL;
if (L1 > 100)
L1 = 100;
if (L1 < 0)
L1 = 0;
double SC = (0.638 + 0.0638 * refX_C / (1 + 0.0131 * refX_C));
C1 = C1 + (chromaOffset * SC);
// if (C1 > 128)
// C1 = 128;
if (C1 < 0)
C1 = 0;
//double h1 = H1;
//if (h1 < 0)
// h1 = h1 + 360;
double refX_CQ = Math.Pow(refX_C, 4);
double refX_H = H1;
double refX_F = Math.Sqrt(refX_CQ / (refX_CQ + 1900));
double refX_T = 0;
if ((refX_H > 164) & (refX_H < 345))
refX_T = 0.56 + Math.Abs(0.2 * Math.Cos(Math.PI * (refX_H + 168) / 180));
else if ((refX_H >= 345) | (refX_H <= 164))
refX_T = 0.36 + Math.Abs(0.4 * Math.Cos(Math.PI * (refX_H + 35) / 180));
//double refX_SC = (0.638 + 0.0638 * refX_C / (1 + 0.0131 * refX_C));
double refX_SH = SC * (refX_T * refX_F + 1 - refX_F);
if (C1 != 0)
{
var argum = 1 - (refX_SH * refX_SH * hueOffset * hueOffset / (2 * C1 * C1));
if (argum < -1)
argum = -1;
if (argum > 1)
argum = 1;
double tmp = (180 / Math.PI) * Math.Acos(argum); //degrees
if (hueOffset < 0)//?
tmp *= -1;
H1 += tmp;
}
Lch lch = new Lch() { L = L1, C = C1, H = H1 };
return lch;
}
#region Converter
#endregion
}
}