skia draw

2024-01-24 01:08
文章标签 draw skia

本文主要是介绍skia draw,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近终于有时间去看skia draw的一些过程,参考skia/gm和skia/samplecode里面的示例非常粗略的总结了一下skia的绘制过程,只能说建立一个概览吧。希望有熟悉skia的大神在不对之处可以帮忙指点。


skia的每次绘制都是由canvas.drawXX方法发起,经过path generation、rasterizer、shading和transfer四个步骤完成一张图的绘制。

Path generation

在skia绘制管线中,第一步工作就是要生成SkPah。所谓path,字面上讲是绘制路径,其实就是绘制形状。这部分工作可以分为三个阶段去完成:
第一阶段:初始化path。可以使用SkPath的moveTo(),lineTo(),conicTo(),quadto()等方法手动绘制线段、二次曲线等,以此来绘制物体的轮廓;也可以使用canvas的draw api来绘制矩形、椭圆等形状完成轮廓绘制。
第二阶段:为path添加效果。skia支持的效果有:添加线宽、corner、虚线、DiscretePath、1Dpath、2Dpath等。这部分可以参考pathEffect.cpp。
第三阶段:使用SkPath的setStyle()方法确定path的风格。
enum Style {kFill_Style,            //!< fill the geometry填充kStroke_Style,          //!< stroke the geometry绘制轮廓kStrokeAndFill_Style,   //!< fill and stroke the geometry};

Rasterizer

生成path之后的工作就是要去rasterizer。skia中的rasterizer主要是确定像素要画在哪,这通过使用一个mask图像来完成。mask图像实际上是一个只有alpha通道的灰度图。mask图像可以决定每个像素是全透明、不透明还是部分透明。

可以使用两个方法生成mask:

(1)no rasterizer

使用paint style property和path property进行path扫描转换,产生一个初始的mask。在path内部的像素是不透明的,path外部的像素保持透明,在path边界上的像素部分透明(如果设置anti-aliasing抗锯齿)。

如果设置了maskFilter,初始的mask会根据它进行变换,比如blur、emboss、table等效果。设置步骤为:首先使用SkPaint方法setMaskFilter()为paint分配一个SkMaskFilter;然后具体的mask过滤由SkMaskFilter子类实现。

对于blur效果,可以参考sampleBlur.cpp。

emboss效果,可以参考sampleEmboss.cpp。

(2)rasterizer

由SkRasterizer创建一个mask。

首先使用SkPaint的方法setRasterizer()为paint设置一个SkRasterizer;然后SkRasterizer的rasterize()方法会创建一个mask bitmap,之后把path绘制到这个mask中。

Shading

rasterizer之后就需要进行shading。shading的主要工作是确定像素的颜色,即着色。skia主要支持四种shader:线性梯度shader、环形梯度shader、扫略梯度shader以及混合shader。混合shader用来处理使用两种相同或者不同的shader在xfermode下的混合着色。这部分可以参考sampleShader.cpp例子。

着色过程有两个阶段:第一个阶段是为SkPaint分配一个SkShader,同样也是使用SkPaint的setShader方法。SkShader会生成一个初始的源图像。

在创建shader时,需要指定平铺模式(TileMode),有三种:kClamp_TileMode、kRepeat_TileMode和kMirror_TileMode,分别对应普通平铺、重复平铺和镜像平铺。镜像平铺很好理解,对于普通平铺,如果shader超出着色边界,则会使用边界的颜色延伸到bitmap边界;对于重复平铺,如果shader超出着色边界,则会在边界处重复之前的着色。

如果在这个阶段没有设置SkShader,则需要给paint设置一个color,此时会产生一张单色图像。


第二个阶段:如果为Skpaint设置了colorFilter,则colorFilter会为初始源图像的颜色进行变换。maskFilter与colorFilter不同:maskFilter是对一个paint的alpha通道的转换;而colorFilter是针对RGB通道的转换。所有由colorFilter所派生的类在执行它们的转换时都会忽略alpha通道。

(1)colorFilter可以通过改变colorMatrix进行色彩变换(C1=pin(C*Cm+Ca))。

a ,b ,c, d, e,

f ,g ,h ,i , j,

k ,l, m, n, o,

p ,q ,r ,s ,t

颜色矩阵M的第一行参数abcde决定了图像的红色成分,第二行参数fghij决定了图像的绿色成分,第三行参数klmno决定了图像的蓝色成分,第四行参数pqrst决定了图像的透明度,第五列参数ejot是颜色的偏移量。在Android中,对图像进行颜色方面的处理,如黑白老照片、泛黄旧照片、高对比度、低饱和度等效果,都可以通过使用颜色矩阵(ColorMatrix)来实现。
这部分的例子可以参考colorFilters.cpp。

(2)colorFilter也可以通过处理各种XforMode(图像混合模式)来针对dst/src图像进行色彩处理。

这部分的例子可以参考sampleColorFilters.cpp。

Transfer

这部分的工作是Transferring color to the destination Bitmap。我理解为把由rasterizer生成的mask、shader生成的源color图像、XferMode和目的图像进行混合处理,然后把最终的图像搬移到目的bitmap中。这部分也分为两个阶段进行:
第一阶段:把shader生成的源color图像与目的图像使用XferMode生成中间图像。
对于XferMode,我的理解是一种图像的混合模式,它主要有以下模式:
<pre name="code" class="cpp"><pre name="code" class="cpp"><span style="font-family:Microsoft YaHei;">/* Sa 代表source alpha ,即源 alpha 值 ,
Da 代表 Destination alpha ,即 目标alpha值 ,
Sc 代表 source color ,即源色值 ,
Dc 代表 Destination color ,即目标色值,并且这所有的计算都以像素为单位.
[a, c]代表在某一种混合模式下,对每一个像素的alpha 和 color 通过对应算法进行运算,所得出的像素值*/
enum Mode {kClear_Mode,    //!< [0, 0]清除模式[0,0],即最终所有点的像素的alpha 和color 都为 0,所以画出来的效果只有白色背景kSrc_Mode,      //!< [Sa, Sc]只保留源图像的 alpha 和 color ,所以绘制出来只有源图kDst_Mode,      //!< [Da, Dc]同上类比,只保留目标图像的 alpha 和 color,所以绘制出来的只有目标图kSrcOver_Mode,  //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc]在目标图片顶部绘制源图像,从命名上也可以看出来就是把源//图像绘制在上方kDstOver_Mode,  //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc]将目标图像绘制在上方kSrcIn_Mode,    //!< [Sa * Da, Sc * Da]在两者相交的地方绘制源图像,并且绘制的效果会受到目标图像对应地方透明度的影响kDstIn_Mode,    //!< [Sa * Da, Sa * Dc]在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)]在不相交的地方绘制源图像,相交处根据目标alpha进行过滤,目标色完全//不透明时则完全过滤,完全透明则不过滤kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)]类似上面kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]源图像和目标图像相交处绘制源图像,不相交的地方绘制目标图像,并且相//交处的效果会受到源图像和目标图像alpha的影响kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]类似上面kXor_Mode,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]在不相交的地方按原样绘制源图像和目标图像,//相交的地方受到对应alpha和色值影响,按上面公式进行计算,如果都完全不透明则相交处完全不绘制kPlus_Mode,     //!< [Sa + Da, Sc + Dc]kModulate_Mode, // multiplies all components (= alpha and color)// Following blend modes are defined in the CSS Compositing standard:// https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingkScreen_Mode,   //滤色,滤色模式与我们所用的显示屏原理相同,所以也有版本把它翻译成“屏幕”;简单的说就是保留两个图层中较//白的部分,较暗的部分被遮盖;当一层使用了滤色(屏幕)模式时,图层中纯黑的部分变成完全透明,纯白部分完全//不透明,其他的颜色根据颜色级别产生半透明的效果kLastCoeffMode = kScreen_Mode,kOverlay_Mode,  //像素是进行 Multiply (正片叠底)混合还是 Screen (屏幕)混合,取决于底层颜色,但底层颜色的高光与阴影部//分的亮度细节会被保留kDarken_Mode,   //该模式处理过后,会感觉效果变暗,即进行对应像素的比较,取较暗值,如果色值相同则进行混合;从算法上看,//alpha值变大,色值上如果都不透明则取较暗值,非完全不透明情况下使用上面算法进行计算,受到源图和目标图对应//色值和alpha值影响kLighten_Mode,  //DARKEN 的目的是变暗,LIGHTEN 的目的则是变亮,如果在均完全不透明的情况下 ,色值取源色值和目标色值中的较大值,//否则按上面算法进行计算kColorDodge_Mode,kColorBurn_Mode,kHardLight_Mode,kSoftLight_Mode,kDifference_Mode,kExclusion_Mode,kMultiply_Mode, //正片叠底,即查看每个通道中的颜色信息,并将基色与混合色复合。结果色总是较暗的颜色。任何颜色与黑色复合产生黑色。//任何颜色与白色复合保持不变。当用黑色或白色以外的颜色绘画时,绘画工具绘制的连续描边产生逐渐变暗的颜色kLastSeparableMode = kMultiply_Mode,kHue_Mode,kSaturation_Mode,kColor_Mode,kLuminosity_Mode,kLastMode = kLuminosity_Mode};</span>
 
 有关XferMode的例子可以参考xfermode.cpp、xfermode2.cpp、xfermode3.cpp、sampleXfermode.cpp。 
注意:skia默认的XferMode是kSrcOver_Mode。

第二阶段:使用由rasterizer生成的mask把中间图像和目的图像再一次混合处理,然后把搬移到目的bitmap。(这部分暂时还没有看到)

总结

大体看完这部分,感觉skia在draw的过程中,首先要使用path + rasterizer得到绘制的图元形状,然后通过shader进行着色处理,最后transfer的过程主要用来将src/dst图元完成混合处理,并将最终图像搬移到目的bitmap中。

这篇关于skia draw的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/638098

相关文章

Matlab draw a sector 画一个扇形

Matlab draw a sector 画一个扇形 Matlab的函数代码: function [ sector ] = Draw_a_sector( map, center,StartR, EndR, StartAngle, EndAngle )%% Get indexs(row,column)size_map=size(map);for i = 1:size_map(2)index

数据标注:批量转换json文件,出现AttributeError: module ‘labelme.utils‘ has no attribute ‘draw_label‘错误

labelme版本更换为3.11.2 "D:\Anaconda3\Lib\site-packages\labelme\utils\draw.py"缺失?: import ioimport os.path as ospimport numpy as npimport PIL.Imageimport PIL.ImageDrawimport PIL.ImageFontdef label_co

【教你一键解决】draw.io中输入英文显示成中文且输入位置移到首位

问题描述:当英文输入一个“a”时,会自动出现中文“一个”,再输入“a”才会出现“a”,删除时无法把中文删除,如下图所示。 解决方法:关闭浏览器的自动翻译功能即可,如下图所示。

x11 draw_pixels

对图像每个像素 统一 加一个值 创建一个图片 char *data = (char*)malloc(256*256*4);XImage *img = XCreateImage(display,visual,DefaultDepth(display,screen_num),ZPixmap,0,data,256,256,32,0); 调用 XAddPixel 添加值 int count =

C# 实现draw一个简单的温度计

运行结果 概述: 代码分析 该控件主要包含以下几个部分: 属性定义: MinValue:最低温度值。 MaxValue:最高温度值。 CurrentValue:当前温度值。 构造函数: 设置了一些控件样式来提升绘制效果,如 DoubleBuffer 以及 ResizeRedraw 等。 设定了控件的默认宽度和高度,并设置背景色和内边距。 绘制逻辑(在 OnPaint 方

Draw.io

Draw.io Draw.io是一款很实用的思维导图软件,现在已经推出了桌面版,对于很多办公人士而言画张流程图可以轻松的罗列整个流程,比使用文字或者幻灯片制作简单并且容易理解,该应用程序不仅免费,还拥有专业的工具,可让您创建图表和各种基于图像的流程图。您将无需再计划任何事情。它是迄今为止最容易使用的图表创建工具之一,具有友好的界面,丰富的功能和高度的自定义功能,所有这些功能均已集成到最终产品中。

arcgis for javascript- Draw画图结束添加多个图形问题

在Draw工具中 draw-end(画图结束后想地图添加图形) 发现第一次添加一个图形,第二次添加两个图形,第三次添加三个图形,依次递增 //新增图形function addLifeBoundary(){alert("新增图形");lifeFeatureLayer.clearSelection();lifeFeatureLayer.refresh();drawToolbar.activate

例54:Draw使用

建立一个控制台工程,输入代码: Screen 13 '移动到(50,50)而不绘图 Draw "BM 50,50"   'B:移动但不绘制,M:移动到指定位置 '将绘图颜色设置为2(绿色) Draw "C2"        'C将颜色改为n '画一个盒子 Draw "R50 D30 L50 U30"   'R表示右移动n个单位,D向下 ,L左,U上。 '在盒子里面移动 Draw

图标绘制软件draw.io中文安装包

Draw.io(也称为Diagrams)是一款功能强大的免费在线图表绘制工具。它支持绘制多种类型的图表,如流程图、UML图、组织结构图等,满足了从商务到工程设计的多领域需求。软件界面直观友好,操作简单,用户无需安装额外软件,即可直接在浏览器中使用。Draw.io还支持与云存储服务集成,方便用户保存和分享作品。此外,它还提供了丰富的导出选项,包括PDF、PNG等格式,满足不同用户的使用需求。 图标

draw.io 如何设置图形圆角?

draw.io 如何设置图形圆角呢? draw.io 是一款强大的,免费的开源工具,我经常用它来画流程图,但是我发现 draw.io 对于图形圆角的设置,只提供了一个设置选项,如下图: 当你选中某个图形,然后选中这里的“圆角”的时候,图像就会变成圆角,但是如果当你想把圆角再增大的时候,就没法设置了,工具面板上没有提供相关设置的选项。 这时候怎么办呢?例如我们要将一个矩形设置圆角的大小,可以