|
|
@ -1,5 +1,4 @@ |
|
|
|
using Apewer; |
|
|
|
using Apewer.Internals.Interop; |
|
|
|
using Apewer.Internals.Interop; |
|
|
|
using System; |
|
|
|
using System.Collections.Generic; |
|
|
|
using System.Drawing; |
|
|
@ -23,35 +22,30 @@ namespace Apewer.Surface |
|
|
|
public class FormsUtility |
|
|
|
{ |
|
|
|
|
|
|
|
private const string FontYahei = "Microsoft Yahei"; |
|
|
|
private const string FontSimsun = "Simsun"; |
|
|
|
|
|
|
|
private static string _fontname = ""; |
|
|
|
|
|
|
|
/// <summary>线程锁。</summary>
|
|
|
|
public static object ThreadLocker = new object(); |
|
|
|
|
|
|
|
/// <summary>存在微软雅黑字体。</summary>
|
|
|
|
public static bool MsyhExist |
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>窗体启动初始化。</summary>
|
|
|
|
[STAThread] |
|
|
|
public static void StartInitialization() |
|
|
|
{ |
|
|
|
get { return File.Exists("c:\\windows\\fonts\\msyh.ttc"); } |
|
|
|
Control.CheckForIllegalCrossThreadCalls = false; |
|
|
|
Application.EnableVisualStyles(); |
|
|
|
Application.SetCompatibleTextRenderingDefault(false); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取默认字体名称。</summary>
|
|
|
|
public static string DefaultFontName |
|
|
|
/// <summary>禁用跨线程调用检查。</summary>
|
|
|
|
public static void CrossThread() |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
if (!string.IsNullOrEmpty(_fontname)) return _fontname; |
|
|
|
try |
|
|
|
{ |
|
|
|
if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei; |
|
|
|
else return FontSimsun; |
|
|
|
} |
|
|
|
catch { return FontSimsun; } |
|
|
|
} |
|
|
|
Control.CheckForIllegalCrossThreadCalls = false; |
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#region 颜色。
|
|
|
|
|
|
|
|
/// <summary>获取所有可枚举的颜色。</summary>
|
|
|
|
public static Color[] EnumerableColor |
|
|
|
{ |
|
|
@ -284,7 +278,7 @@ namespace Apewer.Surface |
|
|
|
/// <param name="fore">前景色(基色)。</param>
|
|
|
|
/// <param name="depth">颜色深度,最大值。</param>
|
|
|
|
/// <returns>合成后的颜色(基色)。</returns>
|
|
|
|
public static int AlphaColor(int alpha, int fore, int back, int depth = 255) |
|
|
|
public static int MixAlpha(int alpha, int fore, int back, int depth = 255) |
|
|
|
{ |
|
|
|
int b = back, f = fore; |
|
|
|
if (b > depth) b = depth; if (b < 0) b = 0; |
|
|
@ -294,81 +288,97 @@ namespace Apewer.Surface |
|
|
|
return v; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>从程序集获取资源。发生错误时返回 NULL 值,不引发异常。</summary>
|
|
|
|
public static Stream OpenResourceStream(string name, Assembly assembly = null) |
|
|
|
/// <summary>按 Alpha 混合不透明的颜色。</summary>
|
|
|
|
/// <param name="backColor">背景色。</param>
|
|
|
|
/// <param name="foreColor">前景色。</param>
|
|
|
|
/// <param name="foreAlpha">前景 Alpha 值。</param>
|
|
|
|
/// <returns>混合后的颜色。</returns>
|
|
|
|
public static Color MixAlpha(Color backColor, Color foreColor, int foreAlpha) |
|
|
|
{ |
|
|
|
var stream = null as Stream; |
|
|
|
try |
|
|
|
{ |
|
|
|
if (assembly == null) assembly = Assembly.GetCallingAssembly(); |
|
|
|
stream = assembly.GetManifestResourceStream(name); |
|
|
|
} |
|
|
|
catch { } |
|
|
|
return null; |
|
|
|
var r = MixAlpha(backColor.R, foreColor.R, foreAlpha); |
|
|
|
var g = MixAlpha(backColor.G, foreColor.G, foreAlpha); |
|
|
|
var b = MixAlpha(backColor.B, foreColor.B, foreAlpha); |
|
|
|
var a = MixAlpha(backColor.A, foreColor.A, foreAlpha); |
|
|
|
return Color.FromArgb(a, r, g, b); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。</summary>
|
|
|
|
public static MemoryStream GetResourceStream(string name, Assembly assembly = null) |
|
|
|
{ |
|
|
|
var stream = OpenResourceStream(name, assembly); |
|
|
|
if (stream == null) return null; |
|
|
|
var memory = new MemoryStream(); |
|
|
|
BinaryUtility.Read(stream, memory); |
|
|
|
stream.Dispose(); |
|
|
|
memory.ResetPosition(); |
|
|
|
return memory; |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
|
|
|
|
/// <summary>从程序集获取资源,读取到内存流。发生错误时返回 NULL 值,不引发异常。</summary>
|
|
|
|
public static byte[] GetResource(string name, Assembly assembly = null) |
|
|
|
{ |
|
|
|
var stream = OpenResourceStream(name, assembly); |
|
|
|
if (stream == null) return null; |
|
|
|
var bytes = BinaryUtility.Read(stream); |
|
|
|
stream.Dispose(); |
|
|
|
return bytes; |
|
|
|
} |
|
|
|
#region 屏幕。
|
|
|
|
|
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>获取默认字体。</summary>
|
|
|
|
public static Font DefaultFont |
|
|
|
/// <summary>获取屏幕的截图。</summary>
|
|
|
|
public static Bitmap[] ScreenShot() |
|
|
|
{ |
|
|
|
get { return new Font(DefaultFontName, 9); } |
|
|
|
var list = new List<Bitmap>(); |
|
|
|
var all = Screen.AllScreens; |
|
|
|
foreach (var screen in all) |
|
|
|
{ |
|
|
|
int vw = screen.Bounds.Width; |
|
|
|
int vh = screen.Bounds.Height; |
|
|
|
int vd = screen.BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh)); |
|
|
|
g.Dispose(); |
|
|
|
list.Add(b); |
|
|
|
} |
|
|
|
return list.ToArray(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取大小为 9 的默认字体。</summary>
|
|
|
|
public static Font NewFont() |
|
|
|
/// <summary>获取指定屏幕的截图。</summary>
|
|
|
|
/// <param name="screen">屏幕号。</param>
|
|
|
|
internal static Bitmap ScreenShot(int screen) |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, 9); |
|
|
|
var a = Screen.AllScreens; |
|
|
|
if ((a.Length > 0) && (screen >= 0) && (screen < a.Length)) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
int w = a[screen].Bounds.Width; |
|
|
|
int h = a[screen].Bounds.Height; |
|
|
|
int d = a[screen].BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); |
|
|
|
g.Dispose(); |
|
|
|
return b; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return new Bitmap(0, 0, PixelFormat.Format32bppArgb); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定大小的默认字体。</summary>
|
|
|
|
public static Font NewFont(float size) |
|
|
|
/// <summary>获取指定屏幕的截图。</summary>
|
|
|
|
/// <param name="screen">屏幕,若为 Null 则选择主屏幕。</param>
|
|
|
|
internal static Bitmap ScreenShot(Screen screen) |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, size); |
|
|
|
if (screen == null) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
int w = Screen.PrimaryScreen.Bounds.Width; |
|
|
|
int h = Screen.PrimaryScreen.Bounds.Height; |
|
|
|
int d = Screen.PrimaryScreen.BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); |
|
|
|
g.Dispose(); |
|
|
|
return b; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return new Bitmap(0, 0, PixelFormat.Format32bppArgb); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定大小的默认字体。</summary>
|
|
|
|
public static Font NewFont(float size, bool bold) |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular); |
|
|
|
} |
|
|
|
#endif
|
|
|
|
|
|
|
|
/// <summary>窗体启动初始化。</summary>
|
|
|
|
[STAThread] |
|
|
|
public static void StartInitialization() |
|
|
|
{ |
|
|
|
Control.CheckForIllegalCrossThreadCalls = false; |
|
|
|
Application.EnableVisualStyles(); |
|
|
|
Application.SetCompatibleTextRenderingDefault(false); |
|
|
|
} |
|
|
|
#endregion
|
|
|
|
|
|
|
|
/// <summary>禁用跨线程调用检查。</summary>
|
|
|
|
public static void CrossThread() |
|
|
|
{ |
|
|
|
Control.CheckForIllegalCrossThreadCalls = false; |
|
|
|
} |
|
|
|
#region 窗体。
|
|
|
|
|
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>移动窗体。</summary>
|
|
|
|
public static void MoveForm(Form form) |
|
|
@ -396,85 +406,72 @@ namespace Apewer.Surface |
|
|
|
int oldGWLEx = User32.SetWindowLong(form, Constant.GWL_EXSTYLE, Constant.WS_EX_TRANSPARENT | Constant.WS_EX_LAYERED); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Image image, Color border) |
|
|
|
/// <summary>将窗体最大化,不覆盖任务栏。</summary>
|
|
|
|
/// <param name="form">窗体。</param>
|
|
|
|
public static void ToMaximum(Form form) |
|
|
|
{ |
|
|
|
if (image != null) |
|
|
|
if (form != null) |
|
|
|
{ |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
return true; |
|
|
|
var s = Screen.FromControl(form); |
|
|
|
var r = s.WorkingArea; |
|
|
|
if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height)) |
|
|
|
{ |
|
|
|
form.MaximumSize = r.Size; |
|
|
|
} |
|
|
|
form.Location = r.Location; |
|
|
|
form.Size = r.Size; |
|
|
|
} |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Bitmap image, Color border) |
|
|
|
/// <summary>用指定图像绘制窗体,窗体与图像的大小必须一致。</summary>
|
|
|
|
/// <param name="form">要绘制的窗体。</param>
|
|
|
|
/// <param name="image">要使用的图像。</param>
|
|
|
|
public static void UpdateShadow(Form form, Image image) |
|
|
|
{ |
|
|
|
if (image != null) |
|
|
|
if ((form != null) && (image != null)) |
|
|
|
{ |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
else return false; |
|
|
|
} |
|
|
|
Bitmap vbitmap; |
|
|
|
if ((form.Width != image.Width) || (form.Height != image.Height)) |
|
|
|
{ |
|
|
|
vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
vbitmap = new Bitmap(image); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
/// <param name="wall">背景颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Image image, Color border, Color wall) |
|
|
|
{ |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
var screendc = User32.GetDC(IntPtr.Zero); |
|
|
|
var location = new Internals.Interop.Point(form.Left, form.Top); |
|
|
|
var size = new Internals.Interop.Size(form.Width, form.Height); |
|
|
|
var compatibledc = Gdi32.CreateCompatibleDC(screendc); |
|
|
|
var handle = vbitmap.GetHbitmap(Color.FromArgb(0)); |
|
|
|
var oldbitmap = Gdi32.SelectObject(compatibledc, handle); |
|
|
|
var srcloc = new Internals.Interop.Point(0, 0); |
|
|
|
var blendfunction = new BlendFunction(); |
|
|
|
|
|
|
|
g.Clear(wall); |
|
|
|
blendfunction.blendop = Constant.AC_SRC_OVER; |
|
|
|
blendfunction.sourceconstantalpha = byte.Parse("255"); |
|
|
|
blendfunction.alphaformat = Constant.AC_SRC_ALPHA; |
|
|
|
blendfunction.blendflags = 0; |
|
|
|
User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
return true; |
|
|
|
if (handle != IntPtr.Zero) |
|
|
|
{ |
|
|
|
Gdi32.SelectObject(compatibledc, oldbitmap); |
|
|
|
Gdi32.DeleteObject(handle); |
|
|
|
} |
|
|
|
User32.ReleaseDC(IntPtr.Zero, screendc); |
|
|
|
Gdi32.DeleteDC(compatibledc); |
|
|
|
} |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>建立带有圆角样式的路径。</summary>
|
|
|
|
/// <param name="rect">建立矩形路径的区域。</param>
|
|
|
|
/// <param name="radius">圆角的大小。</param>
|
|
|
|
/// <returns>建立的路径。</returns>
|
|
|
|
public static GraphicsPath CreatePath(Rectangle rect, int radius = 0) |
|
|
|
/// <summary>为窗体启用阴影。</summary>
|
|
|
|
/// <param name="form">要启用阴影的窗体。</param>
|
|
|
|
public static void EnableShadow(Form form) |
|
|
|
{ |
|
|
|
GraphicsPath path = new GraphicsPath(); |
|
|
|
int r = (radius < 0) ? 0 : radius; |
|
|
|
switch (r) |
|
|
|
{ |
|
|
|
case 0: |
|
|
|
path.AddRectangle(rect); |
|
|
|
break; |
|
|
|
default: |
|
|
|
path.AddArc(rect.X, rect.Y, r, r, 180, 90); |
|
|
|
path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90); |
|
|
|
path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90); |
|
|
|
path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90); |
|
|
|
break; |
|
|
|
} |
|
|
|
path.CloseFigure(); |
|
|
|
return path; |
|
|
|
if (form == null) return; |
|
|
|
int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE); |
|
|
|
User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>恢复任务栏中窗体标题的右键菜单。</summary>
|
|
|
@ -489,6 +486,14 @@ namespace Apewer.Surface |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 控件。
|
|
|
|
|
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>在主界面中移动控件,由目标控件取代当前控件,形成切换控件的动画。</summary>
|
|
|
|
/// <param name="current">当前显示的控件。</param>
|
|
|
|
/// <param name="target">将要显示的目标控件。</param>
|
|
|
@ -556,136 +561,138 @@ namespace Apewer.Surface |
|
|
|
current.Visible = false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>将窗体最大化,不覆盖任务栏。</summary>
|
|
|
|
/// <param name="form">窗体。</param>
|
|
|
|
public static void ToMaximum(Form form) |
|
|
|
/// <summary></summary>
|
|
|
|
public static void Invoke(Control control, Action action, bool async = false) |
|
|
|
{ |
|
|
|
if (form != null) |
|
|
|
if (control == null || action == null) return; |
|
|
|
// control.Invoke(action);
|
|
|
|
if (async) |
|
|
|
{ |
|
|
|
var s = Screen.FromControl(form); |
|
|
|
var r = s.WorkingArea; |
|
|
|
if ((form.MaximumSize.Width < r.Width) || (form.MaximumSize.Height < r.Height)) |
|
|
|
control.BeginInvoke(new Action(delegate () |
|
|
|
{ |
|
|
|
form.MaximumSize = r.Size; |
|
|
|
} |
|
|
|
form.Location = r.Location; |
|
|
|
form.Size = r.Size; |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
control.Invoke(new Action(delegate () |
|
|
|
{ |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>用指定图像绘制窗体,窗体与图像的大小必须一致。</summary>
|
|
|
|
/// <param name="form">要绘制的窗体。</param>
|
|
|
|
/// <param name="image">要使用的图像。</param>
|
|
|
|
public static void UpdateShadow(Form form, Image image) |
|
|
|
/// <summary></summary>
|
|
|
|
public static void BeginInvoke(Control control, Action action) |
|
|
|
{ |
|
|
|
if ((form != null) && (image != null)) |
|
|
|
{ |
|
|
|
Bitmap vbitmap; |
|
|
|
if ((form.Width != image.Width) || (form.Height != image.Height)) |
|
|
|
{ |
|
|
|
vbitmap = new Bitmap(image.GetThumbnailImage(form.Width, form.Height, null, IntPtr.Zero)); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
vbitmap = new Bitmap(image); |
|
|
|
} |
|
|
|
if (control == null || action == null) return; |
|
|
|
|
|
|
|
var screendc = User32.GetDC(IntPtr.Zero); |
|
|
|
var location = new Internals.Interop.Point(form.Left, form.Top); |
|
|
|
var size = new Internals.Interop.Size(form.Width, form.Height); |
|
|
|
var compatibledc = Gdi32.CreateCompatibleDC(screendc); |
|
|
|
var handle = vbitmap.GetHbitmap(Color.FromArgb(0)); |
|
|
|
var oldbitmap = Gdi32.SelectObject(compatibledc, handle); |
|
|
|
var srcloc = new Internals.Interop.Point(0, 0); |
|
|
|
var blendfunction = new BlendFunction(); |
|
|
|
control.BeginInvoke(new Action(delegate () |
|
|
|
{ |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
blendfunction.blendop = Constant.AC_SRC_OVER; |
|
|
|
blendfunction.sourceconstantalpha = byte.Parse("255"); |
|
|
|
blendfunction.alphaformat = Constant.AC_SRC_ALPHA; |
|
|
|
blendfunction.blendflags = 0; |
|
|
|
User32.UpdateLayeredWindow(form.Handle, screendc, ref location, ref size, compatibledc, ref srcloc, 0, ref blendfunction, Constant.ULW_ALPHA); |
|
|
|
/// <summary>设置窗体置顶。</summary>
|
|
|
|
public static void SetTopMost(IntPtr form, bool value = true) |
|
|
|
{ |
|
|
|
if (form == null || form == IntPtr.Zero) return; |
|
|
|
User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3); |
|
|
|
} |
|
|
|
|
|
|
|
if (handle != IntPtr.Zero) |
|
|
|
{ |
|
|
|
Gdi32.SelectObject(compatibledc, oldbitmap); |
|
|
|
Gdi32.DeleteObject(handle); |
|
|
|
} |
|
|
|
User32.ReleaseDC(IntPtr.Zero, screendc); |
|
|
|
Gdi32.DeleteDC(compatibledc); |
|
|
|
} |
|
|
|
/// <summary>设置窗体置顶。</summary>
|
|
|
|
public static void SetTopMost(Form form, bool value = true) |
|
|
|
{ |
|
|
|
if (form != null) SetTopMost(form.Handle, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>为窗体启用阴影。</summary>
|
|
|
|
/// <param name="form">要启用阴影的窗体。</param>
|
|
|
|
public static void EnableShadow(Form form) |
|
|
|
#endif
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 绘图。
|
|
|
|
|
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Image image, Color border) |
|
|
|
{ |
|
|
|
if (form == null) return; |
|
|
|
int vformclass = User32.GetClassLong(form.Handle, Constant.GCL_STYLE); |
|
|
|
User32.SetClassLong(form.Handle, Constant.GCL_STYLE, vformclass | Constant.CS_DROPSHADOW); |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取屏幕的截图。</summary>
|
|
|
|
public static Bitmap[] ScreenShot() |
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Bitmap image, Color border) |
|
|
|
{ |
|
|
|
var list = new List<Bitmap>(); |
|
|
|
var all = Screen.AllScreens; |
|
|
|
foreach (var screen in all) |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
int vw = screen.Bounds.Width; |
|
|
|
int vh = screen.Bounds.Height; |
|
|
|
int vd = screen.BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(vw, vh, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(vw, vh)); |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
list.Add(b); |
|
|
|
return true; |
|
|
|
} |
|
|
|
return list.ToArray(); |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定屏幕的截图。</summary>
|
|
|
|
/// <param name="screen">屏幕号。</param>
|
|
|
|
internal static Bitmap ScreenShot(int screen) |
|
|
|
/// <summary>绘制内边框。</summary>
|
|
|
|
/// <param name="image">源图像。</param>
|
|
|
|
/// <param name="border">边框颜色。</param>
|
|
|
|
/// <param name="wall">背景颜色。</param>
|
|
|
|
public static bool PaintBorder(ref Image image, Color border, Color wall) |
|
|
|
{ |
|
|
|
var a = Screen.AllScreens; |
|
|
|
if ((a.Length > 0) && (screen >= 0) && (screen < a.Length)) |
|
|
|
if (image != null) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
int w = a[screen].Bounds.Width; |
|
|
|
int h = a[screen].Bounds.Height; |
|
|
|
int d = a[screen].BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); |
|
|
|
g.Dispose(); |
|
|
|
return b; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
var g = Graphics.FromImage(image); |
|
|
|
var p = new Pen(border); |
|
|
|
|
|
|
|
g.Clear(wall); |
|
|
|
|
|
|
|
g.DrawRectangle(p, 0, 0, image.Width - 1, image.Height - 1); |
|
|
|
p.Dispose(); |
|
|
|
g.Dispose(); |
|
|
|
return true; |
|
|
|
} |
|
|
|
return new Bitmap(0, 0, PixelFormat.Format32bppArgb); |
|
|
|
else return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定屏幕的截图。</summary>
|
|
|
|
/// <param name="screen">屏幕,若为 Null 则选择主屏幕。</param>
|
|
|
|
internal static Bitmap ScreenShot(Screen screen) |
|
|
|
/// <summary>建立带有圆角样式的路径。</summary>
|
|
|
|
/// <param name="rect">建立矩形路径的区域。</param>
|
|
|
|
/// <param name="radius">圆角的大小。</param>
|
|
|
|
/// <returns>建立的路径。</returns>
|
|
|
|
public static GraphicsPath CreatePath(Rectangle rect, int radius = 0) |
|
|
|
{ |
|
|
|
if (screen == null) |
|
|
|
GraphicsPath path = new GraphicsPath(); |
|
|
|
int r = (radius < 0) ? 0 : radius; |
|
|
|
switch (r) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
int w = Screen.PrimaryScreen.Bounds.Width; |
|
|
|
int h = Screen.PrimaryScreen.Bounds.Height; |
|
|
|
int d = Screen.PrimaryScreen.BitsPerPixel; |
|
|
|
Bitmap b = new Bitmap(w, h, PixelFormat.Format32bppArgb); |
|
|
|
Graphics g = Graphics.FromImage(b); |
|
|
|
g.CopyFromScreen(0, 0, 0, 0, new System.Drawing.Size(w, h)); |
|
|
|
g.Dispose(); |
|
|
|
return b; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
case 0: |
|
|
|
path.AddRectangle(rect); |
|
|
|
break; |
|
|
|
default: |
|
|
|
path.AddArc(rect.X, rect.Y, r, r, 180, 90); |
|
|
|
path.AddArc(rect.Right - r - 1, rect.Y, r, r, 270, 90); |
|
|
|
path.AddArc(rect.Right - r - 1, rect.Bottom - r - 1, r, r, 0, 90); |
|
|
|
path.AddArc(rect.X, rect.Bottom - r - 1, r, r, 90, 90); |
|
|
|
break; |
|
|
|
} |
|
|
|
return new Bitmap(0, 0, PixelFormat.Format32bppArgb); |
|
|
|
path.CloseFigure(); |
|
|
|
return path; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary></summary>
|
|
|
@ -731,61 +738,6 @@ namespace Apewer.Surface |
|
|
|
return path; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>从文件加载字体,并获取字体。</summary>
|
|
|
|
public static FontFamily LoadFont(string path) |
|
|
|
{ |
|
|
|
if (!File.Exists(path)) return null; |
|
|
|
var vpfc = new PrivateFontCollection(); |
|
|
|
vpfc.AddFontFile(path); |
|
|
|
var vff = vpfc.Families[0]; |
|
|
|
return vff; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary></summary>
|
|
|
|
public static void Invoke(Control control, Action action, bool async = false) |
|
|
|
{ |
|
|
|
if (control == null || action == null) return; |
|
|
|
// control.Invoke(action);
|
|
|
|
if (async) |
|
|
|
{ |
|
|
|
control.BeginInvoke(new Action(delegate () |
|
|
|
{ |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
control.Invoke(new Action(delegate () |
|
|
|
{ |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary></summary>
|
|
|
|
public static void BeginInvoke(Control control, Action action) |
|
|
|
{ |
|
|
|
if (control == null || action == null) return; |
|
|
|
|
|
|
|
control.BeginInvoke(new Action(delegate () |
|
|
|
{ |
|
|
|
action.Invoke(); |
|
|
|
})); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>设置窗体置顶。</summary>
|
|
|
|
public static void SetTopMost(IntPtr form, bool value = true) |
|
|
|
{ |
|
|
|
if (form == null || form == IntPtr.Zero) return; |
|
|
|
User32.SetWindowPos(form, new IntPtr(value ? -1 : -2), 0, 0, 0, 0, 3); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>设置窗体置顶。</summary>
|
|
|
|
public static void SetTopMost(Form form, bool value = true) |
|
|
|
{ |
|
|
|
if (form != null) SetTopMost(form.Handle, value); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定文件中的图标总数。</summary>
|
|
|
|
public static int GetIconsCount(string path) |
|
|
|
{ |
|
|
@ -830,6 +782,216 @@ namespace Apewer.Surface |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 字体。
|
|
|
|
|
|
|
|
private const string FontYahei = "Microsoft Yahei"; |
|
|
|
private const string FontSimsun = "Simsun"; |
|
|
|
|
|
|
|
private static string _fontname = ""; |
|
|
|
|
|
|
|
/// <summary>存在微软雅黑字体。</summary>
|
|
|
|
public static bool MsyhExist |
|
|
|
{ |
|
|
|
get { return File.Exists("c:\\windows\\fonts\\msyh.ttc"); } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取默认字体名称。</summary>
|
|
|
|
public static string DefaultFontName |
|
|
|
{ |
|
|
|
get |
|
|
|
{ |
|
|
|
if (!string.IsNullOrEmpty(_fontname)) return _fontname; |
|
|
|
try |
|
|
|
{ |
|
|
|
if (File.Exists("c:\\windows\\fonts\\msyh.ttc")) return FontYahei; |
|
|
|
else return FontSimsun; |
|
|
|
} |
|
|
|
catch { return FontSimsun; } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#if NETFX || NETCORE
|
|
|
|
|
|
|
|
/// <summary>获取默认字体。</summary>
|
|
|
|
public static Font DefaultFont |
|
|
|
{ |
|
|
|
get { return new Font(DefaultFontName, 9); } |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取大小为 9 的默认字体。</summary>
|
|
|
|
public static Font NewFont() |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, 9); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定大小的默认字体。</summary>
|
|
|
|
public static Font NewFont(float size) |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, size); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定大小的默认字体。</summary>
|
|
|
|
public static Font NewFont(float size, bool bold) |
|
|
|
{ |
|
|
|
return new Font(DefaultFontName, size, bold ? FontStyle.Bold : FontStyle.Regular); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>从文件加载字体,并获取指定字体。</summary>
|
|
|
|
/// <param name="path">文件路径。</param>
|
|
|
|
/// <param name="index">文件中的 Font Family 索引,默认取第一个(索引 0)。</param>
|
|
|
|
/// <returns>已存在的 Font Family,如果指定的索引处不存在 Font Family,则返回 NULL 值。</returns>
|
|
|
|
public static FontFamily LoadFont(string path, int index = 0) |
|
|
|
{ |
|
|
|
if (index < 0) return null; |
|
|
|
if (string.IsNullOrEmpty(path)) return null; |
|
|
|
if (!File.Exists(path)) return null; |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
var pfc = new PrivateFontCollection(); |
|
|
|
pfc.AddFontFile(path); |
|
|
|
var fs = pfc.Families; |
|
|
|
if (fs.Length > 0 && index < fs.Length) return fs[index]; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
#if NET40 || NET461
|
|
|
|
|
|
|
|
/// <summary></summary>
|
|
|
|
public static List<System.Windows.Media.FontFamily> ListFileFont(string path) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
var collection = System.Windows.Media.Fonts.GetFontFamilies(path); |
|
|
|
var list = new List<System.Windows.Media.FontFamily>(collection.Count); |
|
|
|
foreach (var item in collection) list.Add(item); |
|
|
|
return list; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
return new List<System.Windows.Media.FontFamily>(); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary></summary>
|
|
|
|
public static List<System.Windows.Media.FontFamily> ListSystemFont() |
|
|
|
{ |
|
|
|
var collection = System.Windows.Media.Fonts.SystemFontFamilies; |
|
|
|
var list = new List<System.Windows.Media.FontFamily>(collection.Count); |
|
|
|
foreach (var item in collection) list.Add(item); |
|
|
|
return list; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>枚举指定字体中的所有字符。</summary>
|
|
|
|
public static List<char> EnumerateFontChars(IEnumerable<System.Windows.Media.Typeface> typefaces) |
|
|
|
{ |
|
|
|
var chars = new List<char>(); |
|
|
|
if (typefaces != null) |
|
|
|
{ |
|
|
|
foreach (var typeface in typefaces) |
|
|
|
{ |
|
|
|
var subs = EnumerateFontChars(typeface); |
|
|
|
if (subs != null) chars.AddRange(subs); |
|
|
|
} |
|
|
|
} |
|
|
|
return chars; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>枚举指定字体中的所有字符。</summary>
|
|
|
|
public static List<char> EnumerateFontChars(System.Windows.Media.Typeface typeface) |
|
|
|
{ |
|
|
|
System.Windows.Media.GlyphTypeface glyph; |
|
|
|
var tried = typeface.TryGetGlyphTypeface(out glyph); |
|
|
|
if (glyph == null) return null; |
|
|
|
|
|
|
|
var map = glyph.CharacterToGlyphMap; |
|
|
|
var keys = map.Keys; |
|
|
|
var chars = new List<char>(keys.Count); |
|
|
|
for (int i = 0; i < keys.Count; i++) |
|
|
|
{ |
|
|
|
var index = System.Linq.Enumerable.ElementAt(keys, i); |
|
|
|
try |
|
|
|
{ |
|
|
|
var c = Convert.ToChar(index); |
|
|
|
chars.Add(c.ToString()); |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return chars; |
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/// <summary>获取已安装的字体。</summary>
|
|
|
|
public static List<FontFamily> ListInstalledFonts() |
|
|
|
{ |
|
|
|
var list = new List<FontFamily>(); |
|
|
|
int ret = 0; // Win32 API 返回值,非零值均为异常。
|
|
|
|
|
|
|
|
// 初始化 FontCollection。
|
|
|
|
var collection = new Internals.FontCollection(); |
|
|
|
ret = GdiPlus.GdipNewInstalledFontCollection(out collection.NativePointer); |
|
|
|
if (ret != 0) return list; |
|
|
|
|
|
|
|
// 获取字体总数。
|
|
|
|
int found1 = 0; |
|
|
|
ret = GdiPlus.GdipGetFontCollectionFamilyCount(new HandleRef(collection, collection.NativePointer), out found1); |
|
|
|
if (ret != 0) return list; |
|
|
|
|
|
|
|
// 获取字体指针。
|
|
|
|
var ptrs = new IntPtr[found1]; |
|
|
|
int found2 = 0; |
|
|
|
ret = GdiPlus.GdipGetFontCollectionFamilyList(new HandleRef(collection, collection.NativePointer), found1, ptrs, out found2); |
|
|
|
if (ret != 0) return list; |
|
|
|
|
|
|
|
// 获取字体列表。
|
|
|
|
list.Capacity = found2; |
|
|
|
for (int i = 0; i < found2; i++) |
|
|
|
{ |
|
|
|
IntPtr cloned; |
|
|
|
GdiPlus.GdipCloneFontFamily(new HandleRef(null, ptrs[i]), out cloned); |
|
|
|
try |
|
|
|
{ |
|
|
|
var flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance; |
|
|
|
var args = new object[] { cloned }; |
|
|
|
var instance = Activator.CreateInstance(typeof(FontFamily), flags, null, args, null, null); |
|
|
|
var item = instance as FontFamily; |
|
|
|
if (item != null) list.Add(item); |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
|
|
|
|
list.Capacity = list.Count; |
|
|
|
return list; |
|
|
|
} |
|
|
|
|
|
|
|
private static bool GlyphExists(char c, Font font) |
|
|
|
{ |
|
|
|
using (var dummy = Graphics.FromImage(new Bitmap(1, 1))) |
|
|
|
{ |
|
|
|
IntPtr hdc = dummy.GetHdc(); |
|
|
|
var pgi = new ushort[1]; |
|
|
|
try |
|
|
|
{ |
|
|
|
IntPtr hfont = font.ToHfont(); |
|
|
|
Gdi32.SelectObject(hdc, hfont); |
|
|
|
string str = c.ToString(); |
|
|
|
Gdi32.GetGlyphIndices(hdc, str, str.Length, pgi, Constant.GGI_MARK_NONEXISTING_GLYPHS); |
|
|
|
} |
|
|
|
catch { } |
|
|
|
dummy.ReleaseHdc(hdc); |
|
|
|
|
|
|
|
// 0xFFFF 表示字形不存在。
|
|
|
|
return (pgi[0] != 0xffff); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|