1、前言git
最近因業務須要開發了一款地產類微信小程序,開發的過程當中須要實現分享給好友和分享到朋友圈的功能。好友分享能夠直接調用微信小程序API來實現,調用時需提供一張5:4的圖片,若是不提供則使用默認截圖,爲了更好的效果咱們通常會選擇自行生成圖片。而分享到朋友圈的功能因爲小程序並未開放,則須要咱們生成一張長圖供用戶自行發送朋友圈。下面我以生成好友好享圖片爲例來說講如何在.Net Core環境中使用SkiaSharp繪製圖片。github
(圖1:最終效果圖)數據庫
2、SkiaSharp類庫介紹canvas
SkiaSharp是一個基於Google的Skia圖形庫(https://skia.org/)打造的供.Net平臺使用的跨平臺的2D繪圖API類庫。它提供一個全面的2D繪圖API,能用在移動端、服務端和桌面端呈現圖像。小程序
目前SkiaSharp可供如下平臺使用:微信小程序
- .NET Standard 1.3
- .NET Core
- Tizen
- Xamarin.Android
- Xamarin.iOS
- Xamarin.tvOS
- Xamarin.watchOS
- Xamarin.Mac
- Windows Classic Desktop (Windows.Forms / WPF)
- Windows UWP (Desktop / Mobile / Xbox / HoloLens)
github地址:https://github.com/mono/SkiaSharpapi
3、準備工做微信
一、新建一個.Net Core API項目,這裏我命名爲ShareImage。字體
二、安裝SkiaSharp,使用NuGet命令或者包管理器安裝:優化
nuget install SkiaSharp
三、準備底圖
分析最終效果圖(圖1),找出不會變化的部分,讓UI摳下來做爲底圖。能夠將底圖保存在項目的Images目錄下,我這裏存爲bg.png。
(圖2:底圖)
四、準備字體
我這裏中文部分用了PingFangSC Regular字體,數字部分用了PingFangSC Medium字體。在項目根目錄下新建Fonts目錄,複製這兩種字體,我這裏分別命名爲PIngfangScRegular.ttf和PingfangScMedium.ttf。因爲載入字體是一個耗時的操做,所以咱們能夠定義一個靜態類TypeFace,預先將字體載入。
using SkiaSharp; namespace ShareImage { public static class Typeface { public static TypefaseWithMuiltWeight PingFang = new TypefaseWithMuiltWeight { Regular = SKTypeface.FromFile("Fonts/PIngfangScRegular.ttf"), Medium = SKTypeface.FromFile("Fonts/PingfangScMedium.ttf") }; } public class TypefaseWithMuiltWeight { public SKTypeface Regular { get; set; } public SKTypeface Medium { get; set; } } }
4、繪圖
一、讀取要寫入的數據,通常這類數據從數據庫讀取,這裏我直接定義示例數據
//示例數據 var shop = new ShopInfo { Name = "李學雯", Company = "某某地產", ViewNum = "1024", Nums = new string[] { "128", "64", "96", "48" }, Location = "廣州市-黃埔區", Des = "專業爲大宗資產提供中介、法律、會計服務,買賣廠房、倉庫、土地請找咱們爲您提供更專業更安心的服務" };
二、載入底圖並初始化畫布
//載入底圖 var bmp = SKBitmap.Decode("Images/cardShopBg.png"); //初始化畫布 var canvas = new SKCanvas(bmp);
三、畫頭像
//保存當前畫布狀態,即正常全圖繪製狀態 canvas.Save(); //定義圓形頭像路徑 var avatarPath = new SKPath(); avatarPath.AddCircle(114, 120, 70); //在當前畫布上剪切出頭像路徑,做爲當前繪製區域 canvas.ClipPath(avatarPath, SKClipOperation.Intersect, true); //載入頭像圖片,這裏用Images/avatar0.jpg文件代替 using (var avatarImage = SKImage.FromEncodedData(SKData.Create("Images/avatar0.jpg"))) { //定義繪製頭像的位置和尺寸 var rect = SKRect.Create(44, 50, 140, 140); //繪製頭像 canvas.DrawImage(avatarImage, rect); } //恢復畫布狀態爲全圖繪製狀態 canvas.Restore();
因爲頭像是圓形,而咱們獲取到的頭像通常是方形,因此咱們須要在底圖上定義一個圓形區域做爲本次畫圖的區域,在繪製完成後須要恢復爲全圖繪製狀態,不然就沒法繼續接下來的寫字等操做了。
四、寫單行文本(以姓名爲例)
//定義畫筆 using (var paint = new SKPaint()) { //字體 paint.Typeface = Typeface.PingFang.Regular; //字體大小 paint.TextSize = 48; //字體顏色 paint.Color = SKColors.White; //抗鋸齒不能少 paint.IsAntialias = true; //調用畫單行文字擴展方法 canvas.DrawSingleLineText(shop.Name, 225, 62, paint); } //畫單行文字擴展方法 public static void DrawSingleLineText(this SKCanvas canvas,string text,float x,float y,SKPaint paint) { //定義一個矩形,此矩形爲計算文字區域的結果 var tRect = new SKRect(); //計算文字佔用區域 paint.MeasureText(text, ref tRect); //調用畫布的畫字方法 canvas.DrawText(text, x - tRect.Left, y - tRect.Top, paint); }
寫文字的時候須要注意有一個座標編移量,能夠直接調用canvas.DrawText(text, 0, 0, paint)來觀察一下,寫出文字的起點並不是是0,0。因此咱們在寫出文字的時候要算出這個偏移量並抵消掉。這個偏移量是如何產生的本人並不知道,若是有熱心網友能幫忙解答一下就行了!
五、畫帶色矩形背景框(見圖1公司名「某某地產」黃色矩形背景)
//定義畫筆 using (var paint = new SKPaint()) { //字體 paint.Typeface = Typeface.PingFang.Regular; //字體大小 paint.TextSize = 26; //抗鋸齒 paint.IsAntialias = true; //顏色 paint.Color = SKColor.Parse("#FFB33E"); //因爲這個黃色背景矩形長度是根據文字長度而定的,因此咱們須要計算文字的區域大小 var tRect = new SKRect(); //文字長度 var tWidth = paint.MeasureText(shop.Company,ref tRect); //矩形背景區域 var rect = SKRect.Create(224, 134, tWidth + 20, 40); //畫矩形 canvas.DrawRect(rect, paint); }
六、寫多行文字。因爲本人並未在SkiaSharp文檔中找到寫多行文字的方法,因此寫一個擴展方法來寫出多行文字:
/// </summary> /// <param name="canvas">畫布</param> /// <param name="text">多行文字</param> /// <param name="x">x座標</param> /// <param name="y">y座標</param> /// <param name="paint">畫筆</param> /// <param name="maxWidth">單行文字最大寬度</param> /// <param name="maxLines">最大行數,若是超出,則使用...</param> public static void DrawMuiltLineText(this SKCanvas canvas, string text, float x, float y, SKPaint paint, float maxWidth, int maxLines) { //已寫出行數 int lines = 0; //省略號寬度 var ellipseWidth = paint.MeasureText("..."); //若是文字沒寫完且已寫行數小於最大行數,則繼續寫出 while (!string.IsNullOrEmpty(text) && lines < maxLines) { //單行文字 string lineStr; //單行文字長度 long strLength; //非最後一行 if (lines != maxLines - 1) { //調用BreakText方法,可計算指定寬度能寫出多少文字 strLength = paint.BreakText(text, maxWidth, out float ww, out lineStr); } //最後一行 else { //調用BreakText方法計算單行文字長度,這裏需減去省略號寬度 strLength = paint.BreakText(text, maxWidth - ellipseWidth, out float ww, out lineStr); //假如字還沒寫完,需加省略號 if (strLength < text.Length) { lineStr += "..."; } } //文字矩形 var tRect = new SKRect(); //計算文字矩形 paint.MeasureText(lineStr, ref tRect); //計算座標 var tPoint = new SKPoint { X = x - tRect.Left, //這裏注意Y座標須要加上行高 Y = y + lines * paint.FontSpacing - tRect.Top }; //寫出一行文字 canvas.DrawText(lineStr, tPoint, paint); //已寫出行數加1 lines++; //取剩餘文字 text = text.Substring((int)strLength); } }
5、總結
SkiaSharp是一個很是強大且易用的.Net平臺繪圖庫,這裏以繪製小程序分享圖爲例僅列出一些基礎用法。因爲本人水平有限,以上代碼若有紕漏、錯誤或有待優化之處,歡迎你們指出!
附SkiaSharp文檔地址:https://docs.microsoft.com/en-us/dotnet/api/SkiaSharp