WPF 粉笔绘制
在做白板书写的时候,会有各种笔的绘制,比如 书写笔、马克笔、演示笔等等。粉笔的功能需求也是很有必要的。
上网搜了一圈,几乎没有绘制粉笔的。
有的是毛笔、楷体等绘制的如下博客:
wpf inkcanvas customink 毛笔效果_wpf inkcanvas 笔锋-CSDN博客
绘制粉笔的思路,一开始是源于 github的一个仓库:mychalkboard/MyChalkBoard: MyChalkBoard is an application for you to quickly sketch with a chalk.
对应的网页的链接:MyChalkBoard
思路:就是用一个通用的笔头(ImageSource),利用Stroke 捕获到的StylusPoints的点,生成对应的点的坐标,调用drawingContext.DrawImage,绘制图案
1、生成笔头
找UI绘制一个粉笔形状的图片,以Png为例:
2、支持修改颜色
参考了该博文: 2018-8-10-WPF-修改图片颜色-CSDN博客
只要是修改 WriteableBitmap 的RGBA的值,达到替换颜色的效果
public static unsafe ImageSource ConvertImageColor(Color newColor, WriteableBitmap writableBitmap) { var bitmap = writableBitmap; if (bitmap == null) { return null; } bitmap.Lock(); var length = bitmap.PixelWidth * bitmap.PixelHeight * bitmap.Format.BitsPerPixel / 8; var backBuffer = (byte*)bitmap.BackBuffer; var byteList = new byte[length]; for (int i = 0; i + 4 < length; i = i + 4) { byteList[i] = newColor.B; byteList[i + 1] = newColor.G; byteList[i + 2] = newColor.R; byteList[i + 3] = backBuffer[i + 3]; } bitmap.Unlock(); bitmap = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight, 96, 96, bitmap.Format, bitmap.Palette); bitmap.Lock(); bitmap.WritePixels(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight), byteList, bitmap.BackBufferStride, 0); bitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight)); bitmap.Unlock(); return bitmap; }
3、收集点迹
主要是调用了我们组内自研封装的一套基于鼠标、触摸汇总的笔迹点迹收集的算法(WPF 输入附加事件 - 唐宋元明清2188 - 博客园),通过 Down、Move、Up以及分段汇总的方式,收集并呈现笔迹
4、自定义补点
由于通过设备采集到的点,会有疏密的区分,所以对于比较稀疏的点,需要通过补点的方式,达到减少锯齿的效果,具体的补点的距离,因业务需要不同,可以通过调节参数的方式做适配
//标识上一个点 var previousPoint = new Point(double.NegativeInfinity, double.NegativeInfinity); for (int i = 0; i < stylusPoints.Count; i++) { var pressureFactor = stylusPoints[i].PressureFactor * 2; var currentPoint = stylusPoints[i].ToPoint(); var vector = previousPoint - currentPoint; var newWidth = width * pressureFactor; //作为基准值 var baseWidth = newWidth / 1.5; if (!double.IsInfinity(vector.Length) && vector.Length > baseWidth) { var w2 = newWidth; if (newWidth - vector.Length > newWidth) w2 = newWidth - vector.Length; var newPointCount = (int)(vector.Length / (baseWidth)) * 2; var dx = (currentPoint.X - previousPoint.X) / newPointCount; var dy = (currentPoint.Y - previousPoint.Y) / newPointCount; for (int pointCount = 0; pointCount < newPointCount; pointCount++) { var newX = previousPoint.X + dx * (pointCount + 1); var newY = previousPoint.Y + dy * (pointCount + 1); drawingContext.DrawImage(imageSource, new Rect(newX - w2, newY - w2, w2 * 2, w2 * 2)); } } else { Rect rectangle = new Rect(currentPoint.X - newWidth, currentPoint.Y - newWidth, newWidth * 2, newWidth * 2); drawingContext.DrawImage(imageSource, rectangle); } previousPoint = currentPoint;
5、绘制点迹
通过以上4个前提步骤,就可以计算出来笔迹的大小,通过调用 drawingContext.DrawImage 的方式把带粉笔头的Image绘制出来
drawingContext.DrawImage(imageSource, new Rect(newX - w2, newY - w2, w2 * 2, w2 * 2));
6、效果如下:
普通书写
重力慢速书写(仿压着粉笔写字):