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

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

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

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. Windows 提权-SeImpersonatePrivilege 特权

    本文通过 Google 翻译 SeImpersonatePrivilege – Windows Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校 ...

  2. postgresql使用for循环

    开发过程中经常需要制造一些测试数据,sqlserver等数据库都有循环执行语句的方式,postgresql也可以使用for循环插入数据 do $$ begin for tt in 1..99 loop ...

  3. 洛谷P2701 [USACO5.3] 巨大的牛棚Big Barn 题解

    怎么题解全是清一色的 dp?可以用笛卡尔树啊(虽然麻烦了很多,但是我热爱)! 题目传送门. 笛卡尔树的介绍 笛卡尔树,是一种二叉搜索树,它满足如下条件: 每个节点的编号满足二叉搜索树的性质. 每个节点 ...

  4. 分布式锁—2.Redisson的可重入锁

    大纲 1.Redisson可重入锁RedissonLock概述 2.可重入锁源码之创建RedissonClient实例 3.可重入锁源码之lua脚本加锁逻辑 4.可重入锁源码之WatchDog维持加锁 ...

  5. [AI/GPT/LLOps/AI中台] Dify : 开源AI大模型应用开发平台(Apache 2.0)

    概述:Dify Dify 是一款开源的大语言模型(LLM) 应用开发平台. 它融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者可以快速搭建生产级的生成式 AI ...

  6. C/C++显示类型转换的位拓展方式

    最近用verilator写模块的tb,在这里卡了好久(测半天都是C++写的问题) 要点 变量从小位宽到大位宽显示类型转换(explicit cast)时的位拓展方式,取决于转换前变量的符号性. 倘若转 ...

  7. C++基础学习--随记

    博客地址:https://www.cnblogs.com/zylyehuo/ 参考"C++基础与深度解析" 一.预备知识 // c++常用工具 /usr/bin/time //查看 ...

  8. linux防火墙查看状态firewall

    一.firewall防火墙 1.查看firewall服务状态 systemctl status firewalld 出现Active: active (running)切高亮显示则表示是启动状态. 出 ...

  9. 异常的两种处理方式--java进阶day08

    1.异常的默认处理流程 java中,对于异常的默认处理方式是--向上抛出 之前我们说过,异常都是类,当某个程序出错后,就会自动生成该异常对象,而这个异常对象就如同一颗雷 . java的异常默认处理方式 ...

  10. Sql语句:数据操作

    数据操作,核心是:增删改查. 其中查与增删改不同,要返回数据集,其他的只要知道是否修改成功即可,所以一般调用时,返回值不同,这点要注意. 一.查询: select sname,sdept,sage f ...