silverlight:手写板/涂鸦/墨迹/InkPresenter示例程序


这种应用现在已经比较常见了,比如论坛回贴中的手写功能 ,IM聊天中的个性化手写文字,个性签名等,在Silverlight中要实现该功能其实非常简单,只要一个InkPresenter控件即可

使用要点:

1.要合理设置裁剪区,否则手写时可能笔划会写到你不希望出现的地方.
2.处理好MouseLeftButtonDown,MouseMove,LostMouseCapture这三个事件.

演示代码:

前端Xaml部分:

by 菩提树下的杨过 http://yjmyzz.cnblogs.com/

<UserControl x:Class="InkPresenterTest.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" Background="Black"
    >

    <Grid Background="#FF0BB5A3" Width="650" Height="615">

        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="150"></RowDefinition>
        </Grid.RowDefinitions>

        <TextBlock x:Name="txtTitle" Text="InkPresenter 演 示" FontWeight="Bold" Grid.Row="0" HorizontalAlignment="Center" Height="20" VerticalAlignment="Center" Foreground="White" />

        <StackPanel x:Name="spToolBar" Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Height="25" VerticalAlignment="Center">
            <TextBlock Text="笔划颜色:" VerticalAlignment="Center"></TextBlock>
            <ComboBox x:Name="cboColor" Width="65" VerticalAlignment="Center">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Rectangle Fill="{Binding Color}" ToolTipService.ToolTip="{Binding Name}" Width="10" Height="10"/>
                            <TextBlock Text="{Binding Name}" Margin="2,0,0,0" Foreground="{Binding Color}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="笔划外框颜色:" VerticalAlignment="Center" Margin="10,0,0,0"></TextBlock>
            <ComboBox x:Name="cboOutlineColor" Width="65" VerticalAlignment="Center">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Rectangle Fill="{Binding Color}" ToolTipService.ToolTip="{Binding Name}" Width="10" Height="10"/>
                            <TextBlock Text="{Binding Name}" Margin="2,0,0,0" Foreground="{Binding Color}"></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="笔划宽度:" Margin="10,0,0,0" VerticalAlignment="Center"></TextBlock>
            <ComboBox x:Name="cboWidth" Width="60" VerticalAlignment="Center" Height="20">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <Rectangle Fill="Black" Width="40" Height="{Binding Size}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="笔划高度:" Margin="10,0,0,0" VerticalAlignment="Center"></TextBlock>
            <ComboBox x:Name="cboHeight" Width="60" VerticalAlignment="Center" Height="20">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <Rectangle Fill="Black" Width="40" Height="{Binding Size}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
            <TextBlock Text="透明度:" Margin="10,0,0,0" VerticalAlignment="Center"></TextBlock>
            <ComboBox x:Name="cboOpactiy" Width="60" VerticalAlignment="Center" SelectionChanged="cboOpactiy_SelectionChanged">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Value}" Opacity="{Binding Value}" ></TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ComboBox.ItemTemplate>
            </ComboBox>
        </StackPanel>

        <Canvas x:Name="inkC" Grid.Row="2" Height="370">
            <Rectangle x:Name="rectBg" Grid.Row="2" Width="650" Height="370" Fill="#FFECD85C" Margin="0" StrokeThickness="0"></Rectangle>
            <Image Source="image/background.png" Stretch="UniformToFill" x:Name="imgBg"></Image>
            <InkPresenter x:Name="ink" Height="370" Width="650" Grid.Row="2"            
              Background="Transparent" Opacity="1" 
              MouseLeftButtonDown="OnMouseLeftButtonDown"
              MouseMove="OnMouseMove"
              LostMouseCapture="OnLostMouseCapture" Margin="0"
              >
                <InkPresenter.Clip>
                    <RectangleGeometry Rect="0,0,650,370"></RectangleGeometry>
                </InkPresenter.Clip>

            </InkPresenter>
            
            <TextBlock Text="by 菩提树下的杨过" MouseLeftButtonDown="TextBlock_MouseLeftButtonDown" Cursor="Hand" Canvas.Left="5" Canvas.Top="5" Foreground="LightGray"></TextBlock>
        </Canvas>

        <StackPanel x:Name="spBtn" Grid.Row="3" Height="30" Margin="0" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button x:Name="btnToogleBg"  HorizontalAlignment="Center"  Width="80" Content="隐藏背景图" VerticalAlignment="Center" Click="btnToogleBg_Click"/>
            <Button x:Name="btnToogleBgRect"  HorizontalAlignment="Center"  Width="80" Content="隐藏背景色" VerticalAlignment="Center" Click="btnToogleBgRect_Click" Margin="10,0,0,0"/>
            <Button x:Name="btnSave"  HorizontalAlignment="Center"  Width="80" Content="保存图片" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnSave_Click"/>
            <Button x:Name="btnSaveLocal"  HorizontalAlignment="Center"  Width="90" Content="保存图片到本地" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnSaveLocal_Click" />
            <Button x:Name="btnClear"  HorizontalAlignment="Center"  Width="80" Content="清空画版" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnClear_Click"/>
            <Button x:Name="btnClearSave"  HorizontalAlignment="Center"  Width="80" Content="清空保存区" VerticalAlignment="Center" Margin="10,0,0,0" Click="btnClearSave_Click"/>
        </StackPanel>

        <ScrollViewer x:Name="ScreenshotViewer" Margin="0" Grid.Row="4" Background="#FFFFFF99" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
            <StackPanel x:Name="thumbs"  Orientation="Horizontal"/>
        </ScrollViewer>

    </Grid>

