示例#1
0
        public override Brush GetBrush(SvgVisualElement renderingElement, SvgRenderer renderer, float opacity)
        {
            LoadStops(renderingElement);

            try
            {
                if (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.Boundable(renderingElement);
                }
                var origin      = renderer.Boundable().Location;
                var centerPoint = CalculateCenterPoint(renderer, origin);
                var focalPoint  = CalculateFocalPoint(renderer, origin);

                var specifiedRadius = CalculateRadius(renderer);
                var effectiveRadius = CalculateEffectiveRadius(renderingElement, centerPoint, specifiedRadius);

                var brush = new PathGradientBrush(CreateGraphicsPath(origin, centerPoint, effectiveRadius))
                {
                    InterpolationColors = CalculateColorBlend(renderer, opacity, specifiedRadius, effectiveRadius),
                    CenterPoint         = focalPoint
                };

                Debug.Assert(brush.Rectangle.Contains(renderingElement.Bounds), "Brush rectangle does not contain rendering element bounds!");

                return(brush);
            }
            finally
            {
                if (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.PopBoundable();
                }
            }
        }
示例#2
0
        /// <summary>
        /// Renders the <see cref="SvgDocument"/> to the specified <see cref="SvgRenderer"/>.
        /// </summary>
        /// <param name="renderer">The <see cref="SvgRenderer"/> to render the document with.</param>
        /// <exception cref="ArgumentNullException">The <paramref name="renderer"/> parameter cannot be <c>null</c>.</exception>
        public void Draw(SvgRenderer renderer)
        {
            if (renderer == null)
            {
                throw new ArgumentNullException("renderer");
            }

            renderer.Boundable(this);
            this.Render(renderer);
        }
示例#3
0
        public override Brush GetBrush(SvgVisualElement renderingElement, SvgRenderer renderer, float opacity)
        {
            LoadStops(renderingElement);
            if (IsInvalid)
            {
                return(null);
            }

            try
            {
                if (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.Boundable(renderingElement);
                }

                var specifiedStart = CalculateStart(renderer);
                var specifiedEnd   = CalculateEnd(renderer);

                var effectiveStart = specifiedStart;
                var effectiveEnd   = specifiedEnd;

                if (NeedToExpandGradient(renderingElement, specifiedStart, specifiedEnd))
                {
                    var expansion = ExpandGradient(renderingElement, specifiedStart, specifiedEnd);
                    effectiveStart = expansion.StartPoint;
                    effectiveEnd   = expansion.EndPoint;
                }

                return(new LinearGradientBrush(effectiveStart, effectiveEnd, System.Drawing.Color.Transparent, System.Drawing.Color.Transparent)
                {
                    InterpolationColors = CalculateColorBlend(renderer, opacity, specifiedStart, effectiveStart, specifiedEnd, effectiveEnd),
                    WrapMode = WrapMode.TileFlipX
                });
            }
            finally
            {
                if (this.GradientUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.PopBoundable();
                }
            }
        }
