SkiaSharp常用操作
1. 屏幕坐标系
屏幕的坐标系原点在屏幕的左上角,水平往右、竖直往下为正。屏幕的坐标横坐标用“x”表示,纵坐标用“y”表示,坐标的单位为像素。坐标(4, 2)用表示当前点在原点右方4个像素处,在原点下方2个像素处,
2. 颜色 SKColor
颜色的构造方法有很多种,但最常见的是利用RGB三原色来构造,此外还可以加入透明度:
var color = new SKColor(180, 180, 180, 128); //四个参数表示red, green, blue, alpha
3. 画刷 SKPaint
Skia是用画刷来完成各种绘制工作的。画刷的构造函数并无参数输入,各种参数是以属性的方式传入的。常见的属性有:颜色、字体、填充类型、画笔宽度等。
var paint = new SKPaint()
{
Color = new SKColor(180, 180, 180, 128), //颜色
StrokeWidth = 2, //画笔宽度
Typeface = SKTypeface.FromFamilyName("宋体", SKFontStyle.Normal), //字体
TextSize = 32, //字体大小
Style = SKPaintStyle.Stroke, //类型:填充 或 画边界 或全部
PathEffect = SKPathEffect.CreateDash(LongDash, 0), //绘制虚线
};
4. 画布 SKCanvas
Skia所有的绘制是基于画布的。画布来自于SKSurface,SKSurface一般从图像从获取。画布绘制通常直接调用其DrawXXX方法,其函数意义及所需参数大都可通过其名称轻易判断。而本项目中海图直接显示窗体中的SKControl控件上,该控件的的PaintSurface事件中存在画布。
SKImageInfo imageInfo = new SKImageInfo(300, 250);
using (SKSurface surface = SKSurface.Create(imageInfo))
{
SKCanvas canvas = surface.Canvas;
canvas.DrawColor(SKColors.Red); //填充颜色
}
5. 绘制直线 DrawLine
最简单的绘制函数,输入参数为起点、终点的坐标和画刷。
canvas.DrawLine(3, 5, 500, 100, paint); //用paint画直线,起点(3, 5),终点(500, 100)
6. 绘制文本 DrawText
在指定的坐标处,用画笔来绘制指定的文本。指定的坐标可被近似的认为位于文本的左下角。
canvas.DrawText("文本", 50, 50, paint);
7. 绘制矩形 DrawRect
矩形由四个参数来表示:左上角横坐标。左上角纵坐标,矩形宽度,矩形高度。
canvas.DrawRect(10, 10, 100, 100, paint);
8. 绘制多点 DrawPoints
多个点可以代表孤立的点,可代表线段,也可代表多边形区域。因此,绘制多点时,最重要的是传入多点的绘制模式[SKPointMode],SKPointMode是一个枚举,其中0=点,1=线段,2=多边形。
public void DrawPoints(SKPointMode mode, SKPoint[] points, SKPaint paint);
9. 路径及其绘制 SKPath / DrawPath
绘制多点的方式可以绘制多边形区域的,但如果多边形内部存在空洞,绘制多点则无能为力了。而路径功能则强大得多,路径有两个最常用的方法:MoveTo 添加起点
和LineTo 添加拐点
。路径默认的填充方式为Winding
,此外还有EvenOdd
、InverseWinding
、InverseEvenOdd
。通过填充方式来判断某一封闭区域是属于整个区域内部还是外部。缠绕算法和奇偶算法都基于从该区域绘制到无限远的假设线来确定是否填充了任何封闭区域。 该线与构成路径的一条或多条边界线交叉。 在缠绕模式下,如果在一个方向上绘制的边界线数量与在另一方向上绘制的边界线数量平衡,则不会填充该区域(外部);否则,该区域将被填充(内部)。 如果边界线的数量为奇数,则奇偶算法将填充一个区域。直观感受为,外圈顺时针将点添加进路径,内圈逆时针将点添加进路径,就可在内部形成一个空洞,这与海图空间记录编码标准一致。
var path = new SKPath();
//外圈 顺时针
path.MoveTo(50, 50); //起点
path.LineTo(50, 350);
path.LineTo(350, 350);
path.LineTo(350, 50);
//内圈 逆时针
path.MoveTo(100, 100); //起点
path.LineTo(200, 100);
path.LineTo(200, 200);
path.LineTo(100, 200);
//绘制路径
canvas.DrawPath(path, new SKPaint());
10. 截图
在Skia中截图非常简单,直接调用SKSurface的Snapshot()
方法即可。
using (SKImage image = e.Surface.Snapshot())
using (SKData data = image.Encode(SKEncodedImageFormat.Png, 100)) //指定图片格式及质量
using (var mStream = new MemoryStream(data.ToArray()))
{
Bitmap bm = new Bitmap(mStream, false);
pictureBox1.Image = bm;
}
11. 坐标变换
有时绘制某一物标时,需要缩放一定比例、旋转一定角度或偏移一定的位置,这都涉及到坐标变换。任何平面坐标之间的转换关系可以直接用三维矩阵表示,也可以分步进行。分步变换时,每后一步的变换均在前一步变换基础之上的。
- 旋转(绕指定中心点旋转)
public void RotateDegrees(float degrees, float px, float py);
- 缩放(绕指定中心点,分横轴与纵轴方向缩放)
public void Scale(float sx, float sy, float px, float py);
- 平移
public void Translate(float dx, float dy);
如对一个路径,分别进行三次变换:
var path = new SKPath();
path.MoveTo(50, 50); //起点
path.LineTo(50, 150);
path.LineTo(150, 150);
path.LineTo(150, 50);
path.LineTo(50, 50);
//原图像 默认黑色
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke });
//绕点(100,100)旋转45度,绘制成红色
canvas.RotateDegrees(45, 100, 100);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Red });
//缩放 横轴与纵轴方向缩小一倍,缩放中心为(100, 100), 绘制成绿色
canvas.Scale(0.5f, 0.5f, 100, 100);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Green });
//平移 向右平移150,向下平移150,绘制成蓝色
canvas.Translate(150, 150);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Blue });
得到如下效果:
如图所示,最后一步平移的实际结果,与初步设想(向右下方向平移150像素)不一样,是因为最后的平移需考虑前两步的旋转与缩放变换。
12. 坐标系保存与还原
由坐标变换可知,每一步变换都是全局的,都对之后的绘制的坐标系产生影响。当绘制电子海图物标需要执行不同变换时,为避免不同坐标系之间相互干扰,绘制流程一般如下:1. 记住标准坐标系;2. 根据物标需要变换坐标;3. 绘制物标;4. 还原坐标系(执行坐标变换的逆运算)。
而Skia中就提供了当前坐标保存Save()
与还原Restore()
的方法。
//原图像 默认黑色
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke });
canvas.Save();
//绕点(100,100)旋转45度,绘制成红色
canvas.RotateDegrees(45, 100, 100);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Red });
canvas.Restore();
canvas.Save();
//缩放 横轴与纵轴方向缩小一倍,缩放中心为(100, 100), 绘制成绿色
canvas.Scale(0.5f, 0.5f, 100, 100);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Green });
canvas.Restore();
canvas.Save();
//平移 向右平移150,向下平移150,绘制成蓝色
canvas.Translate(150, 150);
canvas.DrawPath(path, new SKPaint() { Style = SKPaintStyle.Stroke, Color = SKColors.Blue });
canvas.Restore();
得到如下效果:
如图所示,每变换一步之前都执行了坐标保存,变换之后立即执行了坐标还原,因此每一步变换只对当前路径作用一次。
作者:EkinWu
链接:https://www.jianshu.com/p/828d1b0f90ac
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。