// Keep this file CodeMaid organised and cleaned
using ClosedXML.Excel;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using Drawing = System.Drawing;
using X14 = DocumentFormat.OpenXml.Office2010.Excel;
namespace ClosedXML.Utils
{
internal static class OpenXmlHelper
{
#region Public Methods
/// <summary>
/// Convert color in ClosedXML representation to specified OpenXML type.
/// </summary>
/// <typeparam name="T">The descendant of <see cref="ColorType"/>.</typeparam>
/// <param name="openXMLColor">The existing instance of ColorType.</param>
/// <param name="xlColor">Color in ClosedXML format.</param>
/// <param name="isDifferential">Flag specifiying that the color should be saved in
/// differential format (affects the transparent color processing).</param>
/// <returns>The original color in OpenXML format.</returns>
public static T FromClosedXMLColor<T>(this ColorType openXMLColor, XLColor xlColor, bool isDifferential = false)
where T : ColorType
{
FillFromClosedXMLColor(openXMLColor, xlColor, isDifferential);
return (T)openXMLColor;
}
/// <summary>
/// Convert color in ClosedXML representation to specified OpenXML type.
/// </summary>
/// <typeparam name="T">The descendant of <see cref="X14.ColorType"/>.</typeparam>
/// <param name="openXMLColor">The existing instance of ColorType.</param>
/// <param name="xlColor">Color in ClosedXML format.</param>
/// <param name="isDifferential">Flag specifiying that the color should be saved in
/// differential format (affects the transparent color processing).</param>
/// <returns>The original color in OpenXML format.</returns>
public static T FromClosedXMLColor<T>(this X14.ColorType openXMLColor, XLColor xlColor, bool isDifferential = false)
where T : X14.ColorType
{
FillFromClosedXMLColor(openXMLColor, xlColor, isDifferential);
return (T)openXMLColor;
}
public static BooleanValue GetBooleanValue(bool value, bool defaultValue)
{
return value == defaultValue ? null : new BooleanValue(value);
}
public static bool GetBooleanValueAsBool(BooleanValue value, bool defaultValue)
{
return (value?.HasValue ?? false) ? value.Value : defaultValue;
}
/// <summary>
/// Convert color in OpenXML representation to ClosedXML type.
/// </summary>
/// <param name="openXMLColor">Color in OpenXML format.</param>
/// <param name="colorCache">The dictionary containing parsed colors to optimize performance.</param>
/// <returns>The color in ClosedXML format.</returns>
public static XLColor ToClosedXMLColor(this ColorType openXMLColor, IDictionary<string, Drawing.Color> colorCache = null)
{
return ConvertToClosedXMLColor(openXMLColor, colorCache);
}
/// <summary>
/// Convert color in OpenXML representation to ClosedXML type.
/// </summary>
/// <param name="openXMLColor">Color in OpenXML format.</param>
/// <param name="colorCache">The dictionary containing parsed colors to optimize performance.</param>
/// <returns>The color in ClosedXML format.</returns>
public static XLColor ToClosedXMLColor(this X14.ColorType openXMLColor, IDictionary<string, Drawing.Color> colorCache = null)
{
return ConvertToClosedXMLColor(openXMLColor, colorCache);
}
#endregion Public Methods
#region Private Methods
/// <summary>
/// Here we perform the actual convertion from OpenXML color to ClosedXML color.
/// </summary>
/// <param name="openXMLColor">OpenXML color. Must be either <see cref="ColorType"/> or <see cref="X14.ColorType"/>.
/// Since these types do not implement a common interface we use dynamic.</param>
/// <param name="colorCache">The dictionary containing parsed colors to optimize performance.</param>
/// <returns>The color in ClosedXML format.</returns>
private static XLColor ConvertToClosedXMLColor(dynamic openXMLColor, IDictionary<string, Drawing.Color> colorCache )
{
XLColor retVal = null;
if (openXMLColor != null)
{
if (openXMLColor.Rgb != null)
{
String htmlColor = "#" + openXMLColor.Rgb.Value;
Drawing.Color thisColor;
if (colorCache?.ContainsKey(htmlColor) ?? false)
{
thisColor = colorCache[htmlColor];
}
else
{
thisColor = ColorStringParser.ParseFromHtml(htmlColor);
colorCache?.Add(htmlColor, thisColor);
}
retVal = XLColor.FromColor(thisColor);
}
else if (openXMLColor.Indexed != null && openXMLColor.Indexed <= 64)
retVal = XLColor.FromIndex((Int32)openXMLColor.Indexed.Value);
else if (openXMLColor.Theme != null)
{
retVal = openXMLColor.Tint != null
? XLColor.FromTheme((XLThemeColor)openXMLColor.Theme.Value, openXMLColor.Tint.Value)
: XLColor.FromTheme((XLThemeColor)openXMLColor.Theme.Value);
}
}
return retVal ?? XLColor.NoColor;
}
/// <summary>
/// Initialize properties of the existing instance of the color in OpenXML format basing on properties of the color
/// in ClosedXML format.
/// </summary>
/// <param name="openXMLColor">OpenXML color. Must be either <see cref="ColorType"/> or <see cref="X14.ColorType"/>.
/// Since these types do not implement a common interface we use dynamic.</param>
/// <param name="xlColor">Color in ClosedXML format.</param>
/// <param name="isDifferential">Flag specifiying that the color should be saved in
/// differential format (affects the transparent color processing).</param>
private static void FillFromClosedXMLColor(dynamic openXMLColor, XLColor xlColor, bool isDifferential)
{
if (openXMLColor == null)
throw new ArgumentNullException(nameof(openXMLColor));
if (xlColor == null)
throw new ArgumentNullException(nameof(xlColor));
switch (xlColor.ColorType)
{
case XLColorType.Color:
openXMLColor.Rgb = xlColor.Color.ToHex();
break;
case XLColorType.Indexed:
// 64 is 'transparent' and should be ignored for differential formats
if (!isDifferential || xlColor.Indexed != 64)
openXMLColor.Indexed = (UInt32)xlColor.Indexed;
break;
case XLColorType.Theme:
openXMLColor.Theme = (UInt32)xlColor.ThemeColor;
if (xlColor.ThemeTint != 0)
openXMLColor.Tint = xlColor.ThemeTint;
break;
}
}
#endregion Private Methods
}
}