字体预览工具 v1.0.0 初始版本
This commit is contained in:
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Text;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FontPreview;
|
||||
|
||||
public class Worker
|
||||
{
|
||||
public class CardData
|
||||
{
|
||||
public Bitmap Bitmap;
|
||||
|
||||
public int Width;
|
||||
|
||||
public string Name;
|
||||
|
||||
public string DisplayName;
|
||||
|
||||
public string Path;
|
||||
|
||||
public bool Failed;
|
||||
}
|
||||
|
||||
public delegate void CompletedHandler(bool cancelled, int done, int failed, int remain, List<CardData> cards);
|
||||
|
||||
private MainForm form;
|
||||
|
||||
private List<FontItem> items;
|
||||
|
||||
private int target;
|
||||
|
||||
private string text;
|
||||
|
||||
private int size;
|
||||
|
||||
private Color fg;
|
||||
|
||||
private Color bg;
|
||||
|
||||
private Dictionary<string, Bitmap> cache;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
private volatile bool stop;
|
||||
|
||||
private List<CardData> results = new List<CardData>();
|
||||
|
||||
public event CompletedHandler Completed;
|
||||
|
||||
public Worker(MainForm f, List<FontItem> items, int target, string text, int size, Color fg, Color bg, Dictionary<string, Bitmap> cache)
|
||||
{
|
||||
form = f;
|
||||
this.items = items;
|
||||
this.target = target;
|
||||
this.text = text;
|
||||
this.size = size;
|
||||
this.fg = fg;
|
||||
this.bg = bg;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public bool IsRunning()
|
||||
{
|
||||
return thread != null && thread.IsAlive;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
stop = true;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
stop = false;
|
||||
thread = new Thread(Run);
|
||||
thread.IsBackground = true;
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
int total = target;
|
||||
int next = 0;
|
||||
int done = 0;
|
||||
int failed = 0;
|
||||
// 并行渲染:拉满 CPU 线程,批量并行
|
||||
int workers = Math.Max(2, Environment.ProcessorCount);
|
||||
object renderLock = new object();
|
||||
|
||||
ParameterizedThreadStart work = delegate (object _)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (stop) break;
|
||||
int i = Interlocked.Increment(ref next) - 1;
|
||||
if (i >= total) break;
|
||||
FontItem fontItem = items[i];
|
||||
Bitmap value = null;
|
||||
bool failed2 = false;
|
||||
string key = fontItem.Cat + "|" + fontItem.Path;
|
||||
lock (renderLock) { cache.TryGetValue(key, out value); }
|
||||
if (value == null)
|
||||
{
|
||||
value = RenderFont(fontItem.Path, fontItem.Name, text, size, fg, bg, out failed2);
|
||||
if (value != null)
|
||||
{
|
||||
lock (renderLock) { cache[key] = value; }
|
||||
}
|
||||
}
|
||||
CardData cardData = new CardData();
|
||||
cardData.Bitmap = value;
|
||||
cardData.Width = 340;
|
||||
cardData.Name = fontItem.Name;
|
||||
cardData.DisplayName = fontItem.DisplayName;
|
||||
cardData.Path = fontItem.Path;
|
||||
cardData.Failed = failed2;
|
||||
lock (results) { results.Add(cardData); }
|
||||
int d = Interlocked.Increment(ref done);
|
||||
if (value == null) Interlocked.Increment(ref failed);
|
||||
// 进度更新节流:每 10 个或最后一个才唤醒 UI,避免频繁打断
|
||||
if (d % 10 == 0 || d >= total)
|
||||
{
|
||||
int pct = (int)((double)d / (double)total * 100.0);
|
||||
((Control)form).BeginInvoke((Delegate)(Action)delegate
|
||||
{
|
||||
form.SetProgress(pct, d, total);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread[] ts = new Thread[workers];
|
||||
for (int w = 0; w < workers; w++)
|
||||
{
|
||||
ts[w] = new Thread(work);
|
||||
ts[w].IsBackground = true;
|
||||
ts[w].Start();
|
||||
}
|
||||
foreach (Thread wt in ts) wt.Join();
|
||||
|
||||
int remain = total - done;
|
||||
List<CardData> snapshot;
|
||||
lock (results) { snapshot = new List<CardData>(results); }
|
||||
((Control)form).Invoke((Delegate)(Action)delegate
|
||||
{
|
||||
if (this.Completed != null)
|
||||
{
|
||||
this.Completed(stop, done, failed, remain, snapshot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
internal static Bitmap RenderFont(string path, string name, string text, int size, Color fg, Color bg, out bool failed)
|
||||
{
|
||||
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_002c: Expected O, but got Unknown
|
||||
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0074: Expected O, but got Unknown
|
||||
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0090: Expected O, but got Unknown
|
||||
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00ee: Expected O, but got Unknown
|
||||
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_011c: Expected O, but got Unknown
|
||||
failed = false;
|
||||
Bitmap val = null;
|
||||
PrivateFontCollection val2 = null;
|
||||
Font val3 = null;
|
||||
try
|
||||
{
|
||||
// 直接按文件路径加载,避免 AddMemoryFont 在快速连续渲染多字体时按内存地址缓存导致串字体
|
||||
val2 = new PrivateFontCollection();
|
||||
val2.AddFontFile(path);
|
||||
if (((FontCollection)val2).Families.Length == 0)
|
||||
{
|
||||
failed = true;
|
||||
return null;
|
||||
}
|
||||
FontFamily val4 = ((FontCollection)val2).Families[0];
|
||||
val3 = new Font(val4, (float)size, (FontStyle)0, (GraphicsUnit)2);
|
||||
int num = 14;
|
||||
Graphics val5 = Graphics.FromHwnd(IntPtr.Zero);
|
||||
try
|
||||
{
|
||||
StringFormat val6 = new StringFormat((StringFormatFlags)4096);
|
||||
try
|
||||
{
|
||||
val6.Alignment = (StringAlignment)0;
|
||||
val6.LineAlignment = (StringAlignment)1;
|
||||
SizeF sizeF = val5.MeasureString(text, val3, 20000, val6);
|
||||
int num2 = (int)Math.Ceiling(sizeF.Width) + num * 2;
|
||||
int num3 = (int)Math.Ceiling(sizeF.Height) + 14;
|
||||
val = new Bitmap(num2, Math.Max(num3, 30));
|
||||
Graphics val7 = Graphics.FromImage((Image)(object)val);
|
||||
try
|
||||
{
|
||||
val7.SmoothingMode = (SmoothingMode)4;
|
||||
val7.TextRenderingHint = (TextRenderingHint)4;
|
||||
val7.Clear(bg);
|
||||
Brush val8 = (Brush)new SolidBrush(fg);
|
||||
try
|
||||
{
|
||||
val7.DrawString(text, val3, val8, new RectangleF(num, 7f, sizeF.Width, num3 - 14), val6);
|
||||
}
|
||||
finally
|
||||
{
|
||||
((IDisposable)val8)?.Dispose();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
((IDisposable)val7)?.Dispose();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
((IDisposable)val6)?.Dispose();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
((IDisposable)val5)?.Dispose();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
failed = true;
|
||||
if (val != null)
|
||||
{
|
||||
((Image)val).Dispose();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (val3 != null)
|
||||
{
|
||||
val3.Dispose();
|
||||
}
|
||||
if (val2 != null)
|
||||
{
|
||||
((FontCollection)val2).Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user