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


    经理让找找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,希望大家指出来,我们共同探讨一下,例如:在移动控件的时候没做边界值判断等等。


     

  • 相关阅读:
    二进制数组ArrayBuffer
    iperf3测量一个网络最大带宽
    Proxy与Reflect
    Symbol
    Iterator
    Set与Map
    Generator
    Android 共享参数 SharedPreferences
    DDMS files not found: xxxhprof-conv.exe
    Android 状态栏通知 Notification
  • 原文地址:https://www.cnblogs.com/aptdo2008/p/2270389.html
Copyright © 2020-2023  润新知