</UserControl>

 

 

后端代码:

by 菩提树下的杨过 http://yjmyzz.cnblogs.com/

using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Browser;
using System.Windows.Media.Imaging;
using System.IO;
using FluxJpeg.Core;

namespace InkPresenterTest
{
    public partial class Page : UserControl
    {
        Stroke _drawStroke;

        List<FillColor> lstFillColor;
        List<SizeData> lstSizeData;
        List<OpacityData> lstOpacityData;

        bool _isLoaded = false;

        public Page()
        {
            InitializeComponent();

            //初始化数据
            lstFillColor = new List<FillColor>() { 
                new FillColor(){ Color = new SolidColorBrush(Colors.Black), Name="黑色"},
                new FillColor(){ Color = new SolidColorBrush(Colors.Red), Name="红色"},
                new FillColor(){ Color = new SolidColorBrush(Colors.Blue), Name="蓝色"},
                new FillColor(){ Color = new SolidColorBrush(Colors.Green),Name="绿色"},
                new FillColor(){ Color = new SolidColorBrush(Colors.Magenta), Name="洋红"},               
                new FillColor(){ Color = new SolidColorBrush(Colors.Orange), Name="橙色"},
            };

            lstSizeData = new List<SizeData>()
            {
                new SizeData(){ Size=1.0},
                new SizeData(){ Size=3.0},
                new SizeData(){ Size=5.0},
                new SizeData(){ Size=7.0},
                new SizeData(){ Size=9.0},
                new SizeData(){ Size=11.0},
                new SizeData(){ Size=13.0},
                new SizeData(){ Size=15.0}
               
            };

            lstOpacityData = new List<OpacityData>(){
                new OpacityData(){ Value=0.1},
                new OpacityData(){ Value=0.2},
                new OpacityData(){ Value=0.3},
                new OpacityData(){ Value=0.4},
                new OpacityData(){ Value=0.5},
                new OpacityData(){ Value=0.6},
                new OpacityData(){ Value=0.7},
                new OpacityData(){ Value=0.8},
                new OpacityData(){ Value=0.9},
                new OpacityData(){ Value=1.0}
            };

            this.Loaded += new RoutedEventHandler(Page_Loaded);
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            this.cboColor.ItemsSource = lstFillColor;
            this.cboColor.SelectedIndex = 0;

            this.cboOutlineColor.ItemsSource = lstFillColor;
            this.cboOutlineColor.SelectedIndex = 0;

            this.cboWidth.ItemsSource = lstSizeData;
            this.cboWidth.SelectedIndex = 0;

            this.cboHeight.ItemsSource = lstSizeData;
            this.cboHeight.SelectedIndex = 0;

            this.cboOpactiy.ItemsSource = lstOpacityData;
            this.cboOpactiy.SelectedIndex = 5;

            _isLoaded = true;
        }

