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、效果如下:
普通书写

重力慢速书写(仿压着粉笔写字):


浙公网安备 33010602011771号