silverlight2中实现涂鸦效果并保存为图片

大家知道,在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!这样我们就实现了将涂鸦效果保存为图片的效果了。。下面是这个老外的源代码,有兴趣的朋友可以下下来看看,研究研究。。点击下载原项目文件
posted @ 2008-11-10 14:30  Leochen  阅读(1050)  评论(0编辑  收藏  举报