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公式如下:
Hsl转RGB公式如下:
其中涉及到有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的红色、蓝色、绿色的逻辑代码:
[code] 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 |