博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF InkCanvas 毛笔效果
阅读量:6162 次
发布时间:2019-06-21

本文共 6972 字,大约阅读时间需要 23 分钟。

原文:

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篇文章,代码基本一致,也不知道哪位是原作者抑或都不是原作者?

【个人觉得该作者为原创?】

【这位童鞋的话,后面都叛变去搞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             //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用的人还是太少!

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

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

转载地址:http://wbrfa.baihongyu.com/

你可能感兴趣的文章
B1010.一元多项式求导(25)
查看>>
10、程序员和编译器之间的关系
查看>>
配置 RAILS FOR JRUBY1.7.4
查看>>
修改GRUB2背景图片
查看>>
Ajax异步
查看>>
好记性不如烂笔杆-android学习笔记<十六> switcher和gallery
查看>>
JAVA GC
查看>>
3springboot:springboot配置文件(外部配置加载顺序、自动配置原理,@Conditional)
查看>>
图解SSH原理及两种登录方法
查看>>
查询个人站点的文章、分类和标签查询
查看>>
基础知识:数字、字符串、列表 的类型及内置方法
查看>>
JS图片跟着鼠标跑效果
查看>>
Leetcode 3. Longest Substring Without Repeating Characters
查看>>
416. Partition Equal Subset Sum
查看>>
app内部H5测试点总结
查看>>
[TC13761]Mutalisk
查看>>
while()
查看>>
常用限制input的方法
查看>>
IIS7下使用urlrewriter.dll配置
查看>>
并行程序设计学习心得1——并行计算机存储
查看>>