Un changement de couleur ? l'HSL (ou TSL) à votre secours

HSL (ou TSL en français) représente une formulation des composantes d'une couleur, il s'agit de la teinte (Hue) exprimée en degré, la saturation (Saturation) souvent exprimée en pourcentage et la luminance (Luminosity), elle aussi exprimée en pourcentage. Pour de plus amples détails je vous suggère cet article de Wikipédia http://fr.wikipedia.org/wiki/Teinte_saturation_lumi%C3%A8re

Si je vous parle de la couleur et de ses composantes, c'est parce que grâce à ces 3 valeurs nous allons pouvoir modifier simplement une couleur et la régénérer pour obtenir un dégradé ou bien des couleurs plus pastels en partant d'une valeur de base. 

Comme vous le savez une couleur est représentée, en informatique, par les composantes Rouge, Verte et Bleu (on omettra volontairement la couche alpha représentant l'opacité de la couleur, qui n'est pas liée aux composantes HSL). Il nous faut donc obtenir ces composantes HSL d'une couleur, pour cela vive les mathématiques. Encore une fois merci Wikipédia http://fr.wikipedia.org/wiki/Codage_informatique_des_couleurs

Voici donc une petite classe sans prétention vous permettant d'obtenir une couleur HSL à partir d'une couleur RGB.


public class HslColor : INotifyPropertyChanged
    {

        #region fields

        private const double Scale = 240;

        #endregion

        #region properties

        private int _hue;

        public int Hue
        {
            get { return _hue; }
            set
            {
                _hue = value;
                OnPropertyChanged(() => Hue);
            }
        }

        private int _saturation;

        public int Saturation
        {
            get { return _saturation; }
            set
            {
                _saturation = value;
                OnPropertyChanged(() => Saturation);
            }
        }

        private int _Luminosity;

        public int Luminosity
        {
            get { return _Luminosity; }
            set
            {
                _Luminosity = value;
                OnPropertyChanged(() => Luminosity);
            }
        }

        #endregion

        public HslColor()
        {}

        public HslColor(int hue, int saturation, int luminosity)
        {
            Hue = hue;
            Saturation = saturation;
            Luminosity = luminosity;
        }

        public HslColor(Color color)
        {
            Hue = GetHue(color);
            Saturation = GetSaturation(color);
            Luminosity = GetLuminosity(color);
        }

        #region public

        /// <summary>
        /// permet de générer une couleur à partir d'une teinte, d'une saturation et d'une luminance
        /// </summary>
        /// <returns>Couleur format RGB</returns>
        public Color ToColorRgb()
        {
            if (Hue < 0)
            {
                Hue = 0;
            }

            if (Saturation < 0)
            {
                Saturation = 0;
            }

            if (Luminosity < 0)
            {
                Luminosity = 0;
            }

            const double vMax = 255;
            double To = (double)Hue / (double)60;

            double max = (double)vMax * ((double)Luminosity / (double)Scale);
            double delta = max * ((double)Saturation / (double)Scale);
            double min = max - delta;

            int ent = (int)Math.Truncate(To);

            double b = 0;
            double g = 0;
            double r = 0;

            switch (ent)
            {
                case 0:
                    b = min;
                    g = min + (To * delta);
                    r = max;
                    break;

                case 1:
                    b = min;
                    r = min + ((2 - To) * delta);
                    g = max;
                    break;

                case 2:
                    r = min;
                    b = min + ((To - 2) * delta);
                    g = max;
                    break;

                case 3:
                    r = min;
                    g = min + ((4 - To) * delta);
                    b = max;
                    break;

                case 4:
                    g = min;
                    r = min + ((To - 4) * delta);
                    b = max;
                    break;

                case 5:
                    g = min;
                    b = min + ((6 - To) * delta);
                    r = max;
                    break;
            }

            return new Color() { A = 255, B = Convert.ToByte(b), G = Convert.ToByte(g), R = Convert.ToByte(r) };
        }

        #endregion

        #region  private

        /// <summary>
        /// Obtient la valeur de teinte de la couleur
        /// </summary>
        /// <param name="color">Couleur voulue</param>
        /// <returns>Valeur de la teinte</returns>
        private static int GetHue(Color color)
        {
            double r = color.R;
            double g = color.G;
            double b = color.B;

            double max = Math.Max(r, Math.Max(g, b));
            double min = Math.Min(r, Math.Min(g, b));
            double delta = max - min;

            double To = 0;
            if (delta > 0)
            {
                if (r > g && r > b)
                {
                    To = ((g - b) / delta) % 6;
                }
                else
                {
                    if (g > b && g > r)
                    {
                        To = ((b - r) / delta) + 2;
                    }
                    else
                    {
                        if (b > r && b > g)
                        {
                            To = ((r - g) / delta) + 4;
                        }
                    }
                }
            }
            return Convert.ToInt32(Math.Round(60 * To));
        }

        /// <summary>
        /// Obtient la valeur de saturation de la couleur
        /// </summary>
        /// <param name="color">Couleur voulue</param>
        /// <returns>Valeur de la saturation</returns>
        private static int GetSaturation(Color color)
        {

            double r = color.R;
            double g = color.G;
            double b = color.B;

            if (r == g && r == b)
            {
                return 0;
            }

            double max = Math.Max(r, Math.Max(g, b));
            double min = Math.Min(r, Math.Min(g, b));
            double delta = max - min;

            return Convert.ToInt32(Math.Round(Scale * (delta / max)));
        }

        /// <summary>
        /// Obtient la valeur de luminance de la couleur
        /// </summary>
        /// <param name="color">Couleur voulue</param>
        /// <returns>Valeur de la luminance</returns>
        private static int GetLuminosity(Color color)
        {
            double r = color.R;
            double g = color.G;
            double b = color.B;

            if (r == 0 && g == 0 && b == 0)
            {
                return 0;
            }

            double max = Math.Max(r, Math.Max(g, b));
            double min = Math.Min(r, Math.Min(g, b));
            double delta = max - min;

            return Convert.ToInt32(Math.Round((Scale / 255) * max));
        }

        #endregion

        #region NotifyPropertyChanged

        //Inspiré de MVVMLight de Laurent Bugnion
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                var propertyName = GetPropertyName<T>(propertyExpression);
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
        {
            if (propertyExpression == null)
            {
                throw new ArgumentNullException("propertyExpression");
            }

            var body = propertyExpression.Body as MemberExpression;

            if (body == null)
            {
                throw new ArgumentException("Invalid argument", "propertyExpression");
            }

            var property = body.Member as PropertyInfo;

            if (property == null)
            {
                throw new ArgumentException("Argument is not a property", "propertyExpression");
            }

            return property.Name;
        }
        #endregion
    }

 

Afin de vous faciliter la tâche, je vous ai également préparé un petit Helper générant une couleur RGB en ajoutant une valeur de teinte, de saturation ou de luminance aux composantes d'une couleur de départ.


public static class HslColorHelper
    {
        private const int SMax = 240;
        private const int LMax = 240;
        private const int HMax = 360;

        /// <summary>
        /// Permet de générer une nouvelle couleur en modifiant les composantes HSL (teinte, saturation, luminance)
        /// </summary>
        /// <param name="color">Couleur de départ</param>
        /// <param name="hueChanged">valeur de modification de la teinte</param>
        /// <param name="saturationChanged">valeur de modification de la saturation</param>
        /// <param name="luminosityChanged">valeur de modification de la luminance</param>
        /// <returns>Couleur générée</returns>
        public static Color ChangedHslValueInColor(Color color, double hueChanged, double saturationChanged, double luminosityChanged)
        {
            return ChangedHslValue(color, hueChanged, saturationChanged, luminosityChanged);
        }

        /// <summary>
        /// Permet de générer une nouvelle couleur en modifiant les composantes HSL (teinte, saturation, luminance).
        /// Les valeurs de modification de la saturation et de la luminance étatn indiquées en pourcentage
        /// </summary>
        /// <param name="color">Couleur de départ</param>
        /// <param name="hueChanged">valeur de modification de la teinte</param>
        /// <param name="saturationPercentChanged">valeur (en pourcentage) de modification de la saturation</param>
        /// <param name="luminosityPercentChanged">valeur (en pourcentage) de modification de la luminance</param>
        /// <returns>Couleur générée</returns>
        public static Color ChangedHslValueInColorPercent(Color color, double hueChanged, double saturationPercentChanged, double luminosityPercentChanged)
        {
            //On récupére les valeurs de composantes traduite du pourcentage voulu
            double saturationChanged = (saturationPercentChanged * SMax) / 100;
            double luminosityChanged = (luminosityPercentChanged * LMax) / 100;

            return ChangedHslValue(color, hueChanged, saturationChanged, luminosityChanged);
        }

        #region  private

        private static Color ChangedHslValue(Color color, double hueChanged, double saturationChanged, double luminosityChanged)
        {
            //On récupérer une couleur au format HSL
            var hslColor = new HslColor(color);

            //On créé une nouvelle couleur
            var sat = Convert.ToInt32(Math.Round((hslColor.Saturation + saturationChanged) > SMax ? SMax : (hslColor.Saturation + saturationChanged)));
            var lum = Convert.ToInt32(Math.Round((hslColor.Luminosity + luminosityChanged) > LMax ? LMax : (hslColor.Luminosity + luminosityChanged)));
            var hue = Convert.ToInt32(Math.Round((hslColor.Hue + hueChanged) > HMax ? HMax : (hslColor.Hue + hueChanged)));
            return new HslColor(hue, sat, lum).ToColorRgb();
        }

        #endregion
    }

2 petites classes pour WinRT sans prétention, mais qui peuvent s'avérer utiles. Très facilement portable pour WPF en modifiant simplement le namespace de Color

Comme d'habitude, le code source d'une petite application de démonstration sur mon Skydrive



// coding with fun

1 commentaire

  1. image axsmhycnx

    FpAHNu <a href="http://vwzvkfomexfu.com/">vwzvkfomexfu</a>, [url=http://xrjahckqysww.com/]xrjahckqysww[/url], [link=http://gkqqbjdvgbhg.com/]gkqqbjdvgbhg[/link], http://zmvhhnohaivn.com/

Écrire un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec une *

Quelle est la troisième lettre du mot tbqeu ? :