zoukankan      html  css  js  c++  java
  • 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用的人还是太少!

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

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

  • 相关阅读:
    APP-5-百度电子围栏
    APP-4-百度地图定位
    洗礼灵魂,修炼python(60)--爬虫篇—httplib2模块
    洗礼灵魂,修炼python(59)--爬虫篇—httplib模块
    洗礼灵魂,修炼python(58)--爬虫篇—【转载】urllib3模块
    洗礼灵魂,修炼python(57)--爬虫篇—知识补充—编码之对比不同python版本获取的数据
    洗礼灵魂,修炼python(56)--爬虫篇—知识补充—编码之url编码
    洗礼灵魂,修炼python(55)--爬虫篇—知识补充—RFC 2616 http状态码
    洗礼灵魂,修炼python(54)--爬虫篇—urllib2模块
    洗礼灵魂,修炼python(53)--爬虫篇—urllib模块
  • 原文地址:https://www.cnblogs.com/LCHL/p/9055642.html
Copyright © 2011-2022 走看看