我是靠谱客的博主 落寞可乐,最近开发中收集的这篇文章主要介绍WPF InkCanvas 毛笔效果,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1、先来看看InkCanvas的一般用法:

<InkCanvas>
     <InkCanvas.DefaultDrawingAttributes>
           <DrawingAttributes StylusTip="Ellipse" Height="8" Width="4" IgnorePressure="False" FitToCurve="True" >
           <!--稍微变换一下,就算设备不支持“压感”,效果也是棒棒-->

    <DrawingAttributes.StylusTipTransform>
                   <Matrix M11="1" M12="1.5" M21="2.2" M22="1"/>
              </DrawingAttributes.StylusTipTransform>
           </DrawingAttributes>
     </InkCanvas.DefaultDrawingAttributes>
</InkCanvas>

2、自定义InkCanvas,实现毛笔效果

找到2篇文章,代码基本一致,也不知道哪位是原作者抑或都不是原作者?

使用WPF的自定义InkCanvas实现毛笔效果 【个人觉得该作者为原创?】

wpf inkcanvas customink 毛笔效果 【这位童鞋的话,后面都叛变去搞Unity3D了!】

以上代码缺点:

2-1、卡顿【虽然提到了解决办法,但都没有给出具体代码】

2-2、颜色【毛笔配黑墨才是正途,但世界是多姿多彩的不是?】

2-3、粗细【这个嘛~】

废话不多说,奉上改进后的代码:

 

 1
