首先简单的介绍下InkCanvas,简单的来说,InkCanvas就是在WPF中实现允许使用墨迹的布局控件。实际上,InkCanvas有着更多层面上的应用,它的主要目的是(通过鼠标或者和指示笔)捕捉笔迹。InkCanvas从技术上说不是一个控件,因为它直接从FrameworkElement继承而来,但是它的行为和控件非常像(但不能用一个新的模板来改变它的样式)。
默认模式下,InkCanvas允许在它的表面上进行简单的书写和画图。当使用指示笔时,笔尖用来写、笔端用来擦。每一个笔画被捕捉为一个System.Windows.Ink.Stroke对象,保存在InkCanvas的Strokes集合中。但是InkCanvas也支持在Children集合(一个内容属性)中保留任意数量的UIElement元素。这样很容易通过墨水(ink)来注释任何东西。如下面的代码,我们可以很容易的生成一个InkCanvas画板。

<Window x:Class="WPFTEST.InkCanvas"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="InkCanvasSample" Width="220" Height="87">
        <InkCanvas>
             <InkCanvas.DefaultDrawingAttributes>             
                 <DrawingAttributes Color="Red" />
            </InkCanvas.DefaultDrawingAttributes>
        <Image Source="E:\Cnblogs\wwf.png"/>
        </InkCanvas>
</Window>

InkCanvas 支持几种模式,它们能利用EditingMode属性被独立地应用到指示笔尖(或鼠标),并通过EditingModeInverted属性来应用于指示笔的末端(back end)。只读的ActiveEditingMode属性可以告诉你哪一个属性当前正在被使用。所有这3个属性都是InkCanvasEditingMode类型的,它有以下几种值:
1、Ink(EditingMode的默认值) —— 通过鼠标或者指示笔来绘制笔画。
2、InkAndGesture —— 和Ink一样,但同样可以识别用户的手势。手势的列表(Up、Down、Circle、ScratchOut和Tap)保存在System.Windows.Ink.ApplicationGesture枚举类型中。
3、GestureOnly —— 只识别手势,不会绘制用户输入的笔画。
4、EraseByStroke (EditingModeInverted的默认值)—— 当笔画被触及时将笔画擦掉。
5、EraseByPoint —— 只擦掉直接碰及到的笔画部分(就像传统的铅笔橡皮)。
6、Select —— 当被触及时,选择笔画或者任何UIElement,使它们能被删除、移动或者在InkCanvas范围内被调整尺寸。
7、None —— 对于鼠标或者指示笔不做任何响应。

一些普通元素与墨水没有任何关系,如果在这些元素上使用Select模式将非常有趣,因为它自动会提供一个“穷人”的运行时设计界面用来排列控件。InkCanvas还定义了15种事件,其中包括改变编辑模式、改变/移动/调整选择、收集或者擦除笔画,以及执行手势。当然,在应用程序中使用墨水比在人脸上画胡子还是要复杂些!你经常要对一个笔画集合做手写识别,如果输入的是字符你就可以分析出它。WPF拥有内建的手势识别功能,但没有手写识别引擎。

概述

程序截图如下:

大概的一个思路就是主要有两个操作窗口,一个是主窗口,可以进行新建涂鸦、调整画笔彩色、画笔形状等等,另外一个就是涂鸦的画板了。首先先截图,然后设置Inkcanvas的Background属性为该图片,然后就可以在上面进行画图了。主要要处理的细节问题在于:

  • 截图的问题
  • 取得窗口坐标的问题
  • 窗口之间传值的问题

把这些细节处理好就很容易就可以实现了。

代码解释

首先是截图的问题。查MSDN,我找不到WPF里有现在的API可以调用,只能通过winForm来实现截图,代码如下:

