SkiaSharp跨平台绘图研究5-Blazor WebAssembly网页绘图

SkiaSharp跨平台绘图研究5-Blazor WebAssembly网页绘图

20211012日,.NET 6发布RC2候选版本(正式发布前最后一版),宣布了一个突破性的技术:支持在Web网页上采用SkiaSharp画布绘图。这是.NET跨平台技术发展的一个创举,使用C#可以直接在网页画布上绘图,打破了JavaScript+canvas的长期垄断地位。C#是强类型语言,可以无缝对接从服务端获取的结构化数据,有效提高开发效率和质量。

ASP.NET Core updates in .NET 6 Release Candidate 2 - ASP.NET Blog (microsoft.com)

SkiaSharp is a cross-platform 2D graphics library for .NET based on the native Skia graphics library, and it now has preview support for Blazor WebAssembly. Let’s give it a try!

 

目前VS2022正式版和NET 6正式版都已经发布,SkiaSharpBlazor WebAssembly的支持仍然处于预览状态。

 

创建Blazor WebAssembly项目

选择项目类型Blazor WebAssemblyNET 6.0平台,带托管主机,我是习惯了容器化部署方式,有个后台服务器部署起来顺手一点。

 

修改服务端项目program.cs,绑定端口和域名证书。

 

using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using System.Net;

namespace WebBlazorDemo.Server;

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        builder.WebHost.ConfigureKestrel(ConfigHttps);

        // Add services to the container.

        builder.Services.AddControllersWithViews();
        builder.Services.AddRazorPages();

        var app = builder.Build();

        // Configure the HTTP request pipeline.
        if (app.Environment.IsDevelopment())
        {
            app.UseWebAssemblyDebugging();
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        app.UseBlazorFrameworkFiles();
        app.UseStaticFiles();

        app.UseRouting();


        app.MapRazorPages();
        app.MapControllers();
        app.MapFallbackToFile("index.html");

        //app.Run();
        await app.RunAsync();
    }

    private static void ConfigHttps(WebHostBuilderContext context, KestrelServerOptions options)
    {
        //http服务端口
        options.Listen(IPAddress.Any, 7902);

        //https服务端口
        options.Listen(IPAddress.Any, 7903, configure);

        void configure(ListenOptions listenOptions)
        {
            if (context.HostingEnvironment.IsProduction())
            {
                //填入pfx文件路径和指定的密码
                listenOptions.UseHttps("myweb.pfx", "xxx");
            }
            else
            {
                //本机调试必须采用默认localhost证书,否则无法建立ssl连接
                listenOptions.UseHttps();
            }
        }
    }
}

 

给客户端项目NuGet安装SkiaSharp.Views.Blazor,现在最新版是2.88.0-preview.155

给主页添加绘图代码,跟WPF基本一样。

 

@page "/"
@using SkiaSharp.Views.Blazor
@using SkiaSharp

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

<button class="btn btn-primary m-1" @onclick="OnClickImg" type="button">更新绘图</button>
<br />

<SKCanvasView OnPaintSurface="OnPaintSurface" style="width:480px; height:240px" @ref="canvasView" @onclick="OnClickImg" />

@code {

    //private ElementReference canvasView;//这个参数无法转换类型为SKCanvasView
    private SKCanvasView canvasView;

    private void OnClickImg()
    {
        //引发画布更新绘图
        canvasView.Invalidate();
    }

    void OnPaintSurface(SKPaintSurfaceEventArgs e)
    {
        var canvas = e.Surface.Canvas;

        canvas.Clear(SKColors.SkyBlue);

        using var paint = new SKPaint
            {
                Color = SKColors.Black,
                IsAntialias = true,
                Typeface = SkiaChinaFont.ChinaFont,
                TextSize = 24
            };

        string msg = $"{DateTimeOffset.Now:T}, 还有1万行Skia绘图代码...";
        canvas.DrawText(msg, 0, 30, paint);

        using var linePaint = new SKPaint()
            {
                Color = (DateTimeOffset.Now.Second % 4 <= 1) ? SKColors.Red : SKColors.Green,
                Style = SKPaintStyle.Stroke,//不填充
                StrokeWidth = 3,
            };
        canvas.DrawRect(10, 50, e.Info.Width - 20, e.Info.Height - 60, linePaint);

        msg += $", linePaint.Color={linePaint.Color}, skContainer.CanvasSize={e.Info.Size}";
        Console.WriteLine(msg);

    }
}

 

同样要添加中文字体类,注意要设置字体文件为嵌入的资源。

using SkiaSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace WebBlazorDemo.Client;

/// <summary>
/// Skia中文字体
/// </summary>
public static class SkiaChinaFont
{
    public static SKTypeface ChinaFont { get; private set; }

    static SkiaChinaFont()
    {
        //加载资源方案,设置字体文件属性为嵌入的资源
        var fontStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("WebBlazorDemo.Client.DroidSansFallback.ttf");
        ChinaFont = SKTypeface.FromStream(fontStream);
    }
}

我在安装VS2022的时候没有添加wasm-tools工作负载,所以会编译Blazor WebAssembly报错,在命令行运行dotnet workload install wasm-tools即可添加。然后跑起来看一下,如愿以偿!在网页上用C#绘图,终于等到了。

 

发布服务端项目到腾讯云CentOS操作系统容器里测试,跟本机测试一样结果,没有什么依赖库。

 

 

展望

网页前端开发主要就是Html + Css + JavaScript三板斧,基于三板斧不断封装也发展出了ReactVueAngular等集成框架,但是前后端数据交互通常要做很多变换处理,毕竟前后端语言的数据类型不一样。Blazor框架把C#强类型语言推进到前端网页开发,打通了前后端统一框架和语言的技术路线,这是非常了不起的突破。Blazor开发常规的表单、导航网页功能都已经非常好用了,但是一旦涉及绘图,仍然要借助JavaScript语言去实现,实在是一个遗憾。

不过从现在开始,C#也可以在Html网页SkiaSharp画布上绘图了,消除了C#前端开发最后一个屏障。但是,仅有绘图功能是远远不够的,Html生态圈中有海量高质量、开源的图形插件,例如ECharts,把模板选好,再放入数据,就能出来光鲜亮丽的图表,并且拥有非常丰富的滚动,缩放,悬停,选取等交互能力。SkiaSharp画布要走的路还很长,希望将来能构建起一个新的生态圈。

 

 

DEMO源代码参见:https://gitee.com/woodsun/skia-sharp-demo

 

posted on 2021-11-18 21:02  SunnyTrudeau  阅读(2973)  评论(2编辑  收藏  举报