示例#4
0
        /// <summary>
        /// Converts the current unit to one that can be used at render time.
        /// </summary>
        /// <param name="boundable">The container element used as the basis for calculations</param>
        /// <returns>The representation of the current unit in a device value (usually pixels).</returns>
        public float ToDeviceValue(SvgRenderer renderer, UnitRenderingType renderType, SvgElement owner)
        {
            // If it's already been calculated
            if (this._deviceValue.HasValue)
            {
                return(this._deviceValue.Value);
            }

            if (this._value == 0.0f)
            {
                this._deviceValue = 0.0f;
                return(this._deviceValue.Value);
            }

            // http://www.w3.org/TR/CSS21/syndata.html#values
            // http://www.w3.org/TR/SVG11/coords.html#Units

            const float cmInInch = 2.54f;
            int         ppi      = SvgDocument.PointsPerInch;

            var type  = this.Type;
            var value = this.Value;

            // Deal with fractional pattern units
            var coordElem = owner as ISvgSupportsCoordinateUnits;

            if (coordElem != null && coordElem.GetUnits() == SvgCoordinateUnits.ObjectBoundingBox && type != SvgUnitType.Percentage)
            {
                type   = SvgUnitType.Percentage;
                value *= 100;
            }

            var element = owner as SvgElement;

            if (element != null)
            {
                var pattern = element.Parents.OfType <SvgPatternServer>().FirstOrDefault();
                if (pattern != null && pattern.PatternContentUnits == SvgCoordinateUnits.ObjectBoundingBox && type != SvgUnitType.Percentage)
                {
                    type   = SvgUnitType.Percentage;
                    value *= 100;
                }
            }

            float points;
            Font  currFont;

            switch (type)
            {
            case SvgUnitType.Em:
                currFont = GetFont(renderer, owner);
                if (currFont == null)
                {
                    points       = (float)(value * 9);
                    _deviceValue = (points / 72.0f) * ppi;
                }
                else
                {
                    _deviceValue = value * (currFont.SizeInPoints / 72.0f) * ppi;
                }
                break;

            case SvgUnitType.Ex:
                currFont = GetFont(renderer, owner);
                if (currFont == null)
                {
                    points       = (float)(value * 9);
                    _deviceValue = (points * 0.5f / 72.0f) * ppi;
                }
                else
                {
                    _deviceValue = value * 0.5f * (currFont.SizeInPoints / 72.0f) * ppi;
                }
                break;

            case SvgUnitType.Centimeter:
                _deviceValue = (float)((value / cmInInch) * ppi);
                break;

            case SvgUnitType.Inch:
                _deviceValue = value * ppi;
                break;

            case SvgUnitType.Millimeter:
                _deviceValue = (float)((value / 10) / cmInInch) * ppi;
                break;

            case SvgUnitType.Pica:
                _deviceValue = ((value * 12) / 72) * ppi;
                break;

            case SvgUnitType.Point:
                _deviceValue = (value / 72) * ppi;
                break;

            case SvgUnitType.Pixel:
                _deviceValue = value;
                break;

            case SvgUnitType.User:
                _deviceValue = value;
                break;

            case SvgUnitType.Percentage:
                // Can't calculate if there is no style owner
                var boundable = (renderer == null ? (owner == null ? null : owner.OwnerDocument) : renderer.Boundable());
                if (boundable == null)
                {
                    _deviceValue = value;
                    break;
                }

                System.Drawing.SizeF size = boundable.Bounds.Size;

                switch (renderType)
                {
                case UnitRenderingType.Horizontal:
                    _deviceValue = (size.Width / 100) * value;
                    break;

                case UnitRenderingType.HorizontalOffset:
                    _deviceValue = (size.Width / 100) * value + boundable.Location.X;
                    break;

                case UnitRenderingType.Vertical:
                    _deviceValue = (size.Height / 100) * value;
                    break;

                case UnitRenderingType.VerticalOffset:
                    _deviceValue = (size.Height / 100) * value + boundable.Location.Y;
                    break;

                default:
                    _deviceValue = (float)(Math.Sqrt(Math.Pow(size.Width, 2) + Math.Pow(size.Height, 2)) / Math.Sqrt(2) * value / 100.0);
                    break;
                }
                break;

            default:
                _deviceValue = value;
                break;
            }
            return(this._deviceValue.Value);
        }