01 public Bitmap GetScreenSnapshot()
02 {
03      System.Drawing.Rectangle rc = SystemInformation.WorkingArea;
04      var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
05
06      using (Graphics g = Graphics.FromImage(bitmap))
07      {
08          g.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy);
09      }
10
11      return bitmap;
12 }
13
14 public BitmapSource ToBitmapSource(Bitmap bmp)
15 {
16      BitmapSource returnSource;
17
18      try
19      {
20          returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
21      }
22      catch
23      {
24          returnSource = null;
25      }
26      return returnSource;
27
28 }
29 //截取整个屏幕作为画布,并开始画画
30 private void pencil_Click(object sender, RoutedEventArgs e)
31 {
32      //初始化画布
33      PainterWindow pw = new PainterWindow();
34      System.Drawing.Rectangle rc = SystemInformation.WorkingArea;
35      pw.Width = rc.Width;
36      pw.Height = rc.Height;
37      pw.ink.Width = rc.Width;
38      pw.ink.Height = rc.Height;
39      //截图
40        this.Hide();
41      Bitmap bt = GetScreenSnapshot();
42      BitmapSource bs = ToBitmapSource(bt);
43
44      System.Windows.Controls.Image img = new System.Windows.Controls.Image();
45      img.Source = bs;
46      pw.ink.Background = new ImageBrush(bs);
47      pw.Show();
48      this.Show();
49
50 }

看到上面的代码,通过System.Drawing.Rectangle rc = SystemInformation.WorkingArea;来获取当前系统工作窗口(不包括任务栏)的信息,包括分辨率的大小,各个点的坐标信息,获取这些信息后,新建一个bitmap,通过winForm里的CopyFromScreen函数我们把屏幕绘画在新建的那个bitmap上,然后获得bitmap的地址设置为BitmapSource,并设置ink的Background为ImageBrush(bs)即可。

下面是响应颜色选择的代码:

