Пример #1
0
        internal static Color InvertLightness(Color color)
        {
            // We unfortunately still need janky tuning of lightness and desaturation for good visibility, but
            // Oklab does give us a beautiful perceptual lightness scale (dark blue goes to light blue!) unlike
            // HSL, so awesome!

            Lab lab = ColorToOklab(color);

            #region Invert and global lightness boost

            float newL = lab.L < 0.5f
                ? ((1.0f - lab.L) + 0.10f).Clamp(0.0f, 1.0f)
                : (lab.L + 0.025f).Clamp(0.5f, 1.0f);

            lab = new Lab(newL, lab.a, lab.b);

            #endregion

            LCh lch = OklabToLCh(lab);

            #region Tweaks for specific hue ranges

            bool redDesaturated = false;

            switch (lch.h)
            {
            // Blue range
            case >= -1.901099f and <= -1.448842f:
            // Green range
            case >= 2.382358f and <= 2.880215f:
                lch = new LCh(lch.L.Clamp(0.7f, 1.0f), lch.C, lch.h);
                break;

            // Red range
            case >= -0.1025453f and <= 0.8673203f:
                lch = new LCh(lch.L.Clamp(0.6f, 1.0f), lch.C, lch.h);
                if (lch.L is >= 0.5f and <= 0.7f)
                {
                    lch            = new LCh(lch.L, (lch.C - 0.025f).Clamp(0, 1.0f), lch.h);
                    redDesaturated = true;
                }
                break;
            }

            #endregion

            // Slight global desaturation
            lab = LChToOklab(new LCh(lch.L, (lch.C - (redDesaturated ? 0.015f : 0.04f)).Clamp(0, 1.0f), lch.h));

            Color retColor = OklabToColor(lab);

            // For some reason RTF doesn't accept a \cfN if the color is 255 all around, it has to be 254 or
            // less... don't ask me
            if (retColor.R == 255 && retColor.G == 255 && retColor.B == 255)
            {
                retColor = Color.FromArgb(254, 254, 254);
            }

            return(retColor);
        }
Пример #2
0
        // Converts Lab to LCh (lightness, chroma, hue)
        private static Lab LChToOklab(LCh lch)
        {
            float a = (float)(lch.C * Math.Cos(lch.h));
            float b = (float)(lch.C * Math.Sin(lch.h));

            return(new Lab(lch.L, a, b));
        }
 public Checador()
 {
     InitializeComponent();
     _lCh             = new LCh();
     _eCh             = new ECh();
     _isEnablebinding = true;
     BindingCheck();
 }
 public Checador(ECh check)
 {
     _lCh = new LCh();
     _eCh = new ECh();
     _eCh = check;
     BindingCheckReload();
     _isEnablebinding = true;
     BindingCheck();
 }
Пример #5
0
        private static LCh LabToLCh(Lab lab)
        {
            LCh lch = new LCh();

            lch.l = lab.L;

            lch.c = Mathf.Sqrt(lab.A * lab.A + lab.B * lab.B);

            float h = Mathf.Rad2Deg * Mathf.Atan2(lab.B, lab.A);

            if (h < 0)
            {
                h += 360f;
            }
            else if (h >= 360)
            {
                h -= 360f;
            }
            lch.h = h;

            lch.alpha = lab.Alpha;

            return(lch);
        }
