【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]