Silverlight实现对图片的涂鸦、绘制矩形、圆形、直线、文本,并且能够移动

 http://archive.cnblogs.com/a/2270389/

 

经理让找找Silverlight实现画图的功能,找了老半天,根据前辈人的经验和思路自己汇总了一个画图工具,基本上实现对图片的涂鸦、绘制图形、添加文本的功能,希望能对大家开发新的图片编辑器有所帮助,下面所以下我的思路,并奉上我的代码。

首先我想到使用InkPresenter控件,实现图形的编辑,然后将InkPresenters上的控件进行保存为Pngs图片。

我们需要监听InkPresenter控件的三个事件, MouseLeftButtonUp、MouseMove 、MouseLeftButtonDown,为了让我的代码显得比较整齐,我用枚举类型来告诉InkPresenter我要干什么

我将我要画得每一个元素以枚举类型描述出来

由于代码比较简单,我就不做详细解说了,直接给代码附上:

页面代码:

<UserControl x:Class="PicDraw.ImageEdit"
    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"
    >
    <Grid ShowGridLines="False" Margin="0" >
        <Grid.RowDefinitions >
            <RowDefinition Height="35"/>
            <RowDefinition Height="600"/>
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <Canvas Grid.ColumnSpan="2"  Grid.Row="0"  Grid.Column="0" Width="1150"    HorizontalAlignment="Left" Background="#0054e3" >
            <TextBlock    Margin="10 5 0 0" Height="35"   FontSize="16" Foreground="White" Text="画图工具" ></TextBlock>
        </Canvas>
        <StackPanel VerticalAlignment="Top"  Background="#e5eff8" Width="150" Height="600" Grid.Row="1" Grid.Column="0">
            <Grid Margin="10 0 0 0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="400"></RowDefinition>
                    <RowDefinition Height="200"></RowDefinition>
                </Grid.RowDefinitions>
                <StackPanel Grid.Row="0">
                    <TextBlock Width="150">工具栏</TextBlock>
                    <Grid OpacityMask="#FFEF1C1C" ShowGridLines="False">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                            <RowDefinition></RowDefinition>
                        </Grid.RowDefinitions>
                        <Button Name="saveBTN" Click="saveBTN_Click" Grid.Row="0" Grid.Column="0" 
                                 Margin="5" >
                            保存
                        </Button>
                        <Button Name="openBTN" Click="openBTN_Click" Grid.Row="0" Grid.Column="1" 
                                 Margin="5" >
                            打开
                        </Button>

                        <Button 
                            Name="eraserBtn" 
                            Grid.Row="4" 
                            Grid.Column="0" 
                            Margin="5" Click="toolBTN_Clik" >
                            橡皮擦
                        </Button>
                        <Button Name="bushBtn" Grid.Row="1" Grid.Column="1" Margin="5" Click="toolBTN_Clik">
                            画笔
                        </Button>
                        <Button Name="txtBtn" Grid.Row="1" Grid.Column="0"  Margin="5" Click="toolBTN_Clik">
                            文本
                        </Button>
                        <Button Name="BorderBtn" Grid.Row="2" Grid.Column="0"  Margin="5" Click="toolBTN_Clik">
                            矩形
                        </Button>
                        <Button Name="circleBtn" Grid.Row="2" Grid.Column="1" Margin="5"  Click="toolBTN_Clik" 
                         >画圆</Button>
                        <Button Grid.Row="3" Grid.Column="0"  Margin="5" Name="lineBtn" Click="toolBTN_Clik">划线
                        </Button>
                        <Button Name="arrowsBtn" Grid.Row="3" Grid.Column="1"  Margin="5" Click="toolBTN_Clik" >箭头
                        </Button>
                    </Grid>
                </StackPanel>
                <StackPanel Grid.Row="1" Opacity="5">
                    <TextBlock Width="150">颜色</TextBlock>
                    <ListBox Name="colorLBX" FlowDirection="LeftToRight"  UseLayoutRounding="True" TabNavigation="Local" SelectionChanged="ListBox_SelectionChanged">
                        <ListBoxItem Background="White">White</ListBoxItem>
                        <ListBoxItem Background="Red">Red</ListBoxItem>
                        <ListBoxItem Background="Green">Green</ListBoxItem>
                        <ListBoxItem Background="Blue" >Blue</ListBoxItem>
                        <ListBoxItem Background="Black" Foreground="White" >Black</ListBoxItem>
                        <ListBoxItem></ListBoxItem>
                    </ListBox>
                    <TextBlock Name="lineWidthTBK">线宽为:5</TextBlock>
                    <Slider Name="lineWidthSD" Width="100" Minimum="0"  Value="5" Maximum="10" ValueChanged="lineWidthSD_ValueChanged" SmallChange="1" />
                </StackPanel>
               
            </Grid>

        </StackPanel>
        <Canvas  
            ScrollViewer.HorizontalScrollBarVisibility="Visible"
            ScrollViewer.VerticalScrollBarVisibility="Visible"
            Name="cnsDesignerContainer" 
            Grid.Row="1" Grid.Column="1"
            VerticalAlignment="Top"
            HorizontalAlignment="Left"
            Width="1000"
            Height="600"
            Background="#dcdcdc">
            <InkPresenter x:Name="inkPresenter" MouseLeftButtonDown="inkPresenter_MouseLeftButtonDown" 
                          MouseLeftButtonUp="inkPresenter_MouseLeftButtonUp"
                          MouseMove="inkPresenter_MouseMove"
                          Cursor="Stylus" Canvas.ZIndex="-1" Background="Transparent">
                <Image Name="test"
                       MaxHeight="600"
                       Canvas.ZIndex="-1"
                       MaxWidth="1000"
                       Source="/PicDraw;component/Images/Penguins.jpg">                    
                </Image>
            </InkPresenter>
        </Canvas>
    </Grid>