        private void OnMouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            ink.CaptureMouse();
            StylusPointCollection MyStylusPointCollection = new StylusPointCollection();
            MyStylusPointCollection.Add(e.StylusDevice.GetStylusPoints(ink));
            _drawStroke = new Stroke(MyStylusPointCollection);
            _drawStroke.DrawingAttributes.Color = (cboColor.SelectedItem as FillColor).Color.Color;
            _drawStroke.DrawingAttributes.OutlineColor = (this.cboOutlineColor.SelectedItem as FillColor).Color.Color;
            _drawStroke.DrawingAttributes.Width = (this.cboWidth.SelectedItem as SizeData).Size;
            _drawStroke.DrawingAttributes.Height = (this.cboHeight.SelectedItem as SizeData).Size;
            //_drawStroke.SetValue(OpacityProperty, (this.cboOpactiy.SelectedItem as OpacityData).Value);
            ink.Strokes.Add(_drawStroke);
            ink.Opacity = (cboOpactiy.SelectedItem as OpacityData).Value;
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (_drawStroke != null)
            {
                _drawStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(ink));
            }
        }

        private void OnLostMouseCapture(object sender, MouseEventArgs e)
        {
            _drawStroke = null;
        }

        private void btnClear_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            ink.Strokes.Clear();
        }

        private void cboOpactiy_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            if (_isLoaded)
            {
                ink.Opacity = (cboOpactiy.SelectedItem as OpacityData).Value;
            }
        }

        private void btnToogleBg_Click(object sender, RoutedEventArgs e)
        {
            Button btn = (sender as Button);
            if (btn.Content.ToString() == "隐藏背景图")
            {
                imgBg.Visibility = Visibility.Collapsed;
                btn.Content = "显示背景图";
            }
            else
            {
                imgBg.Visibility = Visibility.Visible;
                btn.Content = "隐藏背景图";
            }
        }

        private void btnToogleBgRect_Click(object sender, RoutedEventArgs e)
        {
            Button btn = (sender as Button);
            if (btn.Content.ToString() == "隐藏背景色")
            {
                this.rectBg.Visibility = Visibility.Collapsed;
                btn.Content = "显示背景色";
            }
            else
            {
                rectBg.Visibility = Visibility.Visible;
                btn.Content = "隐藏背景色";
            }
        }

        private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            HtmlPage.Window.Navigate(new System.Uri("http://yjmyzz.cnblogs.com/"), "_blank");
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            // 创建一个WriteableBitmap并且把需要呈现位图的元素赋值给WriteableBitmap
            WriteableBitmap wb = new WriteableBitmap(inkC, null);

            // 创建一个Image元素来承载位图
            System.Windows.Controls.Image image = new System.Windows.Controls.Image();
            image.Height = 120;
            image.Margin = new Thickness(5);
            image.Source = wb;

            // 将Image元素放入容器控件中
            thumbs.Children.Add(image);

            ScreenshotViewer.ScrollToHorizontalOffset(ScreenshotViewer.ExtentWidth);

        }

        private void btnClearSave_Click(object sender, RoutedEventArgs e)
        {
            thumbs.Children.Clear();
        }

        private void btnSaveLocal_Click(object sender, RoutedEventArgs e)
        {
            WriteableBitmap wb = new WriteableBitmap(inkC, null);

            if (wb != null)
            {
                SaveFileDialog saveDlg = new SaveFileDialog();
                saveDlg.Filter = "JPEG Files (*.jpeg)|*.jpeg";
                saveDlg.DefaultExt = ".jpeg";

                if (saveDlg.ShowDialog().Value)
                {
                    using (Stream fs = saveDlg.OpenFile())
                    {
                        SaveToFile(wb, fs);
                        MessageBox.Show(string.Format("文件已经保存至“{0}”",saveDlg.SafeFileName));
                    }
                }
            }

        }

        private void SaveToFile(WriteableBitmap bitmap, Stream fs)
        {
            int width = bitmap.PixelWidth;
            int height = bitmap.PixelHeight;
            int bands = 3;
            byte[][,] raster = new byte[bands][,];

            for (int i = 0; i < bands; i++)
            {
                raster[i] = new byte[width, height];
            }

            for (int row = 0; row < height; row++)
            {
                for (int column = 0; column < width; column++)
                {
                    int pixel = bitmap.Pixels[width * row + column];
                    raster[0][column, row] = (byte)(pixel >> 16);
                    raster[1][column, row] = (byte)(pixel >> 8);
                    raster[2][column, row] = (byte)pixel;
                }

            }

            FluxJpeg.Core.ColorModel model = new FluxJpeg.Core.ColorModel { colorspace = FluxJpeg.Core.ColorSpace.RGB };
            FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);

            //Encode the Image as a JPEG
            MemoryStream stream = new MemoryStream();
            FluxJpeg.Core.Encoder.JpegEncoder encoder = new FluxJpeg.Core.Encoder.JpegEncoder(img, 100, stream);
            encoder.Encode();

            //Back to the start
            stream.Seek(0, SeekOrigin.Begin);

            //Get teh Bytes and write them to the stream
            byte[] binaryData = new byte[stream.Length];
            long bytesRead = stream.Read(binaryData, 0, (int)stream.Length);
            fs.Write(binaryData, 0, binaryData.Length);
        }

    }

    public class FillColor
    {
        public SolidColorBrush Color { set; get; }
        public string Name { set; get; }
    }

    public class SizeData
    {
        public double Size { set; get; }
    }

    public class OpacityData
    {
        public double Value { set; get; }
    }
}

 

 

源代码下载地址: http://files.cnblogs.com/yjmyzz/InkPresenterTest.rar

