.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

相关文章
相关标签/搜索