背景
处理和渲染sketch文件目前比较主流的方式有两种,一种是安装sketch插件,基于 Sketch插件相对容易拿到设计稿确定性的信息,借助插件里提供的sketch环境和api进行底图渲染,这种方式大多实现方案一致,主要还是依赖于sketch,基于其自身提供的能力。还有另外一种就是无需安装sketch插件直接在在浏览器中渲染,得益于新型编程语言WebAssembly和Emscripten提供的胶水能力,可将Skia的图形API导出到Web平台,CanvasKIt便是其编译导出到web平台的产物,开发者可利用CanvasKit提供的图形绘制接口在浏览器提供的画布(canvas)上进行绘制和渲染。
WebAssembly 是什么
这里直接引用了维基百科 的介绍:
WebAssembly或称wasm是一个实验性的低级编程语言,应用于浏览器内的客户端。WebAssembly是便携式的抽象语法树,被设计来提供比JavaScript更快速的编译及执行。WebAssembly将让开发者能运用自己熟悉的编程语言(最初以C/C++作为实现目标)编译,再藉虚拟机引擎在浏览器内执行。WebAssembly 于 2019 年 12 月 5 日成为万维网联盟(W3C)的推荐,与 HTML,CSS 和 JavaScript 一起,成为 Web 的第四种语言
从上述可知wasm是一种新型的web编程语言,开发者可以利用自己所熟悉的编程语言(比如这两年大火的rust)编译,允许浏览器访问相同功能的Javascript API 。由于其轻量级的虚拟机设计,WebAssembly 程序具有效率高,速度快的特点。 后续有时间会专门写篇关于wasm的文章,以及如何借助EmscriptenSDK的能力将一些c++ nvtive库编译为WASM文件迁移到web平台。
初识Skia
Skia是个2D向量图形处理函数库,包含字型,坐标、以及点阵图都有高效能且简洁的表现,不仅用于Google Chrome浏览器,在移动端也采用skia作为绘图处理,强化显示的效果。
c++ skia library 可以编译到 WebAssembly ,共享到浏览器端(应用条件比客户端相对严格一些)或桌面端(比如 Electron)。skia中常用的关键类如下所示:
SkAutoCanvasRestore - Canvas save stack manager
SkBitmap - two-dimensional raster pixel array
SkBlendMode - pixel color arithmetic
SkCanvas - drawing context
SkColor - color encoding using integer numbers
SkFont - text style and typeface
SkImage - two dimensional array of pixels to draw
SkImageInfo - pixel dimensions and characteristics
SkIPoint - two integer coordinates
SkIRect - integer rectangle
SkMatrix - 3x3 transformation matrix
SkPaint - color, stroke, font, effects
SkPath - a path encapsulates compound (multiple contour) geometric paths consisting of straight line segments, quadratic curves, and cubic curves
SkPicture - sequence of drawing commands
SkPixmap - pixel map: image info and pixel address
SkPoint - two floating point coordinates
SkRRect - floating point rounded rectangle
SkRect - floating point rectangle
SkRegion - compressed clipping mask
SkSurface - drawing destination
SkTextBlob - runs of glyphs
SkTextBlobBuilder - constructor for runs of glyphs
CanvaKit是什么
首先去看下CanvasKit官网(https:// skia.org/docs/user/modu les/canvaskit/ )介绍:Skia now offers a WebAssembly build for easy deployment of our graphics APIs on the web.。大致意思是canvaskit运用WebAssembly的构建技术来将skia图形渲染能力的API扩展到web上,也就是说CanvasKit项目是skia的WebAssembly版本,对于前端应用而言,canvaskit提供了图形接口,前端开发者可调用其图形绘制API进行图形绘制。
如何使用
CanvasKit整体使用流程如下,接下来会基于流程顺序进行一步步介绍
先来看下如何引入,首先引用用于初始化CanvasKit的函数,该函数接收一个包含canvaskit-wasm文件的对象,异步加载完文件后,将返回值注入到前端js运行的环境,这样前端开发者就可调用绘制相关的api。
const CanvasKitInitFn = require('@skeditor/canvaskit-wasm');
const CanvaskitPromised = (CanvasKitInitFn as any)({
// 加载canvaskit.wasm文件
locateFile: () => '//view.didistatic.com/static/dcms/do1_w5ALGTmj4rnUMFnFT8SD',
}).then((CanvasKitRes) => {
// 前端js运行环境中注入canvaskit对绘制支持的依赖
sk.CanvasKit = CanvasKitRes;
return sk.CanvasKit;
}) as Promise<CanvasKit>;
核心对象SkCanvas 在canvasKIt注入到js环境之后,接下来调用MakeOnScreenGLSurface方法创建画布载体surface,然后引入在其载体上进行画图的skCanvas对象。具体操作如下:const canvasEl = document.getElementById('canvas'); // 绑定绘制的上下文 const webGLContexsk.CanvasKit.GetWebGLContext(canvasEl) const glContext = sk.CanvasKit.MakeGrContext(webGLContexsk); const surface = sk.CanvasKit.MakeOnScreenGLSurface( glContext, canvasEl.width, canvasEl.height, sk.CanvasKit.ColorSpace.SRGB ); const skCanvas = surface.getCanvas();
skCanvas是skia的核心对象和绘图上下文,常用的逻辑和渲染操作都是围绕着该对象进行处理的,并且提供了很多绘制图像的命令,通常是draw+具体layer。常用的api如下所示;drawRect绘制图像或矩形、drawPath绘制不规则图像、drawText绘制文本、drawImageRect从提供的图像中绘制子矩形、drawParagraph在给定的坐标处绘制提供的段落。结构图如下所示:
skCanvas知道图形将在哪里进行绘制,layer表示具体要画的是什么,paint是告诉画布如绘制。比如skCanvas.drawPath(path, paint)这个api,上述的代码会做如下操作;在给定的画布上绘制路径path,paint告诉画布如何绘制这个path,及该path的属性和状态,比如画笔的宽度,颜色,是否有填充和渐变果、居中对齐、内外边界对齐,节点的样式等等。 skCanvas的主要提供两种功能,一是指向正在绘制的实际像素,和web页面的canvas绑定,二是维护一组矩阵状态和剪辑区域。 矩阵决定当前绘制的几何变换,矩阵状态通常是矩形在经过skew、scale、translate等操作后,坐标会发生变换。变换矩阵(transform matrix,在绘制的过程中会涉及到这方面的计算和转换)的状态由一组标准的 3 x 3 变换矩阵进进维护,该结构定义了九种类型的读写属性,如下所示: | ScaleX SkewY Persp0 | | SkewX ScaleY Persp1 | | TransX TransY Persp2 | 裁剪(clips)区域是指在经过剪辑操作之后,画布的当前剪辑可能会限制矩形在画布上的绘制位置,即裁剪决定当前绘制的生效范围,常用的方法有clipRect、clipRRect、clipPath、clipRegion,通常矩阵的裁剪伴随着矩阵状态的保存与恢复,状态相关的api有:save、saveLayer、restore等。在每个SkCanvas中的调用draw+layer方法时,会通过所有SkMatrix值的串联来变换对象的几何形状, 通过所有裁剪区域的交集来裁剪变换后的图形的现实区域。下面通过同一设计稿在设置裁剪与否的情况下来介绍矩阵状态的保存和恢复。
这里暂不涉及合适进行裁剪的逻辑判断,仅仅看裁剪前后的结果,上边的图是未裁剪前,高度明显向下溢出 ,下边的是裁剪后的,与设计稿ui一致。这里主要就是根据计算指定了绘制的height,使其保持正常高度。该操作通常需要下面四个步骤,首先保存当前skCanvas对象的状态,接下来进行裁剪操作,设置裁剪的坐标、区域和方式、然后在裁剪区域进行绘制、最后恢复之前的状态。这样设置裁剪的状态只在画此文本段落时生效,因为在在画完之后,又恢复了之前状态,如果不进行恢复的话,会依然在裁剪区域绘制,那接下来的绘制肯定就得不到正确的图形了。 // 保存当前画布状态 skCanvas.save() // 裁剪操作,指定绘制的区域和位置 skCanvas.clipRect(Rect,sk.CanvasKit.ClipOp.Intersect, true); // 调用draw相关api进行绘制 skCanvas.drawParagraph(para, baseX, baseY); // 恢复剪裁区域之前的状态 skCanvas.restore() 绘制 上面已经讲过,最终在调用draw相关的api时,需要知道paint的设置和要画的具体组件类型,下面会从paint的设置和组件的构建两部分讲述,通过一个小demo来体验下CanvasKit的使用方式。 创建paint对象 const paint = new CanvasKit.Paint(); paint设置颜色、样式、笔画、抗锯齿等属性 paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0)) paint.setStyle(CanvasKit.PaintStyle.Stroke); paint.setStrokeWidth(6) paint.setAntiAlias(true); 创建layer、这里创建了坐标为(5,5),宽高为100的矩形,也可以创建path、paragranph等const rect = CanvasKit.XYWHRect(5, 5, 100, 100) 这里是最后一步,在指定的cavas上开始绘制矩形,surface执行flush skCanvas.drawRect(this .frame.offset(offsetX, offsetY).toSk(), paint); surface.flush() 这只是使用canvasKit最简单小demo,更多CanvasKit的使用方式请关注后续文章 参考文献 Skia官方文档:https:// api.skia.org/classSkSur face.html#details CanvasKit 官方文档:https:// skia.org/docs/user/modu les/canvaskit/ Webassembly 维基百科:https:// ms.wiki.fallingwaterdesignbuild.com /wiki/WebAssembly SkiaSharp: https:// docs.microsoft.com/zh-c n/dotnet/api/skiasharp?view=skiasharp-2.80.2 Canvas中的裁剪区域:https:// blog.csdn.net/syc434432 458/article/details/52858180?locationNum=3&fps=1 图形矩阵转换:https://blog.51cto.com/u_15127627/4261