01 private void color_Click(object sender, RoutedEventArgs e)
02 {
03     ColorDialog cd = new ColorDialog();
04     //取得颜色
05     if (cd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
06     {
07         //要去了解这两种颜色的不同之处
08         inkDA.Color = System.Windows.Media.Color.FromArgb(cd.Color.A, cd.Color.R, cd.Color.G, cd.Color.B);
09         inkDA.Height = 3;
10         inkDA.Width = 3;
11         inkDA.FitToCurve = true;
12         //修改颜色
13         foreach (Window win in System.Windows.Application.Current.Windows)
14         {
15             if (win.Title == "PainterWindow")
16             {
17                 PainterWindow pw = win as PainterWindow;
18                 pw.ink.DefaultDrawingAttributes = inkDA;
19                 pw.Show();
20             }
21         }
22
23     }
24
25
26 }

要注意的是System.Widows.Media.Color与InkCanvas定义的颜色的不同,这中间需要通过一个函数来转换。

其实想着能把它完善好的,像形状的自定义,界面的细节调整,等。最近有太多的事情要做,所以先搁置下来,待时间过后再回来看自己的代码,熟悉下。

相关资料

一些关于InkCancas的资料

  • WPF中InkCanvas(墨水面板)用法
  • 分享WPF实现屏幕截图程序详解
  • 桌面涂鸦工具下载(需要.net支持,涂鸦过程按Esc键退出涂鸦界面。)
  • 源代码

转载于:https://www.cnblogs.com/wpdev/archive/2011/04/21/inkcanvas-sample.html

基于InkCanvas实现的桌面涂鸦工具-[ WPF开发 ]相关推荐

  1. 基于Marlin固件库桌面3D打印机软件开发

    0 系统组成 1硬件 原理框图 2  软件开发平台 Arduino 

  2. 一个为程序员定制的、WPF开发的小巧、美观桌面快捷工具

    今天给大家推荐一个基于WPF开发的,专门为程序员定制的桌面快捷工具. 项目简介 这是基于.Net+WPF开发的,一个小巧.UI美观的快捷工具.此项目发布以来就受到大家的喜欢,代码结构清晰非常适合用来学 ...

  3. WPF学习12:基于MVVM Light 制作图形编辑工具(3)

    本文是WPF学习11:基于MVVM Light 制作图形编辑工具(2)的后续 这一次的目标是完成 两个任务. 本节完成后的效果: 本文分为三个部分: 1.对之前代码不合理的地方重新设计. 2.图形可选 ...

  4. secret-performance-desktop - 基于javafx的桌面个性化工具

    secret-performance-desktop 介绍 基于javafx的桌面个性化工具 起初只想在做个桌面的cpu和内存监控工具,连续迭代几个版本之后,成了一个桌面的个性化工具. 功能 cpu和 ...

  5. 基于RT-THREAD的桌面小工具

    摘要 这个桌面小盒子是之前的东西,一直放着没有整理好.最近有空了就把他整理整理. 小盒子主要用来显示时间和天气预报,功能比较简单,其实还有很多可以玩的,懒得弄,所以就把最简单的整理出来. 软件是基于r ...

  6. WPF开发的实用小工具 - 快捷悬浮菜单

    WPF开发的实用小工具 - 快捷悬浮菜单 ❝ 本文由网友投稿,Dotnet9站长整理.站长觉得这小工具很实用,站长家里.公司也在尝试使用了. 行文目录: 这工具有什么用? 正文 源码获取及应用下载体验 ...

  7. 基于javaGUI的文档识别工具制作

    基于javaGUI的文档识别工具制作 对于某些文本,其中富含了一些标志,需要去排除,以及去获得段落字数,以下是我个人写的一个比较简单的文档识别工具,含导入文件.导出文件以及一个简单的识别功能. 1.功 ...

  8. 纸上原型设计 VS 桌面原型工具设计,你更喜欢谁?

    2019独角兽企业重金招聘Python工程师标准>>> 纸上原型设计,作为传统的原型设计方式,简单快速,成本低廉,为大部分设计师所喜爱.而桌面原型工具设计,作为伴随电脑科技发展而出现 ...

  9. Redis 桌面管理工具 RedisDesktopManager 2019.0 发布

    百度智能云 云生态狂欢季 热门云产品1折起>>>   RedisDesktopManager 2019.0 版本已发布,Redis Desktop Manager(RedisDesk ...

最新文章

  1. Linux kernel 不输出log信息
  2. lombok快速入门:实体类中再也不用写setter和getter,toString等方法了
  3. java print int_java – 在printin输入int
  4. 河源电大有考计算机等级的吗,河源电大有什么专业自考也有?
  5. 建模:确定服务的边界——《微服务设计》读书笔记
  6. Java面向对象编程(基础部分)
  7. 在Spring Boot中使用Vaadin的简介
  8. 前端学习(3191):react中案例
  9. 使用PHP对word文档进行操作的方法
  10. iOS开发SDWebImage源码解析之SDWebImageManager的注解
  11. 波特率dlm_ARM学习随笔(13)UART的理解
  12. Java中的移位操作——Java编程思想笔记
  13. 大数据教程,大数据学习线路图
  14. 机器学习(三):线性模型
  15. 科技企业捐赠武汉最新最全排名(截止2月13日)
  16. 安全狗技术分享|Web应用防火墙之攻击防护
  17. 中国股市:如果历史会重复?
  18. 【Unity】Rigibody——刚体加力、刚体加扭矩力、刚体加力的几种模式
  19. Z-Libary最新地址检测,再也不用担心找不到ZLibary了
  20. 计算机假期计划内容,寒假计划表内容

热门文章

  1. Anthem库的Google Suggest 实现
  2. 人际交往的“三有三避”
  3. ASP.NET 2.0 学习笔记 1: session 与 script 应用
  4. 通用的异步处理类和进度通知类及其示例
  5. java 统计图 mysql_java实现各种数据统计图(转)
  6. mysql每秒57000_MySQL 性能:使用 MySQL 5.7 实现每秒 50 万查询
  7. Nginx静态资源压缩实战内容介绍
  8. Spring如何将事件分配给专门的监听器?
  9. 什么时候用不到索引?
  10. jwt:token的解析