2026-06-08 14:31:31 +07:00
|
|
|
|
namespace QWERTYkez.ExcelProcessor;
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Определяет шрифтовое оформление всей ячейки: размер, семейство, цвет, начертание.
|
|
|
|
|
|
/// Все свойства опциональны.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public readonly struct CellFont : IEquatable<CellFont>
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>Размер шрифта в пунктах (например, 11).</summary>
|
|
|
|
|
|
public double? FontSize { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Имя семейства шрифта (например, "Calibri", "Arial").</summary>
|
|
|
|
|
|
public string? FontFamily { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Цвет текста.</summary>
|
2026-06-19 15:06:40 +07:00
|
|
|
|
public System.Drawing.Color? FontColor { get; init; }
|
2026-06-05 15:58:03 +07:00
|
|
|
|
|
|
|
|
|
|
/// <summary>Жирное начертание.</summary>
|
|
|
|
|
|
public bool? IsBold { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Курсив.</summary>
|
|
|
|
|
|
public bool? IsItalic { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Подчёркивание (одинарное).</summary>
|
|
|
|
|
|
public bool? IsUnderline { get; init; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Зачёркивание.</summary>
|
|
|
|
|
|
public bool? IsStrike { get; init; }
|
|
|
|
|
|
|
2026-06-19 15:06:40 +07:00
|
|
|
|
|
|
|
|
|
|
internal bool TryMerge(CellFont other, out CellFont result)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (other.FontSize == FontSize &&
|
|
|
|
|
|
other.FontFamily == FontFamily &&
|
|
|
|
|
|
other.FontColor == FontColor &&
|
|
|
|
|
|
other.IsBold == IsBold &&
|
|
|
|
|
|
other.IsItalic == IsItalic &&
|
|
|
|
|
|
other.IsUnderline == IsUnderline &&
|
|
|
|
|
|
other.IsStrike == IsStrike)
|
|
|
|
|
|
{
|
|
|
|
|
|
result = default;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = new CellFont
|
|
|
|
|
|
{
|
|
|
|
|
|
FontSize = other.FontSize ?? FontSize,
|
|
|
|
|
|
FontFamily = other.FontFamily ?? FontFamily,
|
|
|
|
|
|
FontColor = other.FontColor ?? FontColor,
|
|
|
|
|
|
IsBold = other.IsBold ?? IsBold,
|
|
|
|
|
|
IsItalic = other.IsItalic ?? IsItalic,
|
|
|
|
|
|
IsUnderline = other.IsUnderline ?? IsUnderline,
|
|
|
|
|
|
IsStrike = other.IsStrike ?? IsStrike
|
|
|
|
|
|
};
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-06-05 15:58:03 +07:00
|
|
|
|
/// <summary>Создаёт элемент Font для Open XML.</summary>
|
|
|
|
|
|
public Font? ToFont()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!FontSize.HasValue && FontFamily is null && FontColor is null &&
|
|
|
|
|
|
!IsBold.HasValue && !IsItalic.HasValue && !IsUnderline.HasValue && !IsStrike.HasValue)
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
|
|
var font = new Font();
|
|
|
|
|
|
if (FontSize.HasValue)
|
|
|
|
|
|
font.FontSize = new FontSize { Val = FontSize.Value };
|
|
|
|
|
|
if (FontFamily is not null)
|
|
|
|
|
|
font.FontName = new FontName { Val = FontFamily };
|
2026-06-19 15:06:40 +07:00
|
|
|
|
if (FontColor is { } c)
|
2026-06-05 15:58:03 +07:00
|
|
|
|
font.Color = new Color { Rgb = $"{c.R:X2}{c.G:X2}{c.B:X2}" };
|
|
|
|
|
|
if (IsBold == true) font.Bold = new Bold();
|
|
|
|
|
|
if (IsItalic == true) font.Italic = new Italic();
|
|
|
|
|
|
if (IsUnderline == true) font.Underline = new Underline();
|
|
|
|
|
|
if (IsStrike == true) font.Strike = new Strike();
|
|
|
|
|
|
return font;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>Создаёт CellFont из элемента Font Open XML.</summary>
|
|
|
|
|
|
public static CellFont FromFont(Font? font)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (font == null)
|
|
|
|
|
|
return default;
|
|
|
|
|
|
|
|
|
|
|
|
var result = new CellFont
|
|
|
|
|
|
{
|
|
|
|
|
|
IsBold = font.Bold != null,
|
|
|
|
|
|
IsItalic = font.Italic != null,
|
|
|
|
|
|
IsUnderline = font.Underline != null,
|
|
|
|
|
|
IsStrike = font.Strike != null
|
|
|
|
|
|
};
|
|
|
|
|
|
if (font.FontSize?.Val?.Value is { } size)
|
|
|
|
|
|
result = result with { FontSize = size };
|
|
|
|
|
|
if (font.FontName?.Val?.Value is { } name)
|
|
|
|
|
|
result = result with { FontFamily = name };
|
|
|
|
|
|
if (font.Color?.Rgb?.Value is { } rgb && rgb.Length >= 6)
|
|
|
|
|
|
{
|
|
|
|
|
|
var color = System.Drawing.Color.FromArgb(
|
|
|
|
|
|
Convert.ToByte(rgb.Substring(0, 2), 16),
|
|
|
|
|
|
Convert.ToByte(rgb.Substring(2, 2), 16),
|
|
|
|
|
|
Convert.ToByte(rgb.Substring(4, 2), 16)
|
|
|
|
|
|
);
|
2026-06-19 15:06:40 +07:00
|
|
|
|
result = result with { FontColor = color };
|
2026-06-05 15:58:03 +07:00
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override bool Equals(object? obj) => obj is CellFont other && Equals(other);
|
|
|
|
|
|
public bool Equals(CellFont other) => this == other;
|
|
|
|
|
|
|
|
|
|
|
|
public static bool operator ==(CellFont left, CellFont right) =>
|
|
|
|
|
|
left.FontSize == right.FontSize &&
|
|
|
|
|
|
left.FontFamily == right.FontFamily &&
|
|
|
|
|
|
Equals(left.FontColor, right.FontColor) &&
|
|
|
|
|
|
left.IsBold == right.IsBold &&
|
|
|
|
|
|
left.IsItalic == right.IsItalic &&
|
|
|
|
|
|
left.IsUnderline == right.IsUnderline &&
|
|
|
|
|
|
left.IsStrike == right.IsStrike;
|
|
|
|
|
|
|
|
|
|
|
|
public static bool operator !=(CellFont left, CellFont right) => !(left == right);
|
|
|
|
|
|
|
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
|
{
|
|
|
|
|
|
unchecked
|
|
|
|
|
|
{
|
|
|
|
|
|
int hash = 17;
|
|
|
|
|
|
hash = hash * 31 + (FontSize?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (FontFamily?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (FontColor?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (IsBold?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (IsItalic?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (IsUnderline?.GetHashCode() ?? 0);
|
|
|
|
|
|
hash = hash * 31 + (IsStrike?.GetHashCode() ?? 0);
|
|
|
|
|
|
return hash;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|