chore: save current workspace progress
This commit is contained in:
+140
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
|
||||
namespace MultiWheelC.TrajectoryPlanning.PathSmoothing.Output.Visualization;
|
||||
|
||||
/// <summary>按准确族名解析报告所需字体,并提供混合中英文文本的共同基线度量。</summary>
|
||||
public sealed class SmoothingFontResolver
|
||||
{
|
||||
public bool TryResolve(
|
||||
string chineseFamilyName,
|
||||
string latinFamilyName,
|
||||
out SmoothingFontResolution resolution,
|
||||
out string reason)
|
||||
{
|
||||
resolution = null;
|
||||
reason = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(chineseFamilyName) || string.IsNullOrWhiteSpace(latinFamilyName))
|
||||
{
|
||||
reason = "中文和拉丁字体族名均不能为空。";
|
||||
return false;
|
||||
}
|
||||
|
||||
var collection = new InstalledFontCollection();
|
||||
FontFamily chinese = FindExact(collection.Families, chineseFamilyName);
|
||||
FontFamily latin = FindExact(collection.Families, latinFamilyName);
|
||||
if (chinese == null || latin == null)
|
||||
{
|
||||
collection.Dispose();
|
||||
reason = "未安装报告所需的精确字体族:" + (chinese == null ? chineseFamilyName : latinFamilyName) + "。";
|
||||
return false;
|
||||
}
|
||||
|
||||
resolution = new SmoothingFontResolution(collection, chinese, latin, chineseFamilyName, latinFamilyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
public RectangleF MeasureMixedText(SmoothingFontResolution resolution, string text, float points)
|
||||
{
|
||||
if (resolution == null) throw new ArgumentNullException(nameof(resolution));
|
||||
if (string.IsNullOrEmpty(text) || points <= 0f) return RectangleF.Empty;
|
||||
using (var bitmap = new Bitmap(1, 1))
|
||||
using (Graphics graphics = Graphics.FromImage(bitmap))
|
||||
using (var format = (StringFormat)StringFormat.GenericTypographic.Clone())
|
||||
{
|
||||
format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
|
||||
float width = 0f, height = 0f;
|
||||
foreach (TextRun run in SplitRuns(text))
|
||||
{
|
||||
using (Font font = resolution.CreateFont(run.IsChinese ? resolution.ChineseFamily : resolution.LatinFamily, points))
|
||||
{
|
||||
SizeF size = graphics.MeasureString(run.Text, font, PointF.Empty, format);
|
||||
width += size.Width;
|
||||
height = Math.Max(height, size.Height);
|
||||
}
|
||||
}
|
||||
return new RectangleF(0f, 0f, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
internal static IReadOnlyList<TextRun> SplitRuns(string text)
|
||||
{
|
||||
var runs = new List<TextRun>();
|
||||
if (string.IsNullOrEmpty(text)) return runs;
|
||||
int start = 0;
|
||||
bool isChinese = IsChinese(text[0]);
|
||||
for (int index = 1; index < text.Length; index++)
|
||||
{
|
||||
bool currentIsChinese = IsChinese(text[index]);
|
||||
if (currentIsChinese == isChinese) continue;
|
||||
runs.Add(new TextRun(text.Substring(start, index - start), isChinese));
|
||||
start = index;
|
||||
isChinese = currentIsChinese;
|
||||
}
|
||||
runs.Add(new TextRun(text.Substring(start), isChinese));
|
||||
return runs;
|
||||
}
|
||||
|
||||
private static FontFamily FindExact(IReadOnlyList<FontFamily> families, string name)
|
||||
{
|
||||
for (int index = 0; index < families.Count; index++)
|
||||
{
|
||||
FontFamily family = families[index];
|
||||
if (string.Equals(family.Name, name, StringComparison.Ordinal) ||
|
||||
string.Equals(family.GetName(1033), name, StringComparison.Ordinal)) return family;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsChinese(char value)
|
||||
{
|
||||
return (value >= 0x3400 && value <= 0x4dbf) || (value >= 0x4e00 && value <= 0x9fff) ||
|
||||
(value >= 0xf900 && value <= 0xfaff) || value == 0x3002 || value == 0xff0c || value == 0xff1a;
|
||||
}
|
||||
|
||||
internal sealed class TextRun
|
||||
{
|
||||
public TextRun(string text, bool isChinese) { Text = text; IsChinese = isChinese; }
|
||||
public string Text { get; }
|
||||
public bool IsChinese { get; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>一次报告导出所使用的精确字体族;释放时同时释放字体集合。</summary>
|
||||
public sealed class SmoothingFontResolution : IDisposable
|
||||
{
|
||||
private readonly InstalledFontCollection _collection;
|
||||
private readonly string _chineseFamilyName;
|
||||
private readonly string _latinFamilyName;
|
||||
|
||||
internal SmoothingFontResolution(
|
||||
InstalledFontCollection collection,
|
||||
FontFamily chineseFamily,
|
||||
FontFamily latinFamily,
|
||||
string chineseFamilyName,
|
||||
string latinFamilyName)
|
||||
{
|
||||
_collection = collection ?? throw new ArgumentNullException(nameof(collection));
|
||||
ChineseFamily = chineseFamily ?? throw new ArgumentNullException(nameof(chineseFamily));
|
||||
LatinFamily = latinFamily ?? throw new ArgumentNullException(nameof(latinFamily));
|
||||
_chineseFamilyName = chineseFamilyName ?? throw new ArgumentNullException(nameof(chineseFamilyName));
|
||||
_latinFamilyName = latinFamilyName ?? throw new ArgumentNullException(nameof(latinFamilyName));
|
||||
}
|
||||
|
||||
public string ChineseFamilyName => _chineseFamilyName;
|
||||
public string LatinFamilyName => _latinFamilyName;
|
||||
internal FontFamily ChineseFamily { get; }
|
||||
internal FontFamily LatinFamily { get; }
|
||||
|
||||
internal Font CreateFont(FontFamily family, float points)
|
||||
{
|
||||
return new Font(family, points, FontStyle.Regular, GraphicsUnit.Point);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_collection.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user