zoukankan      html  css  js  c++  java
  • SkiaSharp跨平台绘图研究1WPF桌面应用

    SkiaSharp跨平台绘图研究1-WPF桌面应用

    背景

    Skia首页、文档和下载 - Google 图形处理引擎 - OSCHINA - 中文开源技术交流社区

    skia是个2D向量图形处理函数库,包含字型、座标转换,以及点阵图都有高效能且简洁的表现。不仅用于Google Chrome浏览器,新兴的Android开放手机平台也采用skia作为绘图处理,搭配OpenGL/ES与特定的硬体特征,强化显示的效果

    2005SkiaGoogle收购后,一直相当神秘低调,直到2007年初,Skia GL相关的程式码才被揭露,作为Google Android平台的图形引擎,稍候的Google Chrome浏览器也采用Skia引擎。随着AndroidChrome (开放版本称为"Chromium")两大专案公布程式码后,skia也一并公开原始程式码,以Apache License v2释出(注意,这意味着与GPLv2授权不相容) ,而AndroidChrome的程式码库中都有一份[skia]的复制,因需求不同,做了部份的修改,比方说Chrome专案底下的 [chrome/trunk/src/skia],需要注意的是,Skia本身是不涉及底层环境,如Linux FramebufferGtk+衔接的处理,这也是何以Android (透过Linux Framebuffer)Chrome (开发中的Linux版本使用Gtk+)需要提供一份修改,以便系统接轨。

    SkiaSharp首页、文档和下载 - .NET 平台的跨平台 2D 图形 API - OSCHINA - 中文开源技术交流社区

    SkiaSharp 是基于 Google Skia Graphics Library .NET 平台的跨平台 2D 图形 API。可用于移动设备,服务器和桌面设备渲染图像。

    SkiaSharp 目前适用于一下平台:

    l .NET Standard 1.3

    l .NET Core

    l Tizen

    l Xamarin.Android

    l Xamarin.iOS

    l Xamarin.tvOS

    l Xamarin.watchOS

    l Xamarin.Mac

    l Windows Classic Desktop (Windows.Forms / WPF)

    l Windows UWP (Desktop / Mobile / Xbox / HoloLens)

    SkiaSharp是一个强大跨平台绘图框架,我曾经用SkiaSharpWPF、安卓Xamarin.Forms客户端绘图,也用来创建过PDF绘图,但是由于它不支持网页绘图,所以总觉得很遗憾,因为目前主流的浏览器都是谷歌Chrom内核,谷歌为什么不支持自家的Skia在网页直接绘图呢?如果SkiaSharp可以直接在网页绘图,那它就是跨越全平台的绘图框架了。

    终于到了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!

    受此鼓舞,决定写一个系列文章,汇总SkiaSharp在各个平台上的绘图方法。

    创建WPF项目

    使用VS2022 prewview6.0工具,其实对于WPF项目而言,VS2019完全足够的。

    NuGet安装SkiaSharp.Views.WPF,当前最新版本是2.88.0-preview.152

    简单地添加一个按钮和SkiaSharp画布容器。

    <Window x:Class="WpfDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfDemo" 
            xmlns:skia="clr-namespace:SkiaSharp.Views.WPF;assembly=SkiaSharp.Views.WPF"
            mc:Ignorable="d"
            Title="MainWindow" Height="400" Width="450">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Button x:Name="btnRefresh" Content="绘图" Grid.Row="0" Width="100" Margin="4"></Button>
            <Grid Grid.Row="1" Margin="4" Height="300">
                <skia:SKElement x:Name="skContainer">
                </skia:SKElement>
            </Grid>
        </Grid>
    </Window>

    编写一点代码

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                btnRefresh.Click += BtnRefresh_Click;
    
                skContainer.PaintSurface += SkContainer_PaintSurface;
            }
    
            private void BtnRefresh_Click(object sender, RoutedEventArgs e)
            {
                Debug.WriteLine($"{DateTimeOffset.Now}, 刷新画布");
    
                //强制画布重绘,有些开发环境InvalidateVisual不会触发调用OnRender
                skContainer.InvalidateVisual();
            }
    
            private void SkContainer_PaintSurface(object? sender, SkiaSharp.Views.Desktop.SKPaintSurfaceEventArgs e)
            {
                var canvas = e.Surface.Canvas;
    
                canvas.Clear(SKColors.SkyBlue);
    
                using var paint = new SKPaint
                {
                    Color = SKColors.Black,
                    IsAntialias = true,
                    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={skContainer.CanvasSize}";
                Debug.WriteLine(msg);
    
            }
        }

    测试SkiaSharp绘图

    测试发现,点击绘图按钮,画布内容并没有更新!我以前用得好好的,怎么突然就不行了?在另外一台电脑上用VS2019创建了一个net 5.0WPF桌面软件,还是用上述代码,运行完全没问题!那么就是开发环境的问题,老司机都知道,Windows的开发环境对桌面软件有一些匪夷所思的影响,这也是微软桌面开发环境带给.Net开发者多年的痛苦。

    运行效果正常的开发环境

    dotnet --info

    .NET SDK (反映任何 global.json):

     Version:   5.0.300

     Commit:    2e0c8c940e

    运行时环境:

     OS Name:     Windows

     OS Version:  10.0.18363

     OS Platform: Windows

     RID:         win10-x64

     Base Path:   C:\Program Files\dotnet\sdk\5.0.300\

    Host (useful for support):

      Version: 5.0.6

      Commit:  478b2f8c0e

    .NET SDKs installed:

      2.2.402 [C:\Program Files\dotnet\sdk]

      5.0.102 [C:\Program Files\dotnet\sdk]

      5.0.300 [C:\Program Files\dotnet\sdk]

    .NET runtimes installed:

      Microsoft.AspNetCore.All 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

      Microsoft.AspNetCore.All 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]

      Microsoft.AspNetCore.App 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.AspNetCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.AspNetCore.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.AspNetCore.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.NETCore.App 2.1.28 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.NETCore.App 2.2.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.NETCore.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.NETCore.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.WindowsDesktop.App 3.1.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

      Microsoft.WindowsDesktop.App 5.0.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

    To install additional .NET runtimes or SDKs:

      https://aka.ms/dotnet-download

    运行效果异常的开发环境

    dotnet --info

    .NET SDK (反映任何 global.json):

     Version:   6.0.100-rc.2.21505.57

     Commit:    ab39070116

    运行时环境:

     OS Name:     Windows

     OS Version:  10.0.19042

     OS Platform: Windows

     RID:         win10-x64

     Base Path:   C:\Program Files\dotnet\sdk\6.0.100-rc.2.21505.57\

    Host (useful for support):

      Version: 6.0.0-rc.2.21480.5

      Commit:  6b11d64e7e

    .NET SDKs installed:

      5.0.402 [C:\Program Files\dotnet\sdk]

      6.0.100-rc.2.21505.57 [C:\Program Files\dotnet\sdk]

    .NET runtimes installed:

      Microsoft.AspNetCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.AspNetCore.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.AspNetCore.App 6.0.0-rc.2.21480.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]

      Microsoft.NETCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.NETCore.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.NETCore.App 6.0.0-rc.2.21480.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]

      Microsoft.WindowsDesktop.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

      Microsoft.WindowsDesktop.App 5.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

      Microsoft.WindowsDesktop.App 6.0.0-rc.2.21501.6 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

    To install additional .NET runtimes or SDKs:

      https://aka.ms/dotnet-download

    对于异常的开发环境,可以通过改变窗口大小,强制引发重绘,看到画布内容刷新。

    解决中文显示问题

    SkiaSharp要创建中文字体,才能显示中文,这也是个麻烦,为什么不能自动从操作系统获取Unicode字库呢?为了减少安装包体积,选用体积小的DroidSansFallback.ttf字库文件。

    /// <summary>
        /// Skia中文字体
        /// </summary>
        public static class SkiaChinaFont
        {
            public static SKTypeface ChinaFont { get; private set; }
    
            static SkiaChinaFont()
            {
                //加载字体资源文件方案,需要把字体文件复制运行目录下,设置文件属性为如果较新则复制
                string fontPath = Path.Combine(AppContext.BaseDirectory, "DroidSansFallback.ttf");
                ChinaFont = SKTypeface.FromFile(fontPath);
            }
        }

    显示文字代码增加中文字体即可

    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);

    最终结果如图

     

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

  • 相关阅读:
    Vue源码探究-数据绑定的实现
    vue 数组遍历方法forEach和map的原理解析和实际应用
    vue 微信内H5调起支付
    uni-app官方教程学习手记
    vue-cli3 搭建的前端项目基础模板
    vue.js响应式原理解析与实现
    vue-waterfall2 基于Vue.js 瀑布流组件
    解决lucene更新删除无效的问题
    spring项目启动报错
    js监听页面copy事件添加版权信息
  • 原文地址:https://www.cnblogs.com/sunnytrudeau/p/15515080.html
Copyright © 2011-2022 走看看