2026-06-08 14:31:31 +07:00
|
|
|
|
namespace QWERTYkez.ExcelProcessor;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Определяет форматирование отдельного фрагмента (Run) внутри ячейки с богатым текстом.
|
|
|
|
|
|
/// Применяется только к тексту внутри <see cref="ICellText"/>.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public readonly struct RunFormat
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>Жирное начертание фрагмента.</summary>
|
|
|
|
|
|
public bool? IsBold { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Курсив фрагмента.</summary>
|
|
|
|
|
|
public bool? IsItalic { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Стиль подчёркивания (одинарное, двойное, волнистое и т.д.).</summary>
|
|
|
|
|
|
public UnderlineStyle? Underline { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Одинарное зачёркивание.</summary>
|
|
|
|
|
|
public bool? IsStrike { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Цвет текста фрагмента.</summary>
|
2026-06-19 15:06:40 +07:00
|
|
|
|
public System.Drawing.Color? Color { get; init; }
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>Размер шрифта фрагмента в пунктах.</summary>
|
|
|
|
|
|
public double? FontSize { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Имя шрифта фрагмента (например, "Calibri").</summary>
|
|
|
|
|
|
public string? FontFamily { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Вертикальное смещение (надстрочный или подстрочный).</summary>
|
|
|
|
|
|
public VerticalTextRunAlignment? Vertical { get; init; }
|
|
|
|
|
|
|
2026-06-08 14:31:31 +07:00
|
|
|
|
public static RunFormat? FromRunProperties(RunProperties rPr)
|
|
|
|
|
|
{
|
|
|
|
|
|
UnderlineStyle? underline;
|
|
|
|
|
|
if (rPr.GetFirstChild<Underline>()?.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<VerticalTextAlignment>()?.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<Bold>() != null,
|
|
|
|
|
|
IsItalic = rPr.GetFirstChild<Italic>() != null,
|
|
|
|
|
|
IsStrike = rPr.GetFirstChild<Strike>() != null,
|
|
|
|
|
|
// DoubleStrike в Excel не поддерживается, опускаем
|
|
|
|
|
|
|
|
|
|
|
|
Underline = underline,
|
2026-06-19 15:06:40 +07:00
|
|
|
|
Color = FromExcelColor(rPr.GetFirstChild<Color>()?.Rgb),
|
2026-06-08 14:31:31 +07:00
|
|
|
|
FontSize = rPr.GetFirstChild<FontSize>()?.Val?.Value,
|
|
|
|
|
|
FontFamily = rPr.GetFirstChild<RunFont>()?.Val,
|
|
|
|
|
|
Vertical = vertical
|
|
|
|
|
|
};
|
|
|
|
|
|
return fmt;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-05 15:58:03 +07:00
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
методы для извлечения OpenXmlElement или других более удобных типов
|
|
|
|
|
|
|
|
|
|
|
|
public bool TryExtract(out List<...> elements);
|
|
|
|
|
|
|
|
|
|
|
|
или
|
|
|
|
|
|
|
|
|
|
|
|
public bool TrySetFor(InlineString str)
|
|
|
|
|
|
|
|
|
|
|
|
или
|
|
|
|
|
|
|
|
|
|
|
|
public bool TrySetFor(ExcelRun str)
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Определяет стиль подчёркивания текста в ячейке или в части текста (Run).</summary>
|
|
|
|
|
|
public enum UnderlineStyle
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>Одинарное сплошное подчёркивание.</summary>
|
|
|
|
|
|
Single,
|
|
|
|
|
|
/// <summary>Двойное сплошное подчёркивание.</summary>
|
|
|
|
|
|
Double,
|
|
|
|
|
|
/// <summary>Одинарное подчёркивание, используемое для бухгалтерских форматов (нижняя граница ячейки).</summary>
|
|
|
|
|
|
SingleAccounting,
|
|
|
|
|
|
/// <summary>Двойное подчёркивание для бухгалтерских форматов.</summary>
|
|
|
|
|
|
DoubleAccounting
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Вертикальное смещение текста внутри прогона (Run) – надстрочный или подстрочный.</summary>
|
|
|
|
|
|
public enum VerticalTextRunAlignment
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>Надстрочный текст (верхний индекс).</summary>
|
|
|
|
|
|
Superscript,
|
|
|
|
|
|
/// <summary>Подстрочный текст (нижний индекс).</summary>
|
|
|
|
|
|
Subscript
|
|
|
|
|
|
}
|