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

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

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

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

普通书写

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

WPF 粉笔绘制的更多相关文章

  1. wpf 后台绘制圆弧

    wpf 前台绘制圆弧很简单,如:<Path x:Name="path_data" Stroke="#FFE23838" StrokeThickness=& ...

  2. C#WPF 如何绘制几何图形 图示教程 绘制sin曲线 正弦 绘制2D坐标系 有图有代码

    原文:C#WPF 如何绘制几何图形 图示教程 绘制sin曲线 正弦 绘制2D坐标系 有图有代码 C#WPF 如何绘制几何图形? 怎么绘制坐标系?绘制sin曲线(正弦曲线)? 这离不开Path(Syst ...

  3. WPF 图形绘制 及各种线帽、箭头的实现

    原文:WPF 图形绘制 及各种线帽.箭头的实现  /// <summary>     /// 矩形类     /// </summary>     public sealed ...

  4. WPF特效-绘制实时2D激光雷达图

    原文:WPF特效-绘制实时2D激光雷达图 接前两篇: https://blog.csdn.net/u013224722/article/details/80738619 https://blog.cs ...

  5. 【C#】第3章补充(一)如何在WPF中绘制正弦曲线

    分类:C#.VS2015 创建日期:2016-06-19 使用教材:(十二五国家级规划教材)<C#程序设计及应用教程>(第3版) 一.要点 本例子提前使用了教材第13章介绍的基本知识. 二 ...

  6. 在WPF中绘制多维数据集

    原文 https://stuff.seans.com/2008/08/13/drawing-a-cube-in-wpf/ 是时候使用WPF绘制一个简单的3D对象了.作为WPF中3D图形的快速介绍,让我 ...

  7. WPF 如何绘制不规则按钮,并且有效点击范围也是不规则的

    最近在做一个东西,如地图,点击地图上的某一区域,这一区域需要填充成其他颜色.区域是不规则的,而且点击该区域的任一点,都能够变色.普通的按钮只是简单的加载一幅图肯定是不行的.查了很多资料,终于把它搞定了 ...

  8. WPF拖动绘制

    using System; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using ...

  9. wpf GeometryDrawing 绘制文字

    <GeometryDrawing x:Key="GeometryDrawingText"> <GeometryDrawing.Geometry> <R ...

  10. WPF绘制折线

    WPF后台绘制折线,填充到一个GRID下 private void btnPreview_Click(object sender, RoutedEventArgs e) { GridImg.Child ...

随机推荐

  1. Docker - 在docker中部署Nginx

    1.docker search 查找ngix 2.docker pull下载镜像 3.查看镜像列表 4.docker run启动容器 5.测试nginx容器是否启动成功 1.docker search ...

  2. 读论文-电子商务产品推荐的序列推荐系统综述与分类(A Survey and Taxonomy of Sequential Recommender Systems for E-commerce Product Recommendation)

    前言 今天读的这篇文章是于2023年发表在"SN Computer Science"上的一篇论文,这篇文章主要对序列推荐系统进行了全面的调查和分类,特别是在电子商务领域的应用.文章 ...

  3. 面试题 17.12. BiNode

    地址:https://leetcode-cn.com/problems/binode-lcci/ <?php /** 二叉树数据结构TreeNode可用来表示单向链表(其中left置空,righ ...

  4. Java Properties配置文件和XML配置文件读取

    一.properties类读取配置文件 1.从项目中读取properties配置文件,新建一个main程序,对应位置建立一个名称为config.properties配置文件,随意放置一些键值对.IDE ...

  5. Swagger OpenAPI Schema 为空时 Example Value 显示 "string" 的原因及解决方案

    解决Swagger UI示例值显示"string"的问题 最近在使用ObjectScript生成JSON接口文档时,遇到了一个奇怪的问题: 生成的JSON数据是正常的. 但Swag ...

  6. 程序员必看 Linux 常用命令(重要)

    文件操作命令 find find 用于在指定目录下查找文件或子目录,如果不指定查找目录,则在当前目录下查找 命令格式:find path -option [-print] [ -exec/-ok co ...

  7. 如何通过 MCP 将你的 Supabase 数据库连接到 Cursor

    Cursor + MCP + Supabase. 图片来自作者 在过去几周里,MCP(Model Context Protocol,模型上下文协议)在许多 AI 相关的在线社区和论坛里大火.开发者和技 ...

  8. 【Linux】3.7 定时任务调度

    3.7定时任务调度 1. 任务调度原理 crond任务调度:crontab进行定时任务调度 使用方法:crontab [选项] crontab [选项] -e:编辑crontab定时任务 -i:查询c ...

  9. ASP.NET 日志路径

    默认路径 protected void Button_StreamWrite_Click(object sender, EventArgs e) {     StreamWriter sw = new ...

  10. unity手机花屏

    关于Camera组件中Clear Flags的理解 - 知乎 (zhihu.com) https://blog.csdn.net/yanchezuo/article/details/77337755 ...