基于InkCanvas实现的桌面涂鸦工具-[ WPF开发 ]
首先簡單的介紹下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开发 ]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MM夏天化妆不掉妆的技巧
- 下一篇: Smarty的assign定义变量