public class ChinesebrushRenderer : DynamicRenderer
 2 
{
 3
private ImageSource imageSource;
 4
private readonly double width = 16;
 5
 6
protected override void OnDrawingAttributesReplaced()
 7 
{
 8
if (DesignerProperties.GetIsInDesignMode(this.Element))
 9
return;
10
11
base.OnDrawingAttributesReplaced();
12
13
var dv = new DrawingVisual();
14
var size = 90;
15
using (var conext = dv.RenderOpen())
16 
{
17
//[关键]OpacityMask了解下?也许有童鞋想到的办法是,各种颜色的图片来一张?
18
conext.PushOpacityMask(new ImageBrush(new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Images\pen.png", UriKind.Absolute))));
19
//用颜色生成画笔画一个矩形
20
conext.DrawRectangle(new SolidColorBrush(this.DrawingAttributes.Color), null, new Rect(0, 0, size, size));
21 
conext.Close();
22 
}
23
var rtb = new RenderTargetBitmap(size, size, 96d, 96d, PixelFormats.Pbgra32);
24 
rtb.Render(dv);
25
imageSource = BitmapFrame.Create(rtb);
26
//[重要]此乃解决卡顿问题的关键!
27 
imageSource.Freeze();
28 
}
29
30
protected override void OnDraw(DrawingContext drawingContext, StylusPointCollection stylusPoints, Geometry geometry, Brush fillBrush)
31 
{
32
var p1 = new Point(double.NegativeInfinity, double.NegativeInfinity);
33
var p2 = new Point(0, 0);
34
var w1 = this.width + 20;
35
36
for (int i = 0; i < stylusPoints.Count; i++)
37 
{
38
p2 = (Point)stylusPoints[i];
39
40
//两点相减得到一个向量[高中数学知识了解下?]
41
var vector = p1 - p2;
42
43
//得到 x、y的变化值
44
var dx = (p2.X - p1.X) / vector.Length;
45
var dy = (p2.Y - p1.Y) / vector.Length;
46
47
var w2 = this.width;
48
if (w1 - vector.Length > this.width)
49
w2 = w1 - vector.Length;
50
51
//为啥又来一个for?图像重叠,实现笔画的连续性,感兴趣的童鞋可以把for取消掉看看效果
52
for (int j = 0; j < vector.Length; j++)
53 
{
54
var x = p2.X;
55
var y = p2.Y;
56
57
if (!double.IsInfinity(p1.X) && !double.IsInfinity(p1.Y))
58 
{
59
x = p1.X + dx;
60
y = p1.Y + dy;
61 
}
62
63
//画图,没啥可说的
64
drawingContext.DrawImage(imageSource, new Rect(x - w2 / 2.0, y - w2 / 2.0, w2, w2));
65
66
//再把新的坐标赋值给p1,以序后来
67
p1 = new Point(x, y);
68
69
if (double.IsInfinity(vector.Length))
70
break;
71
72 
}
73 
}
74 
}

 

 1 public class ChinesebrushStroke : Stroke
 2 
{
 3
 4
private ImageSource imageSource;
 5
private readonly double width = 16;
 6
 7
public ChinesebrushStroke(StylusPointCollection stylusPointCollection, Color color) : base(stylusPointCollection)
 8 
{
 9
if (DesignerProperties.GetIsInDesignMode(App.Current.MainWindow))
10
return;
11
var dv = new DrawingVisual();
12
var size = 90;
13
using (var conext = dv.RenderOpen())
14 
{
15
conext.PushOpacityMask(new ImageBrush(new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Images\pen.png", UriKind.Absolute))));
16
conext.DrawRectangle(new SolidColorBrush(color), null, new Rect(0, 0, size, size));
17 
conext.Close();
18 
}
19
var rtb = new RenderTargetBitmap(size, size, 96d, 96d, PixelFormats.Pbgra32);
20 
rtb.Render(dv);
21
imageSource = BitmapFrame.Create(rtb);
22
23
//Freezable 类提供特殊功能,以便在使用修改或复制开销很大的对象时帮助提高应用程序性能
24
//WPF中的Frozen(冻结)与线程及其他相关问题
25 
imageSource.Freeze();
26 
}
27
28
//卡顿就是该函数造成,每写完一笔就会调用,当笔画过长,后果可想而知~
29
protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
30 
{
31
if (this.StylusPoints?.Count < 1)
32
return;
33
34
var p1 = new Point(double.NegativeInfinity, double.NegativeInfinity);
35
var w1 = this.width + 20;
36
37
38
for (int i = 0; i < StylusPoints.Count; i++)
39 
{
40
var p2 = (Point)this.StylusPoints[i];
41
42
var vector = p1 - p2;
43
44
var dx = (p2.X - p1.X) / vector.Length;
45
var dy = (p2.Y - p1.Y) / vector.Length;
46
47
var w2 = this.width;
48
if (w1 - vector.Length > this.width)
49
w2 = w1 - vector.Length;
50
51
for (int j = 0; j < vector.Length; j++)
52 
{
53
var x = p2.X;
54
var y = p2.Y;
55
56
if (!double.IsInfinity(p1.X) && !double.IsInfinity(p1.Y))
57 
{
58
x = p1.X + dx;
59
y = p1.Y + dy;
60 
}
61
62
drawingContext.DrawImage(imageSource, new Rect(x - w2 / 2.0, y - w2 / 2.0, w2, w2));
63
64
p1 = new Point(x, y);
65
66
if (double.IsInfinity(vector.Length))
67
break;
68 
}
69 
}
70 
}
71
}

 

 1 public class ChinesebrushCanvas : InkCanvas
 2 
{
 3
public ChinesebrushCanvas()
 4 
{
 5
//当然要换上我们特地搞出来的ChinesebrushRenderer
 6
this.DynamicRenderer = new ChinesebrushRenderer();
 7 
}
 8
 9
10
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
11 
{
12
//感兴趣的童鞋,注释这一句看看?
13
this.Strokes.Remove(e.Stroke);
14
15
this.Strokes.Add(new ChinesebrushStroke(e.Stroke.StylusPoints, this.DefaultDrawingAttributes.Color));
16 
}
17
}

 笔画原图:

以上代码只是解决了1、2点,第三点嘛~毕竟每个人都有自己的粗细,大家自行体会~

 

吐槽一下:

本以为本篇文章能有点小小贡献,于是发布到“首页”,结果也就存活十多分钟,而且园内搜索还搜不到!

其实这个需求很久以前做项目就有提了,但那时候刚出来工作没多久【12年毕业,工作以后自学WPF】,还是一个菜鸟萌新,一篇相关文章都搜索不到啊不到!【手动哭泣】

之后也陆陆续续做了好多类似项目,但一直使用文中第一种方案,效果也能被客户接受。

哎,期待有缘人吧!毕竟WPF用的人还是太少!

也是,本篇文章没得个“抄袭”的罪名算好的了,还胆大包天的贴出原文链接!

最后【手动满地打滚撒泼~】

转载于:https://www.cnblogs.com/LCHL/p/9055642.html

最后

以上就是落寞可乐为你收集整理的WPF InkCanvas 毛笔效果的全部内容,希望文章能够帮你解决WPF InkCanvas 毛笔效果所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部