大家知道,在silverlight中实现涂鸦效果是非常的容易,但要将涂鸦的效果保存为一张图片,这个就有一定的困难了,下面介绍一个老外保存涂鸦效果为图片的方法, 首先我们通过画笔InkPresenter和一些鼠标操作实现在画布上的涂鸦效果 /// <summary> /// 画笔鼠标按下的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void onInkPresenterDown(object sender, MouseButtonEventArgs e) { if (editingMode == InkEditingMode.None) return; workCanvas.CaptureMouse(); StylusPointCollection stylusPoints = e.StylusDevice.GetStylusPoints(workCanvas); if (editingMode == InkEditingMode.Erase) { erasePoints = new StylusPointCollection(); erasePoints.Add(stylusPoints); } else if (editingMode == InkEditingMode.Ink) { inkStroke = new Stroke(stylusPoints); inkStroke.DrawingAttributes = new DrawingAttributes(); inkStroke.DrawingAttributes.Color = inkAttributes.Color; inkStroke.DrawingAttributes.OutlineColor = inkAttributes.OutlineColor; inkStroke.DrawingAttributes.Width = inkAttributes.Width; inkStroke.DrawingAttributes.Height = inkAttributes.Height; workCanvas.Strokes.Add(inkStroke); } } /// <summary> /// 画笔鼠标移动的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void onInkPresenterMove(object sender, MouseEventArgs e) { if (editingMode == InkEditingMode.None) return; StylusPointCollection stylusPoints = e.StylusDevice.GetStylusPoints(workCanvas); if (editingMode == InkEditingMode.Erase) { if (erasePoints != null) { // hittest and erase erasePoints.Add(stylusPoints); StrokeCollection hitStrokes = workCanvas.Strokes.HitTest(erasePoints); for (int i = 0; i < hitStrokes.Count; i++) { workCanvas.Strokes.Remove(hitStrokes[i]); } } } else if (editingMode == InkEditingMode.Ink) { if (inkStroke != null) { inkStroke.StylusPoints.Add(stylusPoints); } } } /// <summary> /// 画笔鼠标up的事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void onInkPresenterUp(object sender, MouseButtonEventArgs e) { if (editingMode == InkEditingMode.None) return; if (inkStroke != null) { inkStroke.StylusPoints.Add(e.StylusDevice.GetStylusPoints(workCanvas)); } workCanvas.ReleaseMouseCapture(); erasePoints = null; inkStroke = null; } 然后我们画笔InkPresenter上的Storkes保存为xml文件 StrokeCollection strokeCollection = new StrokeCollection(); strokeCollection = inkCanvas.Strokes; if (strokeCollection.Count > 0) { var xaml = "<StrokeCollection>"; if (strokeCollection != null) { for (var i = 0; i < strokeCollection.Count; i++) { var stroke = strokeCollection[i]; xaml += "<Stroke>"; xaml += "<Stroke.DrawingAttributes>"; xaml += "<DrawingAttributes "; xaml += "Color='" + stroke.DrawingAttributes.Color.ToString() + "' "; xaml += "OutlineColor='" + stroke.DrawingAttributes.OutlineColor + "' "; xaml += "Width='" + stroke.DrawingAttributes.Width + "' "; xaml += "Height='" + stroke.DrawingAttributes.Height + "' "; xaml += "/>"; xaml += "</Stroke.DrawingAttributes>"; xaml += "<Stroke.StylusPoints>"; for (var j = 0; j < stroke.StylusPoints.Count; j++) { var stylusPoint = stroke.StylusPoints[j]; xaml += "<StylusPoint X='" + stylusPoint.X + "' Y='" + stylusPoint.Y + "' />"; } xaml += "</Stroke.StylusPoints>"; xaml += "</Stroke>"; } } xaml += "</StrokeCollection>"; } 最后也是最重要的一步:就是将生成的xml文件传递到wcf,然后在wcf中实现将涂鸦合成为图片的效果 public void SaveImage(string InputXML) { XmlDocument objDoc = new XmlDocument(); objDoc.LoadXml(InputXML); XmlNodeList objNodeList = objDoc.SelectNodes("./StrokeCollection"); foreach (XmlNode objNode in objNodeList) { strokes = InkObjectfromXAML(objNode); } ThreadforConverttoPNG(); } private static StrokeCollection InkObjectfromXAML(XmlNode StrokeColl) { StrokeCollection objStrokes = new StrokeCollection(); XmlNodeList strokeElements = StrokeColl.SelectNodes("Stroke"); foreach (XmlNode strokeNodeElement in strokeElements) { //step 1: create a new stroke from the stylus point elements in the XAML XmlNodeList stylusPointElements = strokeNodeElement.SelectNodes("./Stroke.StylusPoints/StylusPoint"); XmlNode drawAttribs = strokeNodeElement.SelectSingleNode("./Stroke.DrawingAttributes"); //points node is sent to GetStrokePOints method to convert to a type //that can be used by the new stroke System.Windows.Input.StylusPointCollection strokeData = GetStrokePoints(stylusPointElements); Stroke newstroke = new Stroke(strokeData); //step 2: grab color metadata about stroke from the xaml //color is a hex value //the stroke object requires a System.Windows.Media.Color type //following code performs the conversion string mycolor = drawAttribs.FirstChild.Attributes["Color"].Value; System.Drawing.Color drwColor = System.Drawing.ColorTranslator.FromHtml(mycolor); //build the new color from the a,r,g,b values of the drawing.color System.Windows.Media.Color newColor = new System.Windows.Media.Color(); newColor.A = drwColor.A; newColor.R = drwColor.R; newColor.G = drwColor.G; newColor.B = drwColor.B; //Step 3: extract width data from xaml, convert to int int myIntWidth; bool parseSuccess = int.TryParse(drawAttribs.FirstChild.Attributes["Width"].Value, out myIntWidth); //Step 4: apply width & color to stroke //some really wierd unexplainable transformations that I had to get // around until the final images looked right. if (myIntWidth == 3) newstroke.DrawingAttributes.Width = 1.5; else newstroke.DrawingAttributes.Width = 2; newstroke.DrawingAttributes.Color = newColor; //Step 5: add stroke to the stroke collection objStrokes.Add(newstroke); } return objStrokes; } //This method (called from the method above, is an abstraciton of some sample code from Microsoft private static System.Windows.Input.StylusPointCollection GetStrokePoints(XmlNodeList stylusPointElements) { System.Windows.Input.StylusPointCollection pointData = new System.Windows.Input.StylusPointCollection(); //The object requires HiMetric point values, create multiplier for conversion double pixelToHimetricMultiplier = (2540d / 96d) / 100; foreach (XmlNode stylusPointElement in stylusPointElements) { string xStr = stylusPointElement.Attributes["X"].Value; string yStr = stylusPointElement.Attributes["Y"].Value; //x and y are in pixels, we need to multiply them to get them into HIMETRIC //space, which is what the InkAnalyzerBase expects int xInHimetric = (int)(System.Convert.ToDouble(xStr) * pixelToHimetricMultiplier); int yInHimetric = (int)(System.Convert.ToDouble(yStr) * pixelToHimetricMultiplier); pointData.Add(new System.Windows.Input.StylusPoint(xInHimetric, yInHimetric)); } return pointData; } private static void ThreadforConverttoPNG() { Thread t = new Thread(new ThreadStart(ConverttoPNG)); t.SetApartmentState(ApartmentState.STA); // Start ThreadProc. Note that on a uniprocessor, the new // thread does not get any processor time until the main thread // is preempted or yields. Uncomment the Thread.Sleep that // follows t.Start() to see the difference. t.Start(); } private static void ConverttoPNG() { //I had originally achieved this with a LOT more code. This is Stefan's more trimmed down method //create temporary InkCanvas InkCanvas inkCanvas = new InkCanvas(); inkCanvas.Strokes = strokes; //render InkCanvas to a RenderBitmapTarget Rect rect = inkCanvas.Strokes.GetBounds(); RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default); rtb.Render(inkCanvas); //endcode as PNG BitmapEncoder gifEncoder = new GifBitmapEncoder(); gifEncoder.Frames.Add(BitmapFrame.Create(rtb)); //save to memory stream System.IO.MemoryStream ms = new System.IO.MemoryStream(); gifEncoder.Save(ms); ms.Close(); strokeBytes = ms.ToArray(); System.IO.File.WriteAllBytes("D:\\" + System.Guid.NewGuid().ToString() + ".gif", strokeBytes); } } OK!这样我们就实现了将涂鸦效果保存为图片的效果了。。下面是这个老外的源代码,有兴趣的朋友可以下下来看看,研究研究。。点击下载原项目文件 相关文章: