mirror of
				https://gitee.com/csharpui/CPF.git
				synced 2025-11-01 00:46:56 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			563 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			563 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using SkiaSharp;
 | |
| using CPF.Drawing;
 | |
| using System.Globalization;
 | |
| 
 | |
| namespace CPF.Skia
 | |
| {
 | |
|     public static class Extension
 | |
|     {
 | |
|         static Extension()
 | |
|         {
 | |
|             SKFontManager fontManager = SKFontManager.Default;
 | |
|             var n = CultureInfo.InstalledUICulture.Name;
 | |
|             var temp = n.Split('-');
 | |
|             foreach (var item in temp)
 | |
|             {
 | |
|                 if (!string.IsNullOrWhiteSpace(item))
 | |
|                 {
 | |
|                     var f = fontManager.FontFamilies.FirstOrDefault(a => a.EndsWith(" " + item.Trim(), StringComparison.OrdinalIgnoreCase));
 | |
|                     if (f != null)
 | |
|                     {
 | |
|                         defaultFont = f;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (defaultFont == null)
 | |
|             {
 | |
|                 defaultFont = fontManager.FontFamilies.FirstOrDefault(a => a.EndsWith(" mono", StringComparison.OrdinalIgnoreCase));
 | |
|             }
 | |
|             if (defaultFont == null)
 | |
|             {
 | |
|                 defaultFont = fontManager.FontFamilies.FirstOrDefault();
 | |
|             }
 | |
|         }
 | |
|         static string defaultFont;
 | |
| 
 | |
|         private static string GetFontName(SKFontManager fontManager)
 | |
|         {
 | |
|             //var f = fontManager.FontFamilies.FirstOrDefault(a => a.EndsWith(" cn", StringComparison.OrdinalIgnoreCase));
 | |
|             //if (f == null)
 | |
|             //{
 | |
|             //    f = fontManager.FontFamilies.FirstOrDefault(a => a.EndsWith(" zh", StringComparison.OrdinalIgnoreCase));
 | |
|             //}
 | |
|             //if (f == null)
 | |
|             //{
 | |
|             //    f = fontManager.FontFamilies.FirstOrDefault(a => a.EndsWith(" mono", StringComparison.OrdinalIgnoreCase));
 | |
|             //}
 | |
|             //if (f == null)
 | |
|             //{
 | |
|             //    f = fontManager.FontFamilies.FirstOrDefault();
 | |
|             //}
 | |
|             //return f;
 | |
|             return defaultFont;
 | |
|         }
 | |
| 
 | |
|         static string[] bcp47 = new string[] { "en", "zh", "ja", "kr", "enGB", "sw" };
 | |
|         public static void DrawText(this SKCanvas canvas, SKPaint paint, string text, float x, float y)
 | |
|         {
 | |
|             if (!string.IsNullOrWhiteSpace(text))
 | |
|             {
 | |
|                 var fontManager = SKFontManager.Default;
 | |
|                 var t = paint.Typeface;
 | |
|                 var family = t.FamilyName;
 | |
|                 var si = new StringInfo(text);
 | |
|                 for (int i = 0; i < si.LengthInTextElements; i++)
 | |
|                 {
 | |
|                     var str = si.SubstringByTextElements(i, 1);
 | |
|                     if (str.Length != 2)
 | |
|                     {
 | |
|                         if (str != "\r")
 | |
|                         {
 | |
|                             if (t.CountGlyphs(str) == 0)//如果当前字体不支持该字符
 | |
|                             {
 | |
|                                 using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, str[0]))//检索系统默认支持的字体
 | |
|                                 {
 | |
|                                     SKTypeface f = null;
 | |
|                                     if (font == null)
 | |
|                                     {
 | |
|                                         string fn = GetFontName(fontManager);
 | |
|                                         if (fn != null)
 | |
|                                         {
 | |
|                                             f = fontManager.MatchFamily(fn, t.FontStyle);
 | |
|                                             if (f != null)
 | |
|                                             {
 | |
|                                                 paint.Typeface = f;
 | |
|                                             }
 | |
|                                             else
 | |
|                                             {
 | |
|                                                 paint.Typeface = t;
 | |
|                                             }
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                             paint.Typeface = t;
 | |
|                                         }
 | |
|                                     }
 | |
|                                     else
 | |
|                                     {
 | |
|                                         paint.Typeface = font;
 | |
|                                     }
 | |
|                                     canvas.DrawText(str, x, y, paint);
 | |
|                                     x += paint.MeasureText(str);
 | |
|                                     if (f != null)
 | |
|                                     {
 | |
|                                         f.Dispose();
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                                 canvas.DrawText(str, x, y, paint);
 | |
|                                 x += paint.MeasureText(str);
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, StringUtilities.GetUnicodeCharacterCode(str, SKTextEncoding.Utf32)))
 | |
|                         {
 | |
|                             if (font == null)
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = font;
 | |
|                             }
 | |
|                             canvas.DrawText(str, x, y, paint);
 | |
|                             x += paint.MeasureText(str);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 paint.Typeface = t;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public static float MeasureString(this SKPaint paint, string text)
 | |
|         {
 | |
|             float w = 0;
 | |
|             if (!string.IsNullOrEmpty(text))
 | |
|             {
 | |
|                 var fontManager = SKFontManager.Default;
 | |
|                 var t = paint.Typeface;
 | |
|                 var family = t.FamilyName;
 | |
|                 var si = new StringInfo(text);
 | |
|                 for (int i = 0; i < si.LengthInTextElements; i++)
 | |
|                 {
 | |
|                     var str = si.SubstringByTextElements(i, 1);
 | |
|                     if (str.Length != 2)
 | |
|                     {
 | |
|                         if (str != "\r" && str != "\n")
 | |
|                         {
 | |
|                             if (str == " ")
 | |
|                             {
 | |
|                                 w += paint.FontSpacing / 2;
 | |
|                             }
 | |
|                             else// if (str=="\t")
 | |
|                             {
 | |
|                                 if (t.CountGlyphs(str) == 0)
 | |
|                                 {
 | |
|                                     using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, str[0]))
 | |
|                                     {
 | |
|                                         SKTypeface f = null;
 | |
|                                         if (font == null)
 | |
|                                         {
 | |
|                                             string fn = GetFontName(fontManager);
 | |
|                                             if (fn != null)
 | |
|                                             {
 | |
|                                                 f = fontManager.MatchFamily(fn, t.FontStyle);
 | |
|                                                 if (f != null)
 | |
|                                                 {
 | |
|                                                     paint.Typeface = f;
 | |
|                                                 }
 | |
|                                                 else
 | |
|                                                 {
 | |
|                                                     paint.Typeface = t;
 | |
|                                                 }
 | |
|                                             }
 | |
|                                             else
 | |
|                                             {
 | |
|                                                 paint.Typeface = t;
 | |
|                                             }
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                             paint.Typeface = font;
 | |
|                                         }
 | |
|                                         w += paint.MeasureText(str);
 | |
|                                         if (f != null)
 | |
|                                         {
 | |
|                                             f.Dispose();
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     paint.Typeface = t;
 | |
|                                     w += paint.MeasureText(str);
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, StringUtilities.GetUnicodeCharacterCode(str, SKTextEncoding.Utf32)))
 | |
|                         {
 | |
|                             if (font == null)
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = font;
 | |
|                             }
 | |
|                             w += paint.MeasureText(str);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 paint.Typeface = t;
 | |
|             }
 | |
|             return w;
 | |
|         }
 | |
|         /// <summary>
 | |
|         /// 计算每个字符的宽度,不能有换行符
 | |
|         /// </summary>
 | |
|         /// <param name="paint"></param>
 | |
|         /// <param name="text"></param>
 | |
|         /// <returns></returns>
 | |
|         public static IList<(string, float)> MeasureAllChar(this SKPaint paint, string text)
 | |
|         {
 | |
|             List<(string, float)> list = new List<(string, float)>();
 | |
|             if (!string.IsNullOrEmpty(text))
 | |
|             {
 | |
|                 var fontManager = SKFontManager.Default;
 | |
|                 var t = paint.Typeface;
 | |
|                 var family = t.FamilyName;
 | |
|                 var si = new StringInfo(text);
 | |
|                 for (int i = 0; i < si.LengthInTextElements; i++)
 | |
|                 {
 | |
|                     var str = si.SubstringByTextElements(i, 1);
 | |
|                     if (str.Length != 2)
 | |
|                     {
 | |
|                         if (str != "\r" && str != "\n")
 | |
|                         {
 | |
|                             if (str == " ")
 | |
|                             {
 | |
|                                 //list.Add((str, paint.FontSpacing / 2));
 | |
|                                 list.Add((str, paint.MeasureText(str)));
 | |
|                             }
 | |
|                             else// if (str=="\t")
 | |
|                             {
 | |
|                                 if (t.CountGlyphs(str) == 0)
 | |
|                                 {
 | |
|                                     using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, str[0]))
 | |
|                                     {
 | |
|                                         SKTypeface f = null;
 | |
|                                         if (font == null)
 | |
|                                         {
 | |
|                                             string fn = GetFontName(fontManager);
 | |
|                                             if (fn != null)
 | |
|                                             {
 | |
|                                                 f = fontManager.MatchFamily(fn, t.FontStyle);
 | |
|                                                 if (f != null)
 | |
|                                                 {
 | |
|                                                     paint.Typeface = f;
 | |
|                                                 }
 | |
|                                                 else
 | |
|                                                 {
 | |
|                                                     paint.Typeface = t;
 | |
|                                                 }
 | |
|                                             }
 | |
|                                             else
 | |
|                                             {
 | |
|                                                 paint.Typeface = t;
 | |
|                                             }
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                             paint.Typeface = font;
 | |
|                                         }
 | |
|                                         list.Add((str, paint.MeasureText(str)));
 | |
|                                         if (f != null)
 | |
|                                         {
 | |
|                                             f.Dispose();
 | |
|                                         }
 | |
|                                     }
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     paint.Typeface = t;
 | |
|                                     list.Add((str, paint.MeasureText(str)));
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, StringUtilities.GetUnicodeCharacterCode(str, SKTextEncoding.Utf32)))
 | |
|                         {
 | |
|                             if (font == null)
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = font;
 | |
|                             }
 | |
|                             list.Add((str, paint.MeasureText(str)));
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 paint.Typeface = t;
 | |
|             }
 | |
| 
 | |
|             return list;
 | |
|         }
 | |
| 
 | |
|         internal static (int, float, string) BreakText(this IList<(string, float)> list, int start, float maxWidth, bool getText = true)
 | |
|         {
 | |
|             float w = 0;
 | |
|             int count = 0;
 | |
|             for (int i = start; i < list.Count; i++)
 | |
|             {
 | |
|                 count++;
 | |
|                 w += list[i].Item2;
 | |
|                 if (w > maxWidth)
 | |
|                 {
 | |
|                     if (i != start)
 | |
|                     {
 | |
|                         w -= list[i].Item2;
 | |
|                         count--;
 | |
|                     }
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             string text = string.Empty;
 | |
|             if (count > 0 && getText)
 | |
|             {
 | |
|                 StringBuilder sb = new StringBuilder();
 | |
|                 for (int i = start; i < start + count; i++)
 | |
|                 {
 | |
|                     sb.Append(list[i].Item1);
 | |
|                 }
 | |
|                 text = sb.ToString();
 | |
|             }
 | |
|             return (count, w, text);
 | |
|         }
 | |
| 
 | |
|         public static void DrawTextPath(this SKCanvas canvas, SKPaint paint, SKPaint border, string text, float x, float y)
 | |
|         {
 | |
|             if (!string.IsNullOrWhiteSpace(text))
 | |
|             {
 | |
|                 var fontManager = SKFontManager.Default;
 | |
|                 var t = paint.Typeface;
 | |
|                 var family = t.FamilyName;
 | |
|                 var si = new StringInfo(text);
 | |
|                 for (int i = 0; i < si.LengthInTextElements; i++)
 | |
|                 {
 | |
|                     var str = si.SubstringByTextElements(i, 1);
 | |
|                     if (str.Length != 2)
 | |
|                     {
 | |
|                         if (str != "\r")
 | |
|                         {
 | |
|                             if (t.CountGlyphs(str) == 0)
 | |
|                             {
 | |
|                                 using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, str[0]))
 | |
|                                 {
 | |
|                                     SKTypeface f = null;
 | |
|                                     if (font == null)
 | |
|                                     {
 | |
|                                         string fn = GetFontName(fontManager);
 | |
|                                         if (fn != null)
 | |
|                                         {
 | |
|                                             f = fontManager.MatchFamily(fn, t.FontStyle);
 | |
|                                             if (f != null)
 | |
|                                             {
 | |
|                                                 paint.Typeface = f;
 | |
|                                             }
 | |
|                                             else
 | |
|                                             {
 | |
|                                                 paint.Typeface = t;
 | |
|                                             }
 | |
|                                         }
 | |
|                                         else
 | |
|                                         {
 | |
|                                             paint.Typeface = t;
 | |
|                                         }
 | |
|                                     }
 | |
|                                     else
 | |
|                                     {
 | |
|                                         paint.Typeface = font;
 | |
|                                     }
 | |
|                                     using (var path = paint.GetTextPath(str, x, y))
 | |
|                                     {
 | |
|                                         canvas.DrawPath(path, border);
 | |
|                                         canvas.DrawPath(path, paint);
 | |
|                                     }
 | |
|                                     x += paint.MeasureText(str);
 | |
|                                     if (f != null)
 | |
|                                     {
 | |
|                                         f.Dispose();
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                                 using (var path = paint.GetTextPath(str, x, y))
 | |
|                                 {
 | |
|                                     canvas.DrawPath(path, border);
 | |
|                                     canvas.DrawPath(path, paint);
 | |
|                                 }
 | |
|                                 x += paint.MeasureText(str);
 | |
|                             }
 | |
|                         }
 | |
|                         else
 | |
|                         {
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         using (var font = fontManager.MatchCharacter(family, t.FontWeight, t.FontWidth, t.FontSlant, bcp47, StringUtilities.GetUnicodeCharacterCode(str, SKTextEncoding.Utf32)))
 | |
|                         {
 | |
|                             if (font == null)
 | |
|                             {
 | |
|                                 paint.Typeface = t;
 | |
|                             }
 | |
|                             else
 | |
|                             {
 | |
|                                 paint.Typeface = font;
 | |
|                             }
 | |
|                             using (var path = paint.GetTextPath(str, x, y))
 | |
|                             {
 | |
|                                 canvas.DrawPath(path, border);
 | |
|                                 canvas.DrawPath(path, paint);
 | |
|                             }
 | |
|                             x += paint.MeasureText(str);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 paint.Typeface = t;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public static Matrix ToMatrix(this SKMatrix matrix)
 | |
|         {
 | |
|             return new Matrix(matrix.ScaleX, matrix.SkewY, matrix.SkewX, matrix.ScaleY, matrix.TransX, matrix.TransY)
 | |
|             //{ Persp0 = matrix.Persp0, Persp1 = matrix.Persp1, Persp2 = matrix.Persp2 }
 | |
|             ;
 | |
|         }
 | |
|         public static SKMatrix ToMatrix(this Matrix matrix)
 | |
|         {
 | |
|             //return new SKMatrix(matrix.M11, matrix.M21, matrix.OffsetX, matrix.M12, matrix.M22, matrix.OffsetY, 0, 0, 1);
 | |
|             return new SKMatrix()
 | |
|             {
 | |
|                 ScaleX = matrix.M11,
 | |
|                 SkewX = matrix.M21,
 | |
|                 TransX = matrix.OffsetX,
 | |
|                 SkewY = matrix.M12,
 | |
|                 ScaleY = matrix.M22,
 | |
|                 TransY = matrix.OffsetY,
 | |
|                 Persp2 =1// matrix.Persp2,
 | |
|                 //Persp0 = matrix.Persp0,
 | |
|                 //Persp1 = matrix.Persp1
 | |
|             };
 | |
|         }
 | |
| 
 | |
|         public static SKPoint ToSKPoint(this Point p)
 | |
|         {
 | |
|             return new SKPoint((float)p.X, (float)p.Y);
 | |
|         }
 | |
| 
 | |
|         public static SKRect ToSKRect(this Rect r)
 | |
|         {
 | |
|             return new SKRect((float)r.X, (float)r.Y, (float)r.Right, (float)r.Bottom);
 | |
|         }
 | |
| 
 | |
|         public static Rect ToRect(this SKRect r)
 | |
|         {
 | |
|             return new Rect(r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top);
 | |
|         }
 | |
| 
 | |
|         public static SKColor ToSKColor(this Color c)
 | |
|         {
 | |
|             return new SKColor(c.R, c.G, c.B, c.A);
 | |
|         }
 | |
| 
 | |
|         //public static SKColorType ToSkColorType(this PixelFormat fmt)
 | |
|         //{
 | |
|         //    if (fmt == PixelFormat.Rgb565)
 | |
|         //        return SKColorType.Rgb565;
 | |
|         //    if (fmt == PixelFormat.Bgra8888)
 | |
|         //        return SKColorType.Bgra8888;
 | |
|         //    if (fmt == PixelFormat.Rgba8888)
 | |
|         //        return SKColorType.Rgba8888;
 | |
|         //    throw new ArgumentException("Unknown pixel format: " + fmt);
 | |
|         //}
 | |
| 
 | |
|         //public static PixelFormat ToPixelFormat(this SKColorType fmt)
 | |
|         //{
 | |
|         //    if (fmt == SKColorType.Rgb565)
 | |
|         //        return PixelFormat.Rgb565;
 | |
|         //    if (fmt == SKColorType.Bgra8888)
 | |
|         //        return PixelFormat.Bgra8888;
 | |
|         //    if (fmt == SKColorType.Rgba8888)
 | |
|         //        return PixelFormat.Rgba8888;
 | |
|         //    throw new ArgumentException("Unknown pixel format: " + fmt);
 | |
|         //}
 | |
| 
 | |
|         //public static SKShaderTileMode ToSKShaderTileMode(this GradientSpreadMethod m)
 | |
|         //{
 | |
|         //    switch (m)
 | |
|         //    {
 | |
|         //        default:
 | |
|         //        case GradientSpreadMethod.Pad: return SKShaderTileMode.Clamp;
 | |
|         //        case GradientSpreadMethod.Reflect: return SKShaderTileMode.Mirror;
 | |
|         //        case GradientSpreadMethod.Repeat: return SKShaderTileMode.Repeat;
 | |
|         //    }
 | |
|         //}
 | |
| 
 | |
|         //public static SKTextAlign ToSKTextAlign(this TextAlignment a)
 | |
|         //{
 | |
|         //    switch (a)
 | |
|         //    {
 | |
|         //        default:
 | |
|         //        case TextAlignment.Left: return SKTextAlign.Left;
 | |
|         //        case TextAlignment.Center: return SKTextAlign.Center;
 | |
|         //        case TextAlignment.Right: return SKTextAlign.Right;
 | |
|         //    }
 | |
|         //}
 | |
| 
 | |
|         //public static TextAlignment ToTextAlignment(this SKTextAlign a)
 | |
|         //{
 | |
|         //    switch (a)
 | |
|         //    {
 | |
|         //        default:
 | |
|         //        case SKTextAlign.Left: return TextAlignment.Left;
 | |
|         //        case SKTextAlign.Center: return TextAlignment.Center;
 | |
|         //        case SKTextAlign.Right: return TextAlignment.Right;
 | |
|         //    }
 | |
|         //}
 | |
|     }
 | |
| }
 | 