Пример #6
0
        /// <summary>
        /// Tips: 0.5f (really high contrast shapes, maybe 10+ bit monitors), 1f (high-quality monitors, indoors) 2.0f (else).
        /// </summary>
        public static float DeltaEmpfindung00(Lab lab1, Lab lab2, DeltaEWeightType weight = DeltaEWeightType.Graphic)
        {
            // Lab to LCh
            LCh lch1 = LabToLCh(lab1);
            LCh lch2 = LabToLCh(lab2);
            // Weight Factors
            DeltaEWeight weightFactors = Convert.ToBoolean((int)weight) ? weightGraphic : weightTextile;

            float CX = (lch1.c + lch2.c) / 2f;
            float GX = 0.5f * (1f - Mathf.Sqrt(Mathf.Pow(CX, 7f) / (Mathf.Pow(CX, 7f) + Mathf.Pow(25f, 7f))));

            float NN = (1f + GX) * lab1.A;

            lch1.c = Mathf.Sqrt(NN * NN + lab1.B * lab1.B);

            float hue1 = LabToHue(NN, lab1.B);

            NN     = (1f + GX) * lab2.A;
            lch2.c = Mathf.Sqrt(NN * NN + lab2.B * lab2.B);

            float hue2           = LabToHue(NN, lab2.B);
            float deltaLightness = lch2.l - lch1.l;
            float deltaChroma    = lch2.c - lch1.c;
            float deltaHue;

            if ((lch1.c * lch2.c) == 0f)
            {
                deltaHue = 0f;
            }
            else
            {
                NN = Mathf.Round((hue2 - hue1) * 1000f) / 1000f;
                if (Mathf.Abs(NN) <= 180f)
                {
                    deltaHue = hue2 - hue1;
                }
                else
                {
                    if (NN > 180f)
                    {
                        deltaHue = hue2 - hue1 - 360f;
                    }
                    else
                    {
                        deltaHue = hue2 - hue1 + 360f;
                    }
                }
            }
            deltaHue = 2f * Mathf.Sqrt(lch1.c * lch2.c) * Mathf.Sin((deltaHue / 2f) * Mathf.Deg2Rad);

            float lightnessAverage = (lch1.l + lch2.l) / 2f;
            float chromaAverage    = (lch1.c + lch2.c) / 2f;

            float hueNeutralsCompensation;

            if ((lch1.c * lch2.c) == 0f)
            {
                hueNeutralsCompensation = hue1 + hue2;
            }
            else
            {
                NN = Mathf.Abs(Mathf.Round((hue1 - hue2) * 1000f) / 1000f);
                if (NN > 180f)
                {
                    if ((hue2 + hue1) < 360f)
                    {
                        hueNeutralsCompensation = hue1 + hue2 + 360f;
                    }
                    else
                    {
                        hueNeutralsCompensation = hue1 + hue2 - 360f;
                    }
                }
                else
                {
                    hueNeutralsCompensation = hue1 + hue2;
                }
                hueNeutralsCompensation /= 2f;
            }

            float T = 1f
                      - 0.17f * Mathf.Cos((hueNeutralsCompensation - 30f) * Mathf.Deg2Rad)
                      + 0.24f * Mathf.Cos((2f * hueNeutralsCompensation) * Mathf.Deg2Rad)
                      + 0.32f * Mathf.Cos((3f * hueNeutralsCompensation + 6f) * Mathf.Deg2Rad)
                      - 0.20f * Mathf.Cos((4f * hueNeutralsCompensation - 63f) * Mathf.Deg2Rad);

            // Compensations
            float lightnessCompensation = 1f + ((0.015f * ((lightnessAverage - 50f) * (lightnessAverage - 50f))) / Mathf.Sqrt(20f + ((lightnessAverage - 50f) * (lightnessAverage - 50f))));
            float chromaCompensation    = 1f + weightFactors.kC * chromaAverage;
            float hueCompensation       = 1f + weightFactors.kH * chromaAverage * T;
            // Rotation
            float PH           = 30f * Mathf.Exp(-((hueNeutralsCompensation - 275f) / 25f) * ((hueNeutralsCompensation - 275f) / 25f));
            float RC           = 2f * Mathf.Sqrt(Mathf.Pow(chromaAverage, 7f) / (Mathf.Pow(chromaAverage, 7f) + Mathf.Pow(25f, 7f)));
            float rotationTerm = -Mathf.Sin((2f * PH) * Mathf.Deg2Rad) * RC;
            // Weights Constants
            float weightFactorChroma = 1f;
            float weightFactorHue    = 1f;

            // Corrections
            deltaLightness = deltaLightness / (weightFactors.kL * lightnessCompensation);
            deltaChroma    = deltaChroma / (weightFactorChroma * chromaCompensation);
            deltaHue       = deltaHue / (weightFactorHue * hueCompensation);

            float distance = Mathf.Sqrt(Mathf.Pow(deltaLightness, 2f) + Mathf.Pow(deltaChroma, 2f) + Mathf.Pow(deltaHue, 2f) + rotationTerm * deltaChroma * deltaHue);

            return(distance);
        }