namespace QWERTYkez.ExcelProcessor;
///
/// Определяет форматирование отдельного фрагмента (Run) внутри ячейки с богатым текстом.
/// Применяется только к тексту внутри .
///
public readonly struct RunFormat
{
/// Жирное начертание фрагмента.
public bool? IsBold { get; init; }
/// Курсив фрагмента.
public bool? IsItalic { get; init; }
/// Стиль подчёркивания (одинарное, двойное, волнистое и т.д.).
public UnderlineStyle? Underline { get; init; }
/// Одинарное зачёркивание.
public bool? IsStrike { get; init; }
/// Цвет текста фрагмента.
public System.Drawing.Color? Color { get; init; }
/// Размер шрифта фрагмента в пунктах.
public double? FontSize { get; init; }
/// Имя шрифта фрагмента (например, "Calibri").
public string? FontFamily { get; init; }
/// Вертикальное смещение (надстрочный или подстрочный).
public VerticalTextRunAlignment? Vertical { get; init; }
public static RunFormat? FromRunProperties(RunProperties rPr)
{
UnderlineStyle? underline;
if (rPr.GetFirstChild()?.Val?.Value is { } underlineVal)
{
if (underlineVal == UnderlineValues.Single)
{
underline = UnderlineStyle.Single;
}
else if (underlineVal == UnderlineValues.Double)
{
underline = UnderlineStyle.Double;
}
else if (underlineVal == UnderlineValues.SingleAccounting)
{
underline = UnderlineStyle.SingleAccounting;
}
else if (underlineVal == UnderlineValues.DoubleAccounting)
{
underline = UnderlineStyle.DoubleAccounting;
}
else underline = null!;
}
else underline = null!;
VerticalTextRunAlignment? vertical;
if (rPr.GetFirstChild()?.Val?.Value is { } verticalVal)
{
if (verticalVal == VerticalAlignmentRunValues.Superscript)
{
vertical = VerticalTextRunAlignment.Superscript;
}
else if (verticalVal == VerticalAlignmentRunValues.Subscript)
{
vertical = VerticalTextRunAlignment.Subscript;
}
else vertical = null!;
}
else vertical = null!;
if (rPr == null) return null;
var fmt = new RunFormat
{
IsBold = rPr.GetFirstChild() != null,
IsItalic = rPr.GetFirstChild() != null,
IsStrike = rPr.GetFirstChild() != null,
// DoubleStrike в Excel не поддерживается, опускаем
Underline = underline,
Color = FromExcelColor(rPr.GetFirstChild()?.Rgb),
FontSize = rPr.GetFirstChild()?.Val?.Value,
FontFamily = rPr.GetFirstChild()?.Val,
Vertical = vertical
};
return fmt;
}
static System.Drawing.Color? FromExcelColor(string? rgb)
{
if (string.IsNullOrWhiteSpace(rgb)) return null;
if (rgb!.Length == 6)
{
byte r = Convert.ToByte(rgb.Substring(0, 2), 16);
byte g = Convert.ToByte(rgb.Substring(2, 2), 16);
byte b = Convert.ToByte(rgb.Substring(4, 2), 16);
return System.Drawing.Color.FromArgb(r, g, b);
}
else if (rgb.Length == 8)
{
byte a = Convert.ToByte(rgb.Substring(0, 2), 16);
byte r = Convert.ToByte(rgb.Substring(2, 2), 16);
byte g = Convert.ToByte(rgb.Substring(4, 2), 16);
byte b = Convert.ToByte(rgb.Substring(6, 2), 16);
return System.Drawing.Color.FromArgb(a, r, g, b);
}
else return null;
}
public bool TryGetExcelColor(out Color excelColor)
{
if (Color is { } c)
{
excelColor = new Color() { Rgb = $"{c.R:X2}{c.G:X2}{c.B:X2}" };
return true;
}
else
{
excelColor = null!;
return false;
}
}
/*
методы для извлечения OpenXmlElement или других более удобных типов
public bool TryExtract(out List<...> elements);
или
public bool TrySetFor(InlineString str)
или
public bool TrySetFor(ExcelRun str)
*/
}
/// Определяет стиль подчёркивания текста в ячейке или в части текста (Run).
public enum UnderlineStyle
{
/// Одинарное сплошное подчёркивание.
Single,
/// Двойное сплошное подчёркивание.
Double,
/// Одинарное подчёркивание, используемое для бухгалтерских форматов (нижняя граница ячейки).
SingleAccounting,
/// Двойное подчёркивание для бухгалтерских форматов.
DoubleAccounting
}
/// Вертикальное смещение текста внутри прогона (Run) – надстрочный или подстрочный.
public enum VerticalTextRunAlignment
{
/// Надстрочный текст (верхний индекс).
Superscript,
/// Подстрочный текст (нижний индекс).
Subscript
}