Exemple #1
0
        /// <summary>
        /// Implemented
        /// </summary>
        public void DrawLines(Pen pen, PointF[] points)
        {
            SvgPolylineElement pl = new SvgPolylineElement(points);
            pl.Style = new SvgStyle(pen);
            if (!_transforms.Result.IsIdentity)
                pl.Transform = new SvgTransformList(_transforms.Top.Clone());
            _cur.AddChild(pl);

            DrawEndAnchors(pen, points[0], points[points.Length-1]);
        }
Exemple #2
0
        /// <summary>
        /// Implemented
        /// </summary>
        public void DrawLines(Pen pen, PointF[] points)
        {
            if (points.Length <= 1)
                return;

            if (IsEndAnchorSimple(pen.StartCap) && IsEndAnchorSimple(pen.EndCap))
            {
                // This code works, but not for CustomLineCap style
                SvgPolylineElement pl = new SvgPolylineElement(points);
                pl.Style = new SvgStyle(pen);
                if (!_transforms.Result.IsIdentity)
                    pl.Transform = new SvgTransformList(_transforms.Top.Clone());
                _cur.AddChild(pl);

                DrawEndAnchors(pen, points[0], points[points.Length - 1]);

                return;
            }

            // GraphicsPaths used in the constructor of CustomLineCap
            // are private to the native GDI+ and for example the shape of AdjustableArrowCap
            // is completely private to the native GDI+
            //
            // So in order to render the possibly any-shaped custom line caps we'll draw the line as GDI metafile and then reverse
            // engineer the GDI metafile drawing and convert it to corresponding SVG commands

            // Calculate the bounding rectangle
            var minX = points[0].X;
            var maxX = points[0].X;
            var minY = points[0].Y;
            var maxY = points[0].Y;
            for (var i = 1; i < points.Length; i++)
            {
                var point = points[i];
                minX = Math.Min(minX, point.X);
                maxX = Math.Max(maxX, point.X);
                minY = Math.Min(minY, point.Y);
                maxY = Math.Max(maxY, point.Y);
            }
            var bounds = new RectangleF(minX, minY, maxX - minX + 1, maxY - minY + 1);

            // Make the rectangle 0-based where "zero" represents the original shift
            var zero = bounds.Location;
            bounds.Offset(-zero.X, -zero.Y);

            // Make the original point-path "zero"-based
            for (var i = 0; i < points.Length; i++)
            {
                points[i].X -= zero.X;
                points[i].Y -= zero.Y;
            }

            using (var metafileBuffer = new System.IO.MemoryStream())
            {
                System.Drawing.Imaging.Metafile metafile = null;

                try
                {
                    /* For discussion of tricky metafile details see:
                     * - http://nicholas.piasecki.name/blog/2009/06/drawing-o-an-in-memory-metafile-in-c-sharp/
                     * - http://stackoverflow.com/a/1533053/2626313
                     */

                    using (var temporaryBitmap = new Bitmap(1, 1))
                    {
                        using (var temporaryCanvas = Graphics.FromImage(temporaryBitmap))
                        {
                            var hdc = temporaryCanvas.GetHdc();
                            metafile = new Metafile(
                                metafileBuffer,
                                hdc,
                                bounds,
                                MetafileFrameUnit.GdiCompatible,
                                EmfType.EmfOnly);

                            temporaryCanvas.ReleaseHdc();
                        }
                    }

                    using (var metafileCanvas = Graphics.FromImage(metafile))
                    {
                        metafileCanvas.DrawLines(pen, points);
                    }
                }
                finally
                {
                    if (metafile != null)
                        metafile.Dispose();
                }

                metafileBuffer.Position = 0;

                var metafileIsEmpty = true;
                var parser = new MetafileTools.MetafileParser();
                parser.EnumerateMetafile(metafileBuffer, pen.Width, zero, (PointF[] linePoints) =>
                {
                    metafileIsEmpty = false;

                    SvgPolylineElement pl = new SvgPolylineElement(linePoints);
                    pl.Style = new SvgStyle(pen);

                    // Make it pretty
                    pl.Style.Set("stroke-linecap", "round");

                    if (!_transforms.Result.IsIdentity)
                        pl.Transform = new SvgTransformList(_transforms.Top.Clone());
                    _cur.AddChild(pl);
                }, (PointF[] linePoints, Brush fillBrush) =>
                {
                    // TODO: received shapes dont' have the vertex list "normalized" correctly
                    // metafileIsEmpty = false;
                    // FillPolygon(fillBrush, linePoints);
                });

                if (metafileIsEmpty)
                {
                    // TODO: metafile recording on OpenSUSE Linux with Mono 3.8.0 does not seem to work at all
                    // as the supposed implementation in https://github.com/mono/libgdiplus/blob/master/src/graphics-metafile.c is
                    // full of "TODO". In this case we should take a graceful fallback approach

                    // Restore points array to the original values they had when entered the function
                    for (var i = 0; i < points.Length; i++)
                    {
                        points[i].X += zero.X;
                        points[i].Y += zero.Y;
                    }

                    SvgPolylineElement pl = new SvgPolylineElement(points);
                    pl.Style = new SvgStyle(pen);
                    if (!_transforms.Result.IsIdentity)
                        pl.Transform = new SvgTransformList(_transforms.Top.Clone());
                    _cur.AddChild(pl);

                    DrawEndAnchors(pen, points[0], points[points.Length - 1], ignoreUnsupportedLineCaps: true);
                }
            }
        }