对Flash感兴趣的朋友,做为对比,也可以看下Flash/Flex学习笔记(14):制作涂鸦板 

转载请注明来自菩提树下的杨过 http://www.cnblogs.com/yjmyzz/archive/2010/01/14/1647636.html

 

注:里面用到了一个开源的组件FJCore

时间: 2024-08-30 18:18:40

silverlight:手写板/涂鸦/墨迹/InkPresenter示例程序的相关文章

关于继承内部类——java编程思想示例程序分析

编程|程序|继承|示例 关于继承内部类--java编程思想示例程序分析:class Egg2 { protected class Yolk { public Yolk() { System.out.println("Egg2.Yolk()"); } public void f() { System.out.println("Egg2.Yolk.f()"); } } private Yolk y = new Yolk(); public Egg2() { System

RapidWebDev框架 - 快速开发产品管理示例程序

首先,我们按照以往的思路,先将上一章中的t_product进行一定的扩展,如下图: 开发产品管理示例程序-net快速开发框架">在这里,我增加了一张T_PRODUCT_CATEGORY表,用于存放产品分类信息,分类为树型结构,另外增加了一个T_WAREHOUSE表,用于存放仓库信信息,然后在T_PRODUCT增加了相应的外键和一些扩展字段.有了数据表,就开始分别对分类和仓库建了对应的管理代码(CRUD, UI等),然后在产品页面对其调用.为了节约篇幅,这里就不贴这些代码了,反正是一大堆.

使用nodejs如何读取memcache的示例程序

 本人主要介绍了使用nodejs如何读取memcache的示例程序,大家参考使用吧 代码如下: var memcache = require('memcache')     , http = require('http')     , url = require('url')     , qs = require('querystring')     , memsettings = { port: 2000, host: '10.6.0.6' }     , httpsettings = { p

中文语音识别-LD3320链接51示例程序

问题描述 LD3320链接51示例程序 请问有人玩过用51控制LD3320的吗?本人初次玩,水平有限,求助大家,望助 解决方案 http://download.csdn.net/download/zlm867953489/8007009 解决方案二: http://download.csdn.net/download/zlm867953489/8007009 解决方案三: 源代码,编译时前两个头文件找不到,还有后面怎么会有P4口的? #include"LE52.h" #include

Python Socket 编程——聊天室示例程序

原文:Python Socket 编程--聊天室示例程序 上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的理解. 聊天室程序需求 我们要实现的是简单的聊天室的例子,就是允许多个人同时一起聊天,每个人发送的消息所有人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天.如下图: 图来自:http://www.ibm.com/de

Android闪屏示例程序

 用过手机QQ的基本上都知道,刚启动程序时候会在一个界面停留一会,按任意键的就直接跳过,这就是所谓的闪屏.那么,在Android中怎样实现这样的效果呢?  1.新建一个Android项目,命名为SplashyDemo,结构如下所示: 2. 添加资源图片: 首先我们得有闪屏时候显示的图片资源文件,并将图片放在res/drawable目录下,命名为splash.jpg: 这时候会在R类中自动添加资源文件对应的ID,如下所示: 3.编写闪屏的界面布局文件,放在res/layout目录下,如下图: 该布

示例程序运行问题-cocos2dx的android开发遇到的问题

问题描述 cocos2dx的android开发遇到的问题 在eclipse导入编译好的cocos2dx示例程序Helloworld,出现17个错误,查了一下貌似是eclipse无法导入cocos2dx的java框架,怎么办呢?求cocos2dx大神解答 补充一下,17个错误都出现在Cocos2dxGLSurfaceView.java文件中 解决方案 你要把 cocos2dxplatformandroidjavasrc下的org 文件夹 拷贝到 你的android工程src目录 解决方案二: wi

mfc teechart-teechart5 如何显示x轴为时间轴的历史曲线,求示例程序

问题描述 teechart5 如何显示x轴为时间轴的历史曲线,求示例程序 读取Sqlserver数据库,取得数据后在teechart5控件上如何显示x轴为时间轴的历史曲线,尤其是时间轴的显示,求示例程序

《R与Hadoop大数据分析实战》一2.4 编写Hadoop MapReduce示例程序

2.4 编写Hadoop MapReduce示例程序 现在要通过一个很简单且普通的单词统计(word count)来学习MapReduce.该例子的目标是统计每个单词在文章中出现的次数.这些文章作为MapReduce的输入文件. 在该例中,已经准备了一些文本文件,我们希望计算所有单词在这些文件中出现的频率.我们通过Hadoop MapReduce来进行设计. 本节中,将使用旧版API接口学习Hadoop MapReduce编程.假设读者已经配置了Hadoop的环境变量(请参考第1章的内容).同时