</UserControl>


 后台代码实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Imaging;
using System.Windows.Ink;
using System.IO;
namespace PicDraw
{

    public partial class ImageEdit : UserControl
    {
        /// <summary>
        /// 起始点
        /// </summary>
        private Ellipse ellipse = new Ellipse();
        // 在涂鸦板上描绘的笔划
        private System.Windows.Ink.Stroke _newStroke;

        // 在涂鸦板上描绘的笔划的颜色
        private System.Windows.Media.Color _currentColor = Colors.Red;
        private double lineWidth = 5d;
        private SharpType sharpType = SharpType.brush;

        // 当前是否正在 InkPresenter 上捕获鼠标
        private bool _isCapture = false;
        private bool _isStrart = true;
        private double _startX = 0, _startY = 0;
        bool trackingMouseMove = false;
        Point mousePosition;


        public ImageEdit()
        {
            InitializeComponent();
            this.inkPresenter.Height = test.Height;
            this.inkPresenter.Width = test.Width;
        }

        #region 工具栏
        /// <summary>
        /// 颜色选择器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selectItem = colorLBX.SelectedItem as ListBoxItem;
            var bu = selectItem.Background as SolidColorBrush;
            _currentColor = bu.Color;

        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveBTN_Click(object sender, RoutedEventArgs e)
        {
            //保存InkPresenter涂鸦板内绘画的图
            WriteableBitmap _bitmap = new WriteableBitmap(inkPresenter, null);
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "PNG Files (*.png)|*.png|All Files (*.*)|*.*";
            sfd.DefaultExt = ".png";
            sfd.FilterIndex = 1;

            if ((bool)sfd.ShowDialog())
            {
                using (Stream fs = sfd.OpenFile())
                {
                    int width = _bitmap.PixelWidth;
                    int height = _bitmap.PixelHeight;

                    EditableImage ei = new EditableImage(width, height);

                    for (int i = 0; i < height; i++)
                    {
                        for (int j = 0; j < width; j++)
                        {
                            int pixel = _bitmap.Pixels[(i * width) + j];
                            ei.SetPixel(j, i,
                                        (byte)((pixel >> 16) & 0xFF),
                                        (byte)((pixel >> 8) & 0xFF),
                                        (byte)(pixel & 0xFF),
                                        (byte)((pixel >> 24) & 0xFF)
                            );
                        }
                    }
                    //获取流
                    Stream png = ei.GetStream();
                    int len = (int)png.Length;
                    byte[] bytes = new byte[len];
                    png.Read(bytes, 0, len);
                    fs.Write(bytes, 0, len);
                    MessageBox.Show("图片保存成功!");
                }
            }
        }

        /// <summary>
        /// 工具栏
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void toolBTN_Clik(object sender, RoutedEventArgs e)
        {
            _startX = 0;
            _startY = 0;
            _isStrart = true;
            var btn = sender as Button;
            var name = btn.Name;
            if (name.Equals("eraserBtn"))
            {
                inkPresenter.Cursor = Cursors.Eraser;
                this.sharpType = SharpType.eraser;
                return;
            }
            if (name.Equals("bushBtn"))
            {
                this.sharpType = SharpType.brush;
                return;
            }
            if (name.Equals("txtBtn"))
            {
                this.sharpType = SharpType.text;
                return;
            }
            if (name.Equals("BorderBtn"))
            {
                this.sharpType = SharpType.border;
                return;
            }
            if (name.Equals("circleBtn"))
            {
                this.sharpType = SharpType.ellipse;
                return;
            }
            if (name.Equals("arrowsBtn"))
            {
                inkPresenter.Cursor = Cursors.Arrow;
                this.sharpType = SharpType.pointer;
                return;
            }
            if (name.Equals("lineBtn"))
            {
                this.sharpType = SharpType.line;
                return;
            }
        }

        #endregion

        #region 涂鸦板的操作

        private void inkPresenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            inkPresenter.CaptureMouse();
            _isCapture = true;

            switch (sharpType)
            {
                case SharpType.border: BorderStroke(e, false); break;
                case SharpType.brush: BrushStroke(e); break;
                case SharpType.ellipse: EllipseStroke(e, false); break;
                case SharpType.line: LineStroke(e, false); break;
                case SharpType.text: TextStroke(e, false); break;
            }
        }

        private void inkPresenter_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            inkPresenter.ReleaseMouseCapture();
            _newStroke = null;
            _isCapture = false;
        }
        private void inkPresenter_MouseMove(object sender, MouseEventArgs e)
        {
            if (_isCapture)
            {
                switch (sharpType)
                {
                    case SharpType.brush: BrushStroke(e); break;
                    //case SharpType.border: BorderStroke(e, true); break;
                    //case SharpType.ellipse: EllipseStroke(e, true); break;
                    //case SharpType.line: LineStroke(e, true); break;
                }
            }
        }

        #region 操作板

        private void TextStroke(MouseEventArgs e, bool isMove)
        {
            Point p = e.GetPosition(inkPresenter);
            if (_isStrart)
            {
                TextBox txtBox = new TextBox();
                txtBox.Height = 30;
                txtBox.Width = 200;
                txtBox.Text = "请输入字体";
                //字体颜色
                txtBox.Foreground = new SolidColorBrush(_currentColor);
                txtBox.BorderBrush = null;
                txtBox.Background = null;
                txtBox.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
                txtBox.MouseMove += new MouseEventHandler(OnMouseMove);
                txtBox.MouseLeftButtonUp += new MouseButtonEventHandler(OnMouseUp);
                txtBox.TextChanged += null;
                Canvas.SetTop(txtBox, p.Y);
                Canvas.SetLeft(txtBox, p.X);
                Canvas.SetZIndex(txtBox, 1);
                inkPresenter.Children.Add(txtBox);
                
                //<TextBox Background="{x:Null}" BorderBrush="{x:Null}" FontWeight="Bold"></TextBox>
            }
        }        

        #region 划线操作

        private Line startLine = null;
        /// <summary>
        /// 划线处理事件
        /// </summary>
        /// <param name="e"></param>
        /// <param name="isMove">是否为移动鼠标,</param>
        private void LineStroke(MouseEventArgs e, bool isMove)
        {
            var point = e.GetPosition(this.inkPresenter);

            //如果刚开始则话一个点
            if (_isStrart)
            {
                _startX = point.X;
                _startY = point.Y;
                DrawPoint(_startX, _startY);
            }
            else
            {
                DrawOneLine(_startX, _startY, point.X, point.Y, isMove);
            }
            _isStrart = !_isStrart;

        }

        /// <summary>
        /// 画一个点
        /// </summary>
        /// <param name="pX1"></param>
        /// <param name="pY1"></param>
        private void DrawPoint(double pX1, double pY1)
        {
            if (inkPresenter.Children.Contains(ellipse))
            {
                inkPresenter.Children.Remove(ellipse);
            }

            ellipse.Stroke = new SolidColorBrush(_currentColor);//动态设置Stroke属性的方法。
            ellipse.StrokeThickness = 2;
            ellipse.Width = 4;
            ellipse.Height = 4;
            Canvas.SetLeft(ellipse, pX1);
            Canvas.SetTop(ellipse, pY1);
            Canvas.SetZIndex(ellipse, 1);
            inkPresenter.Children.Add(ellipse);
        }
        /// <summary>
        /// 画一根线
        /// </summary>
        /// <param name="pX1"></param>
        /// <param name="pY1"></param>
        /// <param name="pX2"></param>
        /// <param name="pY2"></param>
        /// <returns></returns>
        private void DrawOneLine(double pX1, double pY1, double pX2, double pY2, bool isMove)
        {
            inkPresenter.Children.Remove(startLine);
            if (isMove)
            {
                startLine = new Line();
                startLine.X1 = pX1;
                startLine.Y1 = pY1;
                startLine.X2 = pX2;
                startLine.Y2 = pY2;
                startLine.StrokeThickness = lineWidth;
                startLine.Stroke = new SolidColorBrush(_currentColor);
                Canvas.SetZIndex(startLine, 1);
                inkPresenter.Children.Add(startLine);
                return;

            }
            else
            {
                Line lastLine = new Line();
                lastLine.X1 = pX1;
                lastLine.Y1 = pY1;
                lastLine.X2 = pX2;
                lastLine.Y2 = pY2;
                lastLine.Stroke = new SolidColorBrush(_currentColor);
                lastLine.StrokeThickness = lineWidth;
                lastLine.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
                lastLine.MouseMove += new MouseEventHandler(OnMouseMove);
                lastLine.MouseLeftButtonUp += new MouseButtonEventHandler(OnMouseUp);
                //移除起始线

                Canvas.SetZIndex(lastLine, 1);
                //清空startLine的内容
                startLine = null;
                inkPresenter.Children.Add(lastLine);
                return;
            }
        }


        
        #endregion

        #region 移动控件
        void OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (sharpType == SharpType.pointer)
            {
                FrameworkElement element = sender as FrameworkElement;//当前元件
                mousePosition = e.GetPosition(null);//鼠标位置
                trackingMouseMove = true;
                if (null != element)
                {
                    element.CaptureMouse();//设置鼠标捕获
                    element.Cursor = Cursors.Hand;
                }
            }
        }
        void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (sharpType == SharpType.pointer)
            {
                FrameworkElement element = sender as FrameworkElement;
                if (trackingMouseMove)
                {
                    //计算位置
                    double deltaV = e.GetPosition(null).Y - mousePosition.Y;
                    double deltaH = e.GetPosition(null).X - mousePosition.X;
                    double newTop = deltaV + (double)element.GetValue(Canvas.TopProperty);
                    double newLeft = deltaH + (double)element.GetValue(Canvas.LeftProperty);
                    //GetValue();SetValue();
                    element.SetValue(Canvas.TopProperty, newTop);
                    element.SetValue(Canvas.LeftProperty, newLeft);

                    mousePosition = e.GetPosition(null);
                }
            }
        }
        void OnMouseUp(object sender, MouseButtonEventArgs e)
        {
            if (sharpType == SharpType.pointer)
            {
                FrameworkElement element = sender as FrameworkElement;
                trackingMouseMove = false;
                element.ReleaseMouseCapture();//释放鼠标

                mousePosition.X = mousePosition.Y = 0;
                element.Cursor = null;
            }
            if (sharpType == SharpType.eraser)
            {
                inkPresenter.Children.Remove(sender as UIElement);
            }
        }
        #endregion

        #region 画圆
         private void EllipseStroke(MouseEventArgs e, bool isMove)
        {
            Point p = e.GetPosition(this.inkPresenter);
            if (this._isStrart)
            {
                _startX = p.X;//设置起点坐标
                _startY = p.Y;
                DrawPoint(p.X, p.Y);
            }
            else
            {
                DrawCrile(_startX,_startY, p.X, p.Y,isMove);
            }
            _isStrart = !_isStrart;
        }
        private void DrawCrile(double pX1, double pY1, double pX2, double pY2,bool isMove)
        {
            if (isMove)
            { }
            else
            {
                Ellipse e = new Ellipse();
                e.Height = System.Math.Sqrt(System.Math.Abs(pX1 - pX2) * System.Math.Abs(pX1 - pX2) + System.Math.Abs(pY1 - pY2) * System.Math.Abs(pY1 - pY2)) * 2;
                e.Width = e.Height;
                e.Stroke = new SolidColorBrush(_currentColor);
                e.StrokeThickness = this.lineWidth;
                e.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
                e.MouseMove += new MouseEventHandler(OnMouseMove);
                e.MouseLeftButtonUp += new MouseButtonEventHandler(OnMouseUp);
                Canvas.SetZIndex(e, 10);
                Canvas.SetTop(e, pY1 - e.Height / 2);
                Canvas.SetLeft(e, pX1 - e.Height / 2);
                inkPresenter.Children.Add(e);
            }
        }

        #endregion

        #region 矩形
        private void BorderStroke(MouseEventArgs e, bool isMove)
        {
            Point p = e.GetPosition(this.inkPresenter);
            if (_isStrart)
            {
                _startX = p.X;//设置起点坐标
                _startY = p.Y;
                DrawPoint(p.X, p.Y);
            }
            else
            {
                DrawBord(_startX, _startY, p.X, p.Y,isMove);
            }
            _isStrart = !_isStrart;
        }

        private void DrawBord(double _startX, double _startY, double pX2, double pY2, bool isMove)
        {
            if (isMove)
            { }
            else
            {
                Border b = new Border();
                b.Width = System.Math.Abs(pX2 - _startX);
                b.Height = System.Math.Abs(pY2 - _startY);
                b.BorderThickness = new Thickness(lineWidth);
                //动态设置矩形的颜色
                b.BorderBrush = new SolidColorBrush(_currentColor);
                b.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseDown);
                b.MouseMove += new MouseEventHandler(OnMouseMove);
                b.MouseLeftButtonUp += new MouseButtonEventHandler(OnMouseUp);
                Canvas.SetLeft(b, _startX > pX2 ? pX2 : _startX);
                Canvas.SetTop(b, _startY > pY2 ? pY2 : _startY);
                Canvas.SetZIndex(b, 1000);
                this.inkPresenter.Children.Add(b);
 
            }
        }
        #endregion

        private void BrushStroke(MouseEventArgs e)
        {
            if (_newStroke != null)
            {
                _newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkPresenter));
            }
            _newStroke = new System.Windows.Ink.Stroke();
            _newStroke.DrawingAttributes.Width = lineWidth;
            _newStroke.DrawingAttributes.Height = lineWidth;
            _newStroke.DrawingAttributes.Color = _currentColor;
            _newStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(inkPresenter));
            inkPresenter.Strokes.Add(_newStroke);
        }        

        
        #endregion

        private void lineWidthSD_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (lineWidthTBK != null)
            {
                lineWidthTBK.Text = "线宽为:" + lineWidthSD.Value;
                this.lineWidth = lineWidthSD.Value;
            }
            
        }
        #endregion

        private void openBTN_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog o = new OpenFileDialog() { 
             Multiselect=false,
             Filter="图片文件(*.jpg,*.gif,*.bmp,*.png)|*.jpg;*.gif;*.bmp;*.png"
            };
            if (o.ShowDialog() == true)
            {
                using (Stream stream = o.File.OpenRead())
                {
                    //获取图片流信息并完成与Image控件的绑定
                    BitmapImage image = new BitmapImage();
                    image.SetSource(stream);
                    inkPresenter.Children.Clear();
                    Image img = new Image();
                    Canvas.SetLeft(img, 0);
                    Canvas.SetTop(img, 0);
                    Canvas.SetZIndex(img, -1);
                    img.Source = image;
                    img.MaxWidth = 1000;
                    img.MaxHeight = 600;
                    inkPresenter.Children.Add(img);
                    stream.Close();
                }                
            }
        }

    }
}


