WPF 粉笔绘制

在做白板书写的时候,会有各种笔的绘制,比如 书写笔、马克笔、演示笔等等。粉笔的功能需求也是很有必要的。

上网搜了一圈,几乎没有绘制粉笔的。

有的是毛笔、楷体等绘制的如下博客:

wpf inkcanvas customink 毛笔效果_wpf inkcanvas 笔锋-CSDN博客

【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、效果如下:

普通书写

 

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

 

posted @ 2024-11-26 19:32  wuty007  阅读(16)  评论(0编辑  收藏  举报