玛卡巴卡的卡巴卡玛 发表于 2022-6-20 09:44:20

【Openxml】颜色变化属性计算

Openxml的颜色变化属性

目前Openxml存在颜色变化属性如下:
参数说明Hue色调(色相)HueModulate色调调制,百分比HueOffset色调偏移量,角度值Saturation饱和度SaturationModulation饱和度调制,百分比SaturationOffset饱和度偏移量Luminance亮度LuminanceModulation亮度调制,百分比LuminanceOffset亮度偏移量AlphaAlphaAlphaModulationAlpha 调制,百分比AlphaOffsetAlpha 偏移量Red红色RedModulation红色调制,百分比RedOffset红色偏移量Blue蓝色BlueModification蓝色调制BlueOffse蓝色偏移量,百分比Green绿色GreenModification绿色调制,百分比GreenOffset绿色偏移量Complement补充Gamma伽玛Gray灰色Inverse反函数Inverse Gamma反函数伽玛Shade底纹,百分比Tint底纹,百分比RGB和Hsl的相互转换

其中有关RGB和Hsl的相互转换的公式如下:
RGB转Hsl公式如下:
https://img2022.cnblogs.com/blog/1294271/202206/1294271-20220613123855546-456766327.jpg
Hsl转RGB公式如下:
https://img2022.cnblogs.com/blog/1294271/202206/1294271-20220613123909451-1997126868.jpg
其中涉及到有Hsl计算的有以下九个属性:

