using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing;
using System.ComponentModel;
using Svg.Transforms;
using System.Linq;
namespace Svg
{
///
/// A pattern is used to fill or stroke an object using a pre-defined graphic object which can be replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted.
///
[SvgElement("pattern")]
public sealed class SvgPatternServer : SvgPaintServer, ISvgViewPort, ISvgSupportsCoordinateUnits
{
private SvgUnit _width;
private SvgUnit _height;
private SvgUnit _x;
private SvgUnit _y;
private SvgPaintServer _inheritGradient;
private SvgViewBox _viewBox;
private SvgCoordinateUnits _patternUnits = SvgCoordinateUnits.Inherit;
private SvgCoordinateUnits _patternContentUnits = SvgCoordinateUnits.Inherit;
[SvgAttribute("overflow")]
public SvgOverflow Overflow
{
get { return this.Attributes.GetAttribute("overflow"); }
set { this.Attributes["overflow"] = value; }
}
///
/// Specifies a supplemental transformation which is applied on top of any
/// transformations necessary to create a new pattern coordinate system.
///
[SvgAttribute("viewBox")]
public SvgViewBox ViewBox
{
get { return this._viewBox; }
set { this._viewBox = value; }
}
///
/// Gets or sets the aspect of the viewport.
///
///
[SvgAttribute("preserveAspectRatio")]
public SvgAspectRatio AspectRatio
{
get;
set;
}
///
/// Gets or sets the width of the pattern.
///
[SvgAttribute("width")]
public SvgUnit Width
{
get { return this._width; }
set { this._width = value; }
}
///
/// Gets or sets the width of the pattern.
///
[SvgAttribute("patternUnits")]
public SvgCoordinateUnits PatternUnits
{
get { return this._patternUnits; }
set { this._patternUnits = value; }
}
///
/// Gets or sets the width of the pattern.
///
[SvgAttribute("patternContentUnits")]
public SvgCoordinateUnits PatternContentUnits
{
get { return this._patternContentUnits; }
set { this._patternContentUnits = value; }
}
///
/// Gets or sets the height of the pattern.
///
[SvgAttribute("height")]
public SvgUnit Height
{
get { return this._height; }
set { this._height = value; }
}
///
/// Gets or sets the X-axis location of the pattern.
///
[SvgAttribute("x")]
public SvgUnit X
{
get { return this._x; }
set { this._x = value; }
}
///
/// Gets or sets the Y-axis location of the pattern.
///
[SvgAttribute("y")]
public SvgUnit Y
{
get { return this._y; }
set { this._y = value; }
}
///
/// Gets or sets another gradient fill from which to inherit the stops from.
///
[SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)]
public SvgPaintServer InheritGradient
{
get { return this._inheritGradient; }
set
{
this._inheritGradient = value;
}
}
[SvgAttribute("patternTransform")]
public SvgTransformCollection PatternTransform
{
get { return (this.Attributes.GetAttribute("gradientTransform")); }
set { this.Attributes["gradientTransform"] = value; }
}
protected Matrix EffectivePatternTransform
{
get
{
var transform = new Matrix();
if (PatternTransform != null)
{
transform.Multiply(PatternTransform.GetMatrix());
}
return transform;
}
}
///
/// Initializes a new instance of the class.
///
public SvgPatternServer()
{
this._x = SvgUnit.None;
this._y = SvgUnit.None;
this._width = SvgUnit.None;
this._height = SvgUnit.None;
}
private SvgUnit NormalizeUnit(SvgUnit orig)
{
return (orig.Type == SvgUnitType.Percentage && this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox ?
new SvgUnit(SvgUnitType.User, orig.Value / 100) :
orig);
}
///
/// Gets a representing the current paint server.
///
/// The owner .
/// The opacity of the brush.
public override Brush GetBrush(SvgVisualElement renderingElement, ISvgRenderer renderer, float opacity, bool forStroke = false)
{
var chain = new List();
var curr = this;
while (curr != null)
{
chain.Add(curr);
curr = SvgDeferredPaintServer.TryGet(curr._inheritGradient, renderingElement);
}
var childElem = chain.Where((p) => p.Children != null && p.Children.Count > 0).FirstOrDefault();
if (childElem == null) return null;
var widthElem = chain.Where((p) => p.Width != null && p.Width != SvgUnit.None).FirstOrDefault();
var heightElem = chain.Where((p) => p.Height != null && p.Height != SvgUnit.None).FirstOrDefault();
if (widthElem == null && heightElem == null) return null;
var viewBoxElem = chain.Where((p) => p.ViewBox != null && p.ViewBox != SvgViewBox.Empty).FirstOrDefault();
var viewBox = viewBoxElem == null ? SvgViewBox.Empty : viewBoxElem.ViewBox;
var xElem = chain.Where((p) => p.X != null && p.X != SvgUnit.None).FirstOrDefault();
var yElem = chain.Where((p) => p.Y != null && p.Y != SvgUnit.None).FirstOrDefault();
var xUnit = xElem == null ? SvgUnit.Empty : xElem.X;
var yUnit = yElem == null ? SvgUnit.Empty : yElem.Y;
var patternUnitElem = chain.Where((p) => p.PatternUnits != SvgCoordinateUnits.Inherit).FirstOrDefault();
var patternUnits = (patternUnitElem == null ? SvgCoordinateUnits.ObjectBoundingBox : patternUnitElem.PatternUnits);
var patternContentUnitElem = chain.Where((p) => p.PatternContentUnits != SvgCoordinateUnits.Inherit).FirstOrDefault();
var patternContentUnits = (patternContentUnitElem == null ? SvgCoordinateUnits.UserSpaceOnUse : patternContentUnitElem.PatternContentUnits);
try
{
if (patternUnits == SvgCoordinateUnits.ObjectBoundingBox) renderer.SetBoundable(renderingElement);
using (var patternMatrix = new Matrix())
{
var bounds = renderer.GetBoundable().Bounds;
var xScale = (patternUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Width : 1);
var yScale = (patternUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Height : 1);
float x = xScale * NormalizeUnit(xUnit).ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
float y = yScale * NormalizeUnit(yUnit).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
float width = xScale * NormalizeUnit(widthElem.Width).ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
float height = yScale * NormalizeUnit(heightElem.Height).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
// Apply a scale if needed
patternMatrix.Scale((patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Width : 1) *
(viewBox.Width > 0 ? width / viewBox.Width : 1),
(patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox ? bounds.Height : 1) *
(viewBox.Height > 0 ? height / viewBox.Height : 1), MatrixOrder.Prepend);
Bitmap image = new Bitmap((int)width, (int)height);
using (var iRenderer = SvgRenderer.FromImage(image))
{
iRenderer.SetBoundable((_patternContentUnits == SvgCoordinateUnits.ObjectBoundingBox) ? new GenericBoundable(0, 0, width, height) : renderer.GetBoundable());
iRenderer.Transform = patternMatrix;
iRenderer.SmoothingMode = SmoothingMode.AntiAlias;
iRenderer.SetClip(new Region(new RectangleF(0, 0,
viewBox.Width > 0 ? viewBox.Width : width,
viewBox.Height > 0 ? viewBox.Height : height)));
foreach (SvgElement child in childElem.Children)
{
child.RenderElement(iRenderer);
}
}
TextureBrush textureBrush = new TextureBrush(image);
var brushTransform = EffectivePatternTransform.Clone();
brushTransform.Translate(x, y, MatrixOrder.Append);
textureBrush.Transform = brushTransform;
return textureBrush;
}
}
finally
{
if (this.PatternUnits == SvgCoordinateUnits.ObjectBoundingBox) renderer.PopBoundable();
}
}
public override SvgElement DeepCopy()
{
return DeepCopy();
}
public override SvgElement DeepCopy()
{
var newObj = base.DeepCopy() as SvgPatternServer;
newObj.Overflow = this.Overflow;
newObj.ViewBox = this.ViewBox;
newObj.AspectRatio = this.AspectRatio;
newObj.X = this.X;
newObj.Y = this.Y;
newObj.Width = this.Width;
newObj.Height = this.Height;
return newObj;
}
public SvgCoordinateUnits GetUnits()
{
return _patternUnits;
}
}
}