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的值,达到替换颜色的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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、自定义补点

由于通过设备采集到的点,会有疏密的区分,所以对于比较稀疏的点,需要通过补点的方式,达到减少锯齿的效果,具体的补点的距离,因业务需要不同,可以通过调节参数的方式做适配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//标识上一个点
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绘制出来

1
drawingContext.DrawImage(imageSource, new Rect(newX - w2, newY - w2, w2 * 2, w2 * 2));

 

6、效果如下:

普通书写

 

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

 

posted @   wuty007  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示