示例#5
0
        /// <summary>
        /// Gets the <see cref="GraphicsPath"/> for this element.
        /// </summary>
        /// <value></value>
        public override System.Drawing.Drawing2D.GraphicsPath Path(SvgRenderer renderer)
        {
            // Make sure the path is always null if there is no text
            //if there is a TSpan inside of this text element then path should not be null (even if this text is empty!)
            if ((string.IsNullOrEmpty(this.Text) || this.Text.Trim().Length < 1) && this.Children.Where(x => x is SvgTextSpan).Select(x => x as SvgTextSpan).Count() == 0)
            {
                return(_path = null);
            }
            //NOT SURE WHAT THIS IS ABOUT - Path gets created again anyway - WTF?
            // When an empty string is passed to GraphicsPath, it rises an InvalidArgumentException...

            if (_path == null || this.IsPathDirty)
            {
                renderer = (renderer ?? SvgRenderer.FromNull());
                // Measure the overall bounds of all the text
                var boundsData = GetTextBounds(renderer);

                var         font = GetFont(renderer);
                SvgTextBase innerText;
                float       x = (_x.Count < 1 ? _calcX : _x[0].ToDeviceValue(renderer, UnitRenderingType.HorizontalOffset, this)) +
                                (_dx.Count < 1 ? 0 : _dx[0].ToDeviceValue(renderer, UnitRenderingType.Horizontal, this));
                float y = (_y.Count < 1 ? _calcY : _y[0].ToDeviceValue(renderer, UnitRenderingType.VerticalOffset, this)) +
                          (_dy.Count < 1 ? 0 : _dy[0].ToDeviceValue(renderer, UnitRenderingType.Vertical, this));

                _path = new GraphicsPath();
                _path.StartFigure();

                // Determine the location of the start point
                switch (this.TextAnchor)
                {
                case SvgTextAnchor.Middle:
                    x -= (boundsData.Bounds.Width / 2);
                    break;

                case SvgTextAnchor.End:
                    x -= boundsData.Bounds.Width;
                    break;
                }

                try
                {
                    renderer.Boundable(new FontBoundable(font));
                    switch (this.BaselineShift)
                    {
                    case null:
                    case "":
                    case "baseline":
                    case "inherit":
                        // do nothing
                        break;

                    case "sub":
                        y += new SvgUnit(SvgUnitType.Ex, 1).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
                        break;

                    case "super":
                        y -= new SvgUnit(SvgUnitType.Ex, 1).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
                        break;

                    default:
                        var convert = new SvgUnitConverter();
                        var shift   = (SvgUnit)convert.ConvertFromInvariantString(this.BaselineShift);
                        y -= shift.ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
                        break;
                    }
                }
                finally
                {
                    renderer.PopBoundable();
                }

                NodeBounds data;
                var        yCummOffset = 0.0f;
                for (var i = 0; i < boundsData.Nodes.Count; i++)
                {
                    data      = boundsData.Nodes[i];
                    innerText = data.Node as SvgTextBase;
                    if (innerText == null)
                    {
                        // Minus FontSize because the x/y coords mark the bottom left, not bottom top.
                        DrawString(renderer, _path, x + data.xOffset, y - boundsData.Bounds.Height, font,
                                   PrepareText(data.Node.Content, i > 0 && boundsData.Nodes[i - 1].Node is SvgTextBase,
                                               i < boundsData.Nodes.Count - 1 && boundsData.Nodes[i + 1].Node is SvgTextBase));
                    }
                    else
                    {
                        innerText._calcX = x + data.xOffset;
                        innerText._calcY = y + yCummOffset;
                        if (innerText.Dy.Count == 1)
                        {
                            yCummOffset += innerText.Dy[0].ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
                        }
                    }
                }

                _path.CloseFigure();
                this.IsPathDirty = false;
            }
            return(_path);
        }
示例#6
0
文件: SvgUnit.cs 项目: nhajidin/SVG
        /// <summary>
        /// Converts the current unit to one that can be used at render time.
        /// </summary>
        /// <param name="boundable">The container element used as the basis for calculations</param>
        /// <returns>The representation of the current unit in a device value (usually pixels).</returns>
        public float ToDeviceValue(SvgRenderer renderer, UnitRenderingType renderType, SvgElement owner)
        {
            // If it's already been calculated
            if (this._deviceValue.HasValue)
            {
                return this._deviceValue.Value;
            }

            if (this._value == 0.0f)
            {
                this._deviceValue = 0.0f;
                return this._deviceValue.Value;
            }

            // http://www.w3.org/TR/CSS21/syndata.html#values
            // http://www.w3.org/TR/SVG11/coords.html#Units

            const float cmInInch = 2.54f;
            int ppi = SvgDocument.PointsPerInch;

            var type = this.Type;
            var value = this.Value;

            // Deal with fractional pattern units
            var coordElem = owner as ISvgSupportsCoordinateUnits;
            if (coordElem != null && coordElem.GetUnits() == SvgCoordinateUnits.ObjectBoundingBox && type != SvgUnitType.Percentage)
            {
                type = SvgUnitType.Percentage;
                value *= 100;
            }

            var element = owner as SvgElement;
            if (element != null)
            {
                var pattern = element.Parents.OfType<SvgPatternServer>().FirstOrDefault();
                if (pattern != null && pattern.PatternContentUnits == SvgCoordinateUnits.ObjectBoundingBox && type != SvgUnitType.Percentage)
                {
                    type = SvgUnitType.Percentage;
                    value *= 100;
                }
            }

            float points;
            Font currFont;

            switch (type)
            {
                case SvgUnitType.Em:
                    currFont = GetFont(renderer, owner);
                    if (currFont == null)
                    {
                        points = (float)(value * 9);
                        _deviceValue = (points / 72.0f) * ppi;
                    }
                    else
                    {
                        _deviceValue = value * (currFont.SizeInPoints / 72.0f) * ppi;
                    }
                    break;
                case SvgUnitType.Ex:
                    currFont = GetFont(renderer, owner);
                    if (currFont == null)
                    {
                        points = (float)(value * 9);
                        _deviceValue = (points * 0.5f / 72.0f) * ppi;
                    }
                    else
                    {
                        _deviceValue = value * 0.5f * (currFont.SizeInPoints / 72.0f) * ppi;
                    }
                    break;
                case SvgUnitType.Centimeter:
                    _deviceValue = (float)((value / cmInInch) * ppi);
                    break;
                case SvgUnitType.Inch:
                    _deviceValue = value * ppi;
                    break;
                case SvgUnitType.Millimeter:
                    _deviceValue = (float)((value / 10) / cmInInch) * ppi;
                    break;
                case SvgUnitType.Pica:
                    _deviceValue = ((value * 12) / 72) * ppi;
                    break;
                case SvgUnitType.Point:
                    _deviceValue = (value / 72) * ppi;
                    break;
                case SvgUnitType.Pixel:
                    _deviceValue = value;
                    break;
                case SvgUnitType.User:
                    _deviceValue = value;
                    break;
                case SvgUnitType.Percentage:
                    // Can't calculate if there is no style owner
                    var boundable = (renderer == null ? (owner == null ? null : owner.OwnerDocument) : renderer.Boundable());
                    if (boundable == null)
                    {
                        _deviceValue = value;
                        break;
                    }

                    System.Drawing.SizeF size = boundable.Bounds.Size;

                    switch (renderType)
                    {
                        case UnitRenderingType.Horizontal:
                            _deviceValue = (size.Width / 100) * value;
                            break;
                        case UnitRenderingType.HorizontalOffset:
                            _deviceValue = (size.Width / 100) * value + boundable.Location.X;
                            break;
                        case UnitRenderingType.Vertical:
                            _deviceValue = (size.Height / 100) * value;
                            break;
                        case UnitRenderingType.VerticalOffset:
                            _deviceValue = (size.Height / 100) * value + boundable.Location.Y;
                            break;
                        default:
                            _deviceValue = (float)(Math.Sqrt(Math.Pow(size.Width, 2) + Math.Pow(size.Height, 2)) / Math.Sqrt(2) * value / 100.0);
                            break;
                    }
                    break;
                default:
                    _deviceValue = value;
                    break;
            }
            return this._deviceValue.Value;
        }
示例#7
0
        /// <summary>
        /// Gets a <see cref="ColorBlend"/> representing the <see cref="SvgGradientServer"/>'s gradient stops.
        /// </summary>
        /// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param>
        /// <param name="opacity">The opacity of the colour blend.</param>
        protected ColorBlend GetColorBlend(SvgRenderer renderer, float opacity, bool radial)
        {
            int  colourBlends = this.Stops.Count;
            bool insertStart  = false;
            bool insertEnd    = false;

            //gradient.Transform = renderingElement.Transforms.Matrix;

            //stops should be processed in reverse order if it's a radial gradient

            // May need to increase the number of colour blends because the range *must* be from 0.0 to 1.0.
            // E.g. 0.5 - 0.8 isn't valid therefore the rest need to be calculated.

            // If the first stop doesn't start at zero
            if (this.Stops[0].Offset.Value > 0)
            {
                colourBlends++;

                if (radial)
                {
                    insertEnd = true;
                }
                else
                {
                    insertStart = true;
                }
            }

            // If the last stop doesn't end at 1 a stop
            float lastValue = this.Stops[this.Stops.Count - 1].Offset.Value;

            if (lastValue < 100 || lastValue < 1)
            {
                colourBlends++;
                if (radial)
                {
                    insertStart = true;
                }
                else
                {
                    insertEnd = true;
                }
            }

            ColorBlend blend = new ColorBlend(colourBlends);

            // Set positions and colour values
            int   actualStops   = 0;
            float mergedOpacity = 0.0f;
            float position      = 0.0f;
            Color colour        = System.Drawing.Color.Black;

            for (int i = 0; i < colourBlends; i++)
            {
                var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops];
                var boundWidth  = renderer.Boundable().Bounds.Width;

                mergedOpacity = opacity * currentStop.Opacity;
                position      =
                    radial
                    ? 1 - (currentStop.Offset.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / boundWidth)
                    : (currentStop.Offset.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / boundWidth);
                colour = System.Drawing.Color.FromArgb((int)(mergedOpacity * 255), currentStop.GetColor(this));

                actualStops++;

                // Insert this colour before itself at position 0
                if (insertStart && i == 0)
                {
                    blend.Positions[i] = 0.0f;
                    blend.Colors[i]    = colour;

                    i++;
                }

                blend.Positions[i] = position;
                blend.Colors[i]    = colour;

                // Insert this colour after itself at position 0
                if (insertEnd && i == colourBlends - 2)
                {
                    i++;

                    blend.Positions[i] = 1.0f;
                    blend.Colors[i]    = colour;
                }
            }

            return(blend);
        }
示例#8
0
        /// <summary>
        /// Gets a <see cref="Brush"/> representing the current paint server.
        /// </summary>
        /// <param name="renderingElement">The owner <see cref="SvgVisualElement"/>.</param>
        /// <param name="opacity">The opacity of the brush.</param>
        public override Brush GetBrush(SvgVisualElement renderingElement, SvgRenderer renderer, float opacity)
        {
            // If there aren't any children, return null
            if (this.Children.Count == 0)
            {
                return(null);
            }

            // Can't render if there are no dimensions
            if (this._width.Value == 0.0f || this._height.Value == 0.0f)
            {
                return(null);
            }

            try
            {
                if (this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.Boundable(renderingElement);
                }

                float width  = this._width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
                float height = this._height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this);

                Matrix patternMatrix = new Matrix();
                // Apply a translate if needed
                if (this._x.Value > 0.0f || this._y.Value > 0.0f)
                {
                    float x = this._x.ToDeviceValue(renderer, UnitRenderingType.HorizontalOffset, this);
                    float y = this._y.ToDeviceValue(renderer, UnitRenderingType.VerticalOffset, this);

                    patternMatrix.Translate(x + -1.0f, y + -1.0f);
                }
                else
                {
                    patternMatrix.Translate(-1, -1);
                }

                if (this.ViewBox.Height > 0 || this.ViewBox.Width > 0)
                {
                    patternMatrix.Scale(this.Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) / this.ViewBox.Width,
                                        this.Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this) / this.ViewBox.Height);
                }

                Bitmap image = new Bitmap((int)width, (int)height);
                using (SvgRenderer iRenderer = SvgRenderer.FromImage(image))
                {
                    iRenderer.Boundable((_patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox) ? new GenericBoundable(0, 0, width, height) : renderer.Boundable());
                    iRenderer.Transform          = patternMatrix;
                    iRenderer.CompositingQuality = CompositingQuality.HighQuality;
                    iRenderer.SmoothingMode      = SmoothingMode.AntiAlias;
                    iRenderer.PixelOffsetMode    = PixelOffsetMode.Half;

                    foreach (SvgElement child in this.Children)
                    {
                        child.RenderElement(iRenderer);
                    }

                    iRenderer.Save();
                }

                image.Save(string.Format(@"C:\test{0:D3}.png", imgNumber++));

                TextureBrush textureBrush = new TextureBrush(image);

                return(textureBrush);
            }
            finally
            {
                if (this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    renderer.PopBoundable();
                }
            }
        }