图片转为Png

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;

namespace PicDraw
{
    public class EditableImage
    {
        private int _width = 0;
        private int _height = 0;
        private bool _init = false;
        private byte[] _buffer;
        private int _rowLength;

        /// <summary>
        /// 当图片错误时引发
        /// </summary>
        public event EventHandler<EditableImageErrorEventArgs> ImageError;

        /// <summary>
        /// 实例化
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public EditableImage(int width, int height)
        {
            this.Width = width;
            this.Height = height;
        }

        public int Width
        {
            get
            {
                return _width;
            }
            set
            {
                if (_init)
                {
                    OnImageError("错误: 图片初始化后不可以改变宽度");
                }
                else if ((value <= 0) || (value > 2047))
                {
                    OnImageError("错误: 宽度必须在 0 到 2047");
                }
                else
                {
                    _width = value;
                }
            }
        }

        public int Height
        {
            get
            {
                return _height;
            }
            set
            {
                if (_init)
                {
                    OnImageError("错误: 图片初始化后不可以改变高度");
                }
                else if ((value <= 0) || (value > 2047))
                {
                    OnImageError("错误: 高度必须在 0 到 2047");
                }
                else
                {
                    _height = value;
                }
            }
        }

        public void SetPixel(int col, int row, Color color)
        {
            SetPixel(col, row, color.R, color.G, color.B, color.A);
        }

        public void SetPixel(int col, int row, byte red, byte green, byte blue, byte alpha)
        {
            if (!_init)
            {
                _rowLength = _width * 4 + 1;
                _buffer = new byte[_rowLength * _height];

                // Initialize
                for (int idx = 0; idx < _height; idx++)
                {
                    _buffer[idx * _rowLength] = 0;      // Filter bit
                }

                _init = true;
            }

            if ((col > _width) || (col < 0))
            {
                OnImageError("Error: Column must be greater than 0 and less than the Width");
            }
            else if ((row > _height) || (row < 0))
            {
                OnImageError("Error: Row must be greater than 0 and less than the Height");
            }

            // Set the pixel
            int start = _rowLength * row + col * 4 + 1;
            _buffer[start] = red;
            _buffer[start + 1] = green;
            _buffer[start + 2] = blue;
            _buffer[start + 3] = alpha;
        }

        public Color GetPixel(int col, int row)
        {
            if ((col > _width) || (col < 0))
            {
                OnImageError("Error: Column must be greater than 0 and less than the Width");
            }
            else if ((row > _height) || (row < 0))
            {
                OnImageError("Error: Row must be greater than 0 and less than the Height");
            }

            Color color = new Color();
            int _base = _rowLength * row + col + 1;

            color.R = _buffer[_base];
            color.G = _buffer[_base + 1];
            color.B = _buffer[_base + 2];
            color.A = _buffer[_base + 3];

            return color;
        }

        public Stream GetStream()
        {
            Stream stream;

            if (!_init)
            {
                OnImageError("Error: Image has not been initialized");
                stream = null;
            }
            else
            {
                stream = PngEncoder.Encode(_buffer, _width, _height);
            }

            return stream;
        }

        private void OnImageError(string msg)
        {
            if (null != ImageError)
            {
                EditableImageErrorEventArgs args = new EditableImageErrorEventArgs();
                args.ErrorMessage = msg;
                ImageError(this, args);
            }
        }

        public class EditableImageErrorEventArgs : EventArgs
        {
            private string _errorMessage = string.Empty;

            public string ErrorMessage
            {
                get { return _errorMessage; }
                set { _errorMessage = value; }
            }
        }
    }

    /// <summary>
    /// PNG格式操作类
    /// </summary>
    public class PngEncoder
    {
        private const int _ADLER32_BASE = 65521;
        private const int _MAXBLOCK = 0xFFFF;
        private static byte[] _HEADER = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
        private static byte[] _IHDR = { (byte)'I', (byte)'H', (byte)'D', (byte)'R' };
        private static byte[] _GAMA = { (byte)'g', (byte)'A', (byte)'M', (byte)'A' };
        private static byte[] _IDAT = { (byte)'I', (byte)'D', (byte)'A', (byte)'T' };
        private static byte[] _IEND = { (byte)'I', (byte)'E', (byte)'N', (byte)'D' };
        private static byte[] _4BYTEDATA = { 0, 0, 0, 0 };
        private static byte[] _ARGB = { 0, 0, 0, 0, 0, 0, 0, 0, 8, 6, 0, 0, 0 };

        /// <summary>
        /// 编码
        /// </summary>
        /// <param name="data"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Stream Encode(byte[] data, int width, int height)
        {
            MemoryStream ms = new MemoryStream();
            byte[] size;

            // Write PNG header
            ms.Write(_HEADER, 0, _HEADER.Length);

            // Write IHDR
            //  Width:              4 bytes
            //  Height:             4 bytes
            //  Bit depth:          1 byte
            //  Color type:         1 byte
            //  Compression method: 1 byte
            //  Filter method:      1 byte
            //  Interlace method:   1 byte

            size = BitConverter.GetBytes(width);
            _ARGB[0] = size[3]; _ARGB[1] = size[2]; _ARGB[2] = size[1]; _ARGB[3] = size[0];

            size = BitConverter.GetBytes(height);
            _ARGB[4] = size[3]; _ARGB[5] = size[2]; _ARGB[6] = size[1]; _ARGB[7] = size[0];

            // Write IHDR chunk
            WriteChunk(ms, _IHDR, _ARGB);

            // Set gamma = 1
            size = BitConverter.GetBytes(1 * 100000);
            _4BYTEDATA[0] = size[3]; _4BYTEDATA[1] = size[2]; _4BYTEDATA[2] = size[1]; _4BYTEDATA[3] = size[0];

            // Write gAMA chunk
            WriteChunk(ms, _GAMA, _4BYTEDATA);

            // Write IDAT chunk
            uint widthLength = (uint)(width * 4) + 1;
            uint dcSize = widthLength * (uint)height;

            // First part of ZLIB header is 78 1101 1010 (DA) 0000 00001 (01)
            // ZLIB info
            //
            // CMF Byte: 78
            //  CINFO = 7 (32K window size)
            //  CM = 8 = (deflate compression)
            // FLG Byte: DA
            //  FLEVEL = 3 (bits 6 and 7 - ignored but signifies max compression)
            //  FDICT = 0 (bit 5, 0 - no preset dictionary)
            //  FCHCK = 26 (bits 0-4 - ensure CMF*256+FLG / 31 has no remainder)
            // Compressed data
            //  FLAGS: 0 or 1
            //    00000 00 (no compression) X (X=1 for last block, 0=not the last block)
            //    LEN = length in bytes (equal to ((width*4)+1)*height
            //    NLEN = one's compliment of LEN
            //    Example: 1111 1011 1111 1111 (FB), 0000 0100 0000 0000 (40)
            //    Data for each line: 0 [RGBA] [RGBA] [RGBA] ...
            //    ADLER32

            uint adler = ComputeAdler32(data);
            MemoryStream comp = new MemoryStream();

            // 64K的块数计算
            uint rowsPerBlock = _MAXBLOCK / widthLength;
            uint blockSize = rowsPerBlock * widthLength;
            uint blockCount;
            ushort length;
            uint remainder = dcSize;

            if ((dcSize % blockSize) == 0)
            {
                blockCount = dcSize / blockSize;
            }
            else
            {
                blockCount = (dcSize / blockSize) + 1;
            }

            // 头部
            comp.WriteByte(0x78);
            comp.WriteByte(0xDA);

            for (uint blocks = 0; blocks < blockCount; blocks++)
            {
                // 长度
                length = (ushort)((remainder < blockSize) ? remainder : blockSize);

                if (length == remainder)
                {
                    comp.WriteByte(0x01);
                }
                else
                {
                    comp.WriteByte(0x00);
                }

                comp.Write(BitConverter.GetBytes(length), 0, 2);

                comp.Write(BitConverter.GetBytes((ushort)~length), 0, 2);

                // Write 块
                comp.Write(data, (int)(blocks * blockSize), length);

                //下一块
                remainder -= blockSize;
            }

            WriteReversedBuffer(comp, BitConverter.GetBytes(adler));
            comp.Seek(0, SeekOrigin.Begin);

            byte[] dat = new byte[comp.Length];
            comp.Read(dat, 0, (int)comp.Length);

            WriteChunk(ms, _IDAT, dat);

            // Write IEND chunk
            WriteChunk(ms, _IEND, new byte[0]);

            // Reset stream
            ms.Seek(0, SeekOrigin.Begin);

            return ms;
        }

        private static void WriteReversedBuffer(Stream stream, byte[] data)
        {
            int size = data.Length;
            byte[] reorder = new byte[size];

            for (int idx = 0; idx < size; idx++)
            {
                reorder[idx] = data[size - idx - 1];
            }
            stream.Write(reorder, 0, size);
        }

        private static void WriteChunk(Stream stream, byte[] type, byte[] data)
        {
            int idx;
            int size = type.Length;
            byte[] buffer = new byte[type.Length + data.Length];

            // 初始化缓冲
            for (idx = 0; idx < type.Length; idx++)
            {
                buffer[idx] = type[idx];
            }

            for (idx = 0; idx < data.Length; idx++)
            {
                buffer[idx + size] = data[idx];
            }

            WriteReversedBuffer(stream, BitConverter.GetBytes(data.Length));

            // Write 类型和数据
            stream.Write(buffer, 0, buffer.Length);   // Should always be 4 bytes

            // 计算和书写的CRC

            WriteReversedBuffer(stream, BitConverter.GetBytes(GetCRC(buffer)));
        }

        private static uint[] _crcTable = new uint[256];
        private static bool _crcTableComputed = false;

        private static void MakeCRCTable()
        {
            uint c;

            for (int n = 0; n < 256; n++)
            {
                c = (uint)n;
                for (int k = 0; k < 8; k++)
                {
                    if ((c & (0x00000001)) > 0)
                        c = 0xEDB88320 ^ (c >> 1);
                    else
                        c = c >> 1;
                }
                _crcTable[n] = c;
            }

            _crcTableComputed = true;
        }

        private static uint UpdateCRC(uint crc, byte[] buf, int len)
        {
            uint c = crc;

            if (!_crcTableComputed)
            {
                MakeCRCTable();
            }

            for (int n = 0; n < len; n++)
            {
                c = _crcTable[(c ^ buf[n]) & 0xFF] ^ (c >> 8);
            }

            return c;
        }

        //返回的字节的CRC缓冲区
        private static uint GetCRC(byte[] buf)
        {
            return UpdateCRC(0xFFFFFFFF, buf, buf.Length) ^ 0xFFFFFFFF;
        }

        private static uint ComputeAdler32(byte[] buf)
        {
            uint s1 = 1;
            uint s2 = 0;
            int length = buf.Length;

            for (int idx = 0; idx < length; idx++)
            {
                s1 = (s1 + (uint)buf[idx]) % _ADLER32_BASE;
                s2 = (s2 + s1) % _ADLER32_BASE;
            }

            return (s2 << 16) + s1;
        }
    }
}


呵呵:简单的画图工具实现,里面还有较多的Bug,希望大家指出来,我们共同探讨一下,例如:在移动控件的时候没做边界值判断等等。

 

 

项目描述: 该项目是一款计算机平面几何学的绘图工具。 内置了一些交互的样式库,供在线浏览。 项目使用Silverlight 2.0(可以使用Microsoft Expression v3 beta 转换成 silverlight v3.0) 以及 C#3.0进行开发(在silverlight 和 wpf 上各自实现了一个版本)。核心的绘图引擎具备了良好的灵活性和扩展性,方便开发人员添加新的图形和功能。 我们将面临的工作类型: 将已有的之前无法顺利迁移到web上的桌面应用程序(庞大交互复杂,有一定安全要求或者比较华丽总之就是Ajax无法胜任)使用Silverlight 3.0 技术迁移到web上。 对于一些良好的Flash应用的迁移。(这属于站坑拉屎,谁先占住坑的谁就是大爷) 对于现有AJAX应用进行更加丰富的扩展。 我们将面临的挑战: 开发WinForm程序的大爷们终于可以灵活的涉足于Web界而不需要搞令人沮丧到要无限次重构直到自己写http协议的Asp.net框架。他们来了。 欢迎Flex阵营的朋友投身的到Silverlight3.0 的圈子中,思路一致(不好听的说法叫抄袭)很好迁移,你们也来吧。 之所以能带来更加丰富的用户体验,是因为那纠葛交错的WinForm消息循环体系,任何的动作都可以轻易牵动应用全身,这远远区别于Web应用开发(因为很多时候我们选择--我刷我刷我刷刷刷)。我们的优势: XAML = html,XAML(资源文件) = CSS,C#(Ruby or Python even JS) = JS。 可见,你依然可以像开发web一样开发Silverlight应用只要大脑思路一转。 Silverlight 最终还是要放置在网站之上(我们首先不考虑Out of browser功能),所以熟悉HTML熟悉JS我们可以方便的让Silverlight与 HTML交互。 赘述到此,我想大家应该已经明白, 这款Silverlight 在线本版的平面几何图形画图板便是经典的WinForm 到 Web的迁移。当你解读Silverlight代码和WPF代码的时候,你将会发现这并没有什么重大的不同之处(所以现在出现了Silverlight 和 WPF的兼容性类库,甚至出现了Silverlight 和 WPF的转换程序)。或者我们不妨悲剧的理解这本就是一个WebForm应用。我们带着强烈的愤怒怀疑这个微软的结构师本就是开发了10+年的WinForm(顺便仰慕一下)。 Main/SilverlightClient下为综合演示Demo,用VS2008打开后运行(或右键:在浏览器中打开)即可看到效果 自带了一些在线Demo,其他文件夹中还有些其他几何模型,有兴趣的可以自行研究
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值