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