[*]Hue、HueModulate、HueOffset
[*]Saturation、SaturationModulation、SaturationOffset
[*]Luminance、LuminanceModulation、LuminanceOffset
那么我们开始写代码:
定义RGB的类:
    /// <summary>
    /// 用 A R G B 表示的颜色
    /// </summary>
    public class ARgbColor
    {
      /// <summary>
      /// 创建 A R G B 颜色
      /// </summary>
      public ARgbColor()
      {
      }

      /// <summary>
      /// 创建 A R G B 颜色
      /// </summary>
      /// <param name="a"></param>
      /// <param name="r"></param>
      /// <param name="g"></param>
      /// <param name="b"></param>
      public ARgbColor(byte a, byte r, byte g, byte b)
      {
            A = a;
            R = r;
            G = g;
            B = b;
      }

      /// <summary>
      /// 表示透明色
      /// </summary>
      public byte A { set; get; }

      /// <summary>
      /// 表示红色
      /// </summary>
      public byte R { set; get; }

      /// <summary>
      /// 表示绿色
      /// </summary>
      public byte G { set; get; }

      /// <summary>
      /// 表示蓝色
      /// </summary>
      public byte B { set; get; }

    }定义颜色变化相关类ColorTransform,并且定义RGB和Hsl的相互转换逻辑方法:
    /// <summary>
    ///   处理颜色之间的变换,调整,格式转换
    /// </summary>
    public static class ColorTransform
    {

      /// <summary>
      ///将<see cref="Color" />的数据转换为Hsl
      /// </summary>
      /// <param name="color"></param>
      /// <returns></returns>
      public static (Degree hue, Percentage sat, Percentage lum, byte alpha) ColorToHsl(Color color)
      {
            var max = System.Math.Max(color.R, System.Math.Max(color.G, color.B));
            var min = System.Math.Min(color.R, System.Math.Min(color.G, color.B));
            var delta = max - min;
            var l = Percentage.FromDouble((max + min) / 2.0 / 255.0);
            var h = Degree.FromDouble(0);
            var s = Percentage.Zero;

            if (delta > 0)
            {
                s = l < Percentage.FromDouble(0.5)
                  ? Percentage.FromDouble((max - min) * 1.0 / (max + min))
                  : Percentage.FromDouble((max - min) * 1.0 / (2 * 255 - max - min));

                if (max == color.R)
                {
                  h = Degree.FromDouble((0 + (color.G - color.B) * 1.0 / delta) * 60);
                }
                else if (max == color.G)
                {
                  h = Degree.FromDouble((2 + (color.B - color.R) * 1.0 / delta) * 60);
                }
                else
                {
                  h = Degree.FromDouble((4 + (color.R - color.G) * 1.0 / delta) * 60);
                }
            }

            return (h, s, l, color.A);
      }

    }

            /// <summary>
      ///   将Hsl的数据转换为<see cref="Color" />
      /// </summary>
      /// <param name="hue">色相</param>
      /// <param name="saturation">饱和度</param>
      /// <param name="lightness">亮度</param>
      /// <param name="a">透明度</param>
      /// <returns></returns>
      public static Color HslToColor(Degree hue, Percentage saturation, Percentage lightness, byte a = 0xFF)
      {
            var color = new Color { A = a };

            var hueValue = hue.DoubleValue;
            var saturationValue = saturation.DoubleValue;
            var lightnessValue = lightness.DoubleValue;

            var c = (1 - System.Math.Abs(2 * lightnessValue - 1)) * saturationValue;
            var x = c * (1 - System.Math.Abs((hueValue / 60) % 2 - 1));
            var m = lightnessValue - c / 2;

            var r = 0d;
            var g = 0d;
            var b = 0d;

            if (hueValue is >= 0 and < 60)
            {
                r = c;
                g = x;
                b = 0;
            }

            if (hueValue is >= 60 and < 120)
            {
                r = x;
                g = c;
                b = 0;
            }

            if (hueValue is >= 120 and < 180)
            {
                r = 0;
                g = c;
                b = x;
            }

            if (hueValue is >= 180 and < 240)
            {
                r = 0;
                g = x;
                b = c;
            }

            if (hueValue is >= 240 and < 300)
            {
                r = x;
                g = 0;
                b = c;
            }

            if (hueValue is >= 300 and < 360)
            {
                r = c;
                g = 0;
                b = x;
            }

            color.R = (byte) ((r + m) * 255);
            color.G = (byte) ((g + m) * 255);
            color.B = (byte) ((b + m) * 255);

            return color;
      }然后我们来写真正处理Openxml的Hsl相关属性逻辑:
       /// <summary>
      ///   将<see cref="RgbColorModelHex" />转换为<see cref="Color" />
      /// </summary>
      /// <param name="color"></param>
      /// <returns></returns>
      public static Color? ToColor(this RgbColorModelHex color)
      {
            if (color.Val is not null)
            {
                if (uint.TryParse(color.Val.Value, NumberStyles.HexNumber, null, out var result))
                {
                  var solidColor = result.HexToColor();
                  var modifiedColor = ColorTransform.AppendColorModify(solidColor, color.ChildElements);
                  return modifiedColor;
                }
            }

            return null;
      }


      private static Color HexToColor(this uint rgb)
      {
            var color = new Color();
            const int maxByte = 0xff;

            color.B = (byte) (rgb & maxByte);
            color.G = (byte) ((rgb >> 8) & maxByte);
            color.R = (byte) ((rgb >> 16) & maxByte);
            color.A = 0xFF;

            return color;
      }

      /// <summary>
      /// 给颜色叠加转换
      /// </summary>
      /// <param name="color"></param>
      /// <param name="list"></param>
      /// <returns></returns>
      public static Color AppendColorModify(ARgbColor color, OpenXmlElementList list)
      {
            var updatedColor = color;
            foreach (var element in list)
            {
                if (element is Hue hue)
                {
                  updatedColor = HandleHue(updatedColor, hue, null, null);
                  continue;
                }

                if (element is HueModulation hueModulation)
                {
                  updatedColor = HandleHue(updatedColor, null, hueModulation, null);
                  continue;
                }

                if (element is HueOffset hueOffset)
                {
                  updatedColor = HandleHue(updatedColor, null, null, hueOffset);
                  continue;
                }

                if (element is Saturation saturation)
                {
                  updatedColor = HandleSaturation(updatedColor, saturation, null, null);
                  continue;
                }

                if (element is SaturationModulation saturationModulation)
                {
                  updatedColor = HandleSaturation(updatedColor, null, saturationModulation, null);
                  continue;
                }

                if (element is SaturationOffset saturationOffset)
                {
                  updatedColor = HandleSaturation(updatedColor, null, null, saturationOffset);
                  continue;
                }

                if (element is Luminance luminance)
                {
                  updatedColor = HandleLuminance(updatedColor, luminance, null, null);
                  continue;
                }

                if (element is LuminanceModulation luminanceModulation)
                {
                  updatedColor = HandleLuminance(updatedColor, null, luminanceModulation, null);
                  continue;
                }

                if (element is LuminanceOffset luminanceOffset)
                {
                  updatedColor = HandleLuminance(updatedColor, null, null, luminanceOffset);
                  continue;
                }
            }


      private static Color HandleHue(Color color, Hue? hueElement, HueModulation? hueModElement,
            HueOffset? hueOffsetElement)
      {
            if (hueElement is null && hueModElement is null && hueOffsetElement is null)
            {
                return color;
            }

            var updatedColor = HandleHslCore(color, hueElement: hueElement, hueModElement: hueModElement, hueOffsetElement: hueOffsetElement);

            return updatedColor;
      }

      private static Color HandleSaturation(Color color, Saturation? satElement, SaturationModulation? satModElement,
            SaturationOffset? satOffsetElement)
      {
            if (satElement is null && satModElement is null && satOffsetElement is null)
            {
                return color;
            }

            var updatedColor = HandleHslCore(color, satElement: satElement, satModElement: satModElement, satOffsetElement: satOffsetElement);

            return updatedColor;
      }

      private static Color HandleLuminance(Color color, Luminance? lumElement, LuminanceModulation? lumModElement,
            LuminanceOffset? lumOffsetElement)
      {
            if (lumElement is null && lumModElement is null && lumOffsetElement is null)
            {
                return color;
            }

            var updatedColor = HandleHslCore(color, lumElement: lumElement, lumModElement: lumModElement, lumOffsetElement: lumOffsetElement);

            return updatedColor;
      }


      private static Color HandleHslCore(Color color,
            Hue? hueElement = null, HueModulation? hueModElement = null, HueOffset? hueOffsetElement = null,
            Saturation? satElement = null, SaturationModulation? satModElement = null, SaturationOffset? satOffsetElement = null,
            Luminance? lumElement = null, LuminanceModulation? lumModElement = null, LuminanceOffset? lumOffsetElement = null)
      {
            if (hueElement is null && hueModElement is null && hueOffsetElement is null
                && satElement is null && satModElement is null && satOffsetElement is null
                && lumElement is null && lumModElement is null && lumOffsetElement is null)
            {
                return color;
            }

            var (hue, sat, lum, alpha) = ColorToHsl(color);

            var hueElementVal = hueElement?.Val;
            var hueValue = hueElementVal is not null ? new Angle(hueElementVal).ToDegreeValue() : hue.DoubleValue;
            var satElementVal = satElement?.Val;
            var satValue = satElementVal is not null ? new Percentage(satElementVal).DoubleValue : sat.DoubleValue;
            var lumElementVal = lumElement?.Val;
            var lumValue = lumElementVal is not null ? new Percentage(lumElementVal).DoubleValue : lum.DoubleValue;

            var hueModElementVal = hueModElement?.Val;
            var hueModValue = hueModElementVal is not null && hueModElementVal.HasValue
                ? new Percentage(hueModElementVal)
                : Percentage.FromDouble(1);
            var satModElementVal = satModElement?.Val;
            var satModValue = satModElementVal is not null && satModElementVal.HasValue
                ? new Percentage(satModElementVal)
                : Percentage.FromDouble(1);
            var lumModElementVal = lumModElement?.Val;
            var lumModValue = lumModElementVal is not null && lumModElementVal.HasValue
                ? new Percentage(lumModElementVal)
                : Percentage.FromDouble(1);

            var hueOffsetVal = hueOffsetElement?.Val;
            var hueOffset = hueOffsetVal is not null && hueOffsetVal.HasValue
                ? new Angle(hueOffsetVal).ToDegreeValue()
                : new Angle(0).ToDegreeValue();
            var saturationOffsetVal = satOffsetElement?.Val;
            var saturationOffset = saturationOffsetVal is not null && saturationOffsetVal.HasValue
                ? new Percentage(saturationOffsetVal)
                : Percentage.Zero;
            var lumOffsetElementVal = lumOffsetElement?.Val;
            var lumOffset = lumOffsetElementVal is not null && lumOffsetElementVal.HasValue
                ? new Percentage(lumOffsetElementVal)
                : Percentage.Zero;

            var hueResult = hueValue * hueModValue.DoubleValue + hueOffset;
            hue = Degree.FromDouble(hueResult);

            var satResult = satValue * satModValue.DoubleValue + saturationOffset.DoubleValue;
            sat = Percentage.FromDouble(satResult);
            sat = sat > Percentage.FromDouble(1) ? Percentage.FromDouble(1) : sat;
            sat = sat < Percentage.Zero ? Percentage.Zero : sat;

            var lumResult = lumValue * lumModValue.DoubleValue + lumOffset.DoubleValue;
            lum = Percentage.FromDouble(lumResult);
            lum = lum > Percentage.FromDouble(1) ? Percentage.FromDouble(1) : lum;
            lum = lum < Percentage.Zero ? Percentage.Zero : lum;

            return HslToColor(hue, sat, lum, alpha);

      }处理RGB相关属性

涉及到RGB相关的Openxml属性如下:

[*]透明度:Alpha、AlphaModulation、AlphaOffset
[*]RGB的红色:Red、RedModulation、RedOffset
[*]RGB的蓝色:Blue、BlueModulation、BlueOffset
[*]RGB的绿色:Green、GreenModulation、GreenOffset
[*]RGB的反函数:Inverse
[*]RGB的补码: Complement
[*]RGB的伽玛校正和反伽玛矫正: Gamma、InverseGamma
[*]RGB的灰阶(灰度):Gray
处理透明度

以下为处理透明度的逻辑代码:

      private static Color HandleAlphaModify(Color color, Alpha? alphaElement, AlphaModulation? alphaModulation, AlphaOffset? alphaOffset)
      {
            if (alphaElement is null && alphaModulation is null && alphaOffset is null)
            {
                return color;
            }

            var alphaValue = alphaElement?.Val;
            var modulationVal = alphaModulation?.Val;
            var offsetVal = alphaOffset?.Val;

            var alpha = alphaValue is not null && alphaValue.HasValue
                ? new Percentage(alphaValue)
                : Percentage.FromDouble(1);

            var mod = modulationVal is not null && modulationVal.HasValue
                ? new Percentage(modulationVal)
                : Percentage.FromDouble(1);

            var off = offsetVal is not null && offsetVal.HasValue
                ? new Percentage(offsetVal)
                : Percentage.Zero;


            var alphaResult = alpha.DoubleValue * mod.DoubleValue + off.DoubleValue;
            color.A = (byte) (color.A * alphaResult);


            return color;
      }      处理RGB的红色、蓝色、绿色

以下为处理RGB的红色、蓝色、绿色的逻辑代码:
      private static Color HandleRgb(Color color, Red? redElement, Green? greenElement, Blue? blueElement)      {            if (redElement is null && greenElement is null && blueElement is null)            {                return color;            }            var updatedColor = HandleRgbCore(color, redElement: redElement, greenElement: greenElement,                blueElement: blueElement);            return updatedColor;      }      private static Color HandleRgbModulation(Color color, RedModulation? redModulationElement, GreenModulation? greenModulationElement, BlueModulation? blueModulationElement)      {            if (redModulationElement is null && greenModulationElement is null && blueModulationElement is null)            {                return color;            }            var updatedColor = HandleRgbCore(color, redModulationElement: redModulationElement,                greenModulationElement: greenModulationElement, blueModulationElement: blueModulationElement);            return updatedColor;      }      private static Color HandleRgbOffset(Color color, RedOffset? redOffsetElement, GreenOffset? greenOffsetElement, BlueOffset? blueOffsetElement)      {            if (redOffsetElement is null && blueOffsetElement is null && greenOffsetElement is null)            {                return color;            }            var updatedColor = HandleRgbCore(color, redOffsetElement: redOffsetElement,                greenOffsetElement: greenOffsetElement, blueOffsetElement: blueOffsetElement);            return updatedColor;      }         private static Color HandleRgbCore(Color color,            Red? redElement = null, Green? greenElement = null, Blue? blueElement = null,            RedModulation? redModulationElement = null, GreenModulation? greenModulationElement = null, BlueModulation? blueModulationElement = null,            RedOffset? redOffsetElement = null, GreenOffset? greenOffsetElement = null, BlueOffset? blueOffsetElement = null)      {            if (redElement is null && greenElement is null && blueElement is null                && redModulationElement is null && greenModulationElement is null && blueModulationElement is null                && redOffsetElement is null && greenOffsetElement is null && blueOffsetElement is null)            {                return color;            }            var updatedColor = color;            var redModulationValue = redModulationElement?.Val;            var redMod = redModulationValue is not null ? new Percentage(redModulationValue) : Percentage.FromDouble(1);            var greenModulationValue = greenModulationElement?.Val;            var greenMod = greenModulationValue is not null ? new Percentage(greenModulationValue) : Percentage.FromDouble(1);            var blueModulationValue = blueModulationElement?.Val;            var blueMod = blueModulationValue is not null ? new Percentage(blueModulationValue) : Percentage.FromDouble(1);            var redOffsetValue = redOffsetElement?.Val;            var redOffset = redOffsetValue is not null ? new Percentage(redOffsetValue) : Percentage.FromDouble(0);            var greenOffsetValue = greenOffsetElement?.Val;            var greenOffset = greenOffsetValue is not null ? new Percentage(greenOffsetValue) : Percentage.FromDouble(0);            var blueOffsetValue = blueOffsetElement?.Val;            var blueOffset = blueOffsetValue is not null ? new Percentage(blueOffsetValue) : Percentage.FromDouble(0);            var linearR = SRgbToLinearRgb(updatedColor.R / 255.0);            var linearG = SRgbToLinearRgb(updatedColor.G / 255.0);            var linearB = SRgbToLinearRgb(updatedColor.B / 255.0);            var redValue = redElement?.Val;            var red = redValue is not null ? new Percentage(redValue).DoubleValue : linearR;            var greenValue = greenElement?.Val;            var green = greenValue is not null ? new Percentage(greenValue).DoubleValue : linearG;            var blueValue = blueElement?.Val;            var blue = blueValue is not null ? new Percentage(blueValue).DoubleValue : linearB;            var redResult = red * redMod.DoubleValue + redOffset.DoubleValue;            var greenResult = green * greenMod.DoubleValue + greenOffset.DoubleValue;            var blueResult = blue * blueMod.DoubleValue + blueOffset.DoubleValue;            var r = redResult < 0 ? 0 : redResult > 1 ? 1 : redResult;            var g = greenResult < 0 ? 0 : greenResult > 1 ? 1 : greenResult;            var b = blueResult < 0 ? 0 : blueResult > 1 ? 1 : blueResult;            updatedColor.R = (byte) System.Math.Round(255 * LinearRgbToSRgb(r));            updatedColor.G = (byte) System.Math.Round(255 * LinearRgbToSRgb(g));            updatedColor.B = (byte) System.Math.Round(255 * LinearRgbToSRgb(b));            return updatedColor;      }      ///         /// https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29      ///         ///         ///         private static double SRgbToLinearRgb(double sRgb)      {            if (sRgb
页: [1]
查看完整版本: 【Openxml】颜色变化属性计算