.Net Core使用SkiaSharp繪製小程序分享圖

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

相關文章
相關標籤/搜索