Silverlight实用窍门系列:50.InkPresenter涂鸦板的基本使用,以及将效果保存为Png图片【附带源码实例】

Silverlight实用窍门系列:50.InkPresenter涂鸦板的基本使用,以及将效果保存为Png图片【附带源码实例】,第1张

概述       在Silverlight中我们有时候需要手工绘制线条或者直线等,在这里我们认识一下InkPresenter控件,它将支持用户使用鼠标、手写板等工具来绘制图形或者笔迹,用途为涂鸦、笔迹确认等等。         InkPresenter是继承于Canvas控件的支持所有的Canvas属性,并且其内部还可以嵌套显示其他控件。InkPresenter控件的显 示分为三层:底层是InkPre

       在Silverlight中我们有时候需要手工绘制线条或者直线等,在这里我们认识一下InkPresenter控件,它将支持用户使用鼠标、手写板等工具来绘制图形或者笔迹,用途为涂鸦、笔迹确认等等。

        InkPresenter是继承于Canvas控件的支持所有的Canvas属性,并且其内部还可以嵌套显示其他控件。InkPresenter控件的显 示分为三层:底层是InkPresenter的Background、中间层是InkPresenter的Children属性的控件、最后才是 strokes属性中的笔画层。

        对于strokes属性中的笔画stroke我们可以设置它的颜色、粗细、外边框颜色等等属性以获得满意的笔画类型。下面我们来看看如何使用InkPresenter控件,首先我们来看Xaml代码如下:

 

  <GrID x:name="LayoutRoot1" Background="White"        <Canvas>             <border borderThickness="1" margin="50 10 0 0" borderBrush="CadetBlue"                      HorizontalAlignment="Center" VerticalAlignment="Center"                <InkPresenter x:name="iPresenter" Height="500" WIDth="500"                   MouseleftbuttonDown="iPresenter_MouseleftbuttonDown"                    LostMouseCapture="iPresenter_LostMouseCapture"                    MouseMove="iPresenter_MouseMove"                    Background="transparent" Opacity="1" >                     <TextBox WIDth="138" Canvas.left="58" Canvas.top="105"></TextBox>                 </InkPresenter>             </border>             <button Canvas.left="560" Canvas.top="11" Content="将涂鸦保存为图片" Height="23"                     name="button1" WIDth="104" Click="button1_Click" />             <Image name="showIP" WIDth="400" Height="400" Canvas.left="560" Canvas.top="60"></Image>         </Canvas>     </GrID>   

        然后我们来看看Xaml.cs代码如下:

 

  public partial class MainPage : UserControl             public MainPage()         {             InitializeComponent();             SetPresenterClip();         }         stroke mystroke;              private voID iPresenter_MouseleftbuttonDown(object sender, MouseEventArgs e)         {             //让鼠标捕获数据             iPresenter.CaptureMouse();             //收集笔触数据点保存值StylusPointCollection集合中             StylusPointCollection stylusPointCollection = new StylusPointCollection();             stylusPointCollection.Add(e.StylusDevice.GetStylusPoints(iPresenter));             //将数据点的结合保存为一个笔画             mystroke = new stroke(stylusPointCollection);             //设置笔画的绘画效果,如颜色,大小等。             mystroke.DrawingAttributes.color = colors.Gray;             mystroke.DrawingAttributes.WIDth = 1;             mystroke.DrawingAttributes.Height = 1;             iPresenter.strokes.Add(mystroke);         }              private voID iPresenter_MouseMove(object sender, MouseEventArgs e)         {             //在鼠标移动的过程中将数据点加入到笔画中去。             if (mystroke != null                mystroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(iPresenter));         }              private voID iPresenter_LostMouseCapture(object sender, MouseEventArgs e)         {             //将笔画清空             mystroke = null            iPresenter.ReleaseMouseCapture();//释放鼠标坐标         }              /// <summary>         /// 设置绘画区域为InkPresenter的大小         /// </summary>         private voID SetPresenterClip()         {             RectangleGeometry MyRectangleGeometry = new RectangleGeometry();             MyRectangleGeometry.Rect = new Rect(0, 0, iPresenter.ActualWIDth, iPresenter.ActualHeight);             //设置获取绘画内容的有效区域             iPresenter.Clip = MyRectangleGeometry;         }              private voID button1_Click(object sender, RoutedEventArgs e)         {             //保存InkPresenter涂鸦板内绘画的图             WriteableBitmap _bitmap = new WriteableBitmap(iPresenter, null);             this.showIP.source = _bitmap;             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, len);                     fs.Write(bytes, len);                     MessageBox.Show("图片保存成功!");                 }             }              }       

        对于将InkPresenter中绘画出来的图片保存为Png图片得处理,我们在这里借鉴了园子中永恒的记忆兄弟的将元素转为Png图片的方法,在这里贴出两个辅助转Png格式的类。

 

  /// <summary>     /// 编辑图片     /// </summary>     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, 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; }             }         }            

        这是Png *** 作类:

 

  /// <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)'T' };         private static byte[] _IEND = { (byte)'I', (byte)'E', (byte)'N', (byte)'D' };         private static byte[] _4BYTEDATA = { 0, 0 };         private static byte[] _ARGB = { 0, 8, 6, 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, _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), 2);                      comp.Write(BitConverter.GetBytes((ushort)~length), 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, (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, 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, 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;         }       

        最后我们来看看运行的效果如下,如需源码请点击 SLInkPresenter.zip下载:

总结

以上是内存溢出为你收集整理的Silverlight实用窍门系列:50.InkPresenter涂鸦板的基本使用,以及将效果保存为Png图片【附带源码实例】全部内容,希望文章能够帮你解决Silverlight实用窍门系列:50.InkPresenter涂鸦板的基本使用,以及将效果保存为Png图片【附带源码实例】所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1076849.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存