Files

255 lines
6.0 KiB
C#

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();
}
}
}
}