/// <summary> /// Sets the clipping region of the specified <see cref="SvgRenderer"/>. /// </summary> /// <param name="renderer">The <see cref="SvgRenderer"/> to have its clipping region set.</param> protected internal virtual void SetClip(SvgRenderer renderer) { if (this.ClipPath != null) { SvgClipPath clipPath = this.OwnerDocument.GetElementById <SvgClipPath>(this.ClipPath.ToString()); this._previousClip = renderer.Clip; if (clipPath != null) { renderer.AddClip(clipPath.GetClipRegion(this)); } } }
/// <summary> /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object. /// </summary> protected override void Render(SvgRenderer renderer) { if (!Visible || !Displayable) { return; } if (Width.Value > 0.0f && Height.Value > 0.0f && this.Href != null) { using (Image b = GetImage(this.Href)) { if (b != null) { var srcRect = new RectangleF(0, 0, b.Width, b.Height); var destClip = new RectangleF(this.Location.ToDeviceValue(renderer, this), new SizeF(Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this), Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this))); RectangleF destRect = destClip; this.PushTransforms(renderer); renderer.AddClip(new Region(destClip)); this.SetClip(renderer); if (AspectRatio != null && AspectRatio.Align != SvgPreserveAspectRatio.none) { var fScaleX = destClip.Width / srcRect.Width; var fScaleY = destClip.Height / srcRect.Height; var xOffset = 0.0f; var yOffset = 0.0f; if (AspectRatio.Slice) { fScaleX = Math.Max(fScaleX, fScaleY); fScaleY = Math.Max(fScaleX, fScaleY); } else { fScaleX = Math.Min(fScaleX, fScaleY); fScaleY = Math.Min(fScaleX, fScaleY); } switch (AspectRatio.Align) { case SvgPreserveAspectRatio.xMinYMin: break; case SvgPreserveAspectRatio.xMidYMin: xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2; break; case SvgPreserveAspectRatio.xMaxYMin: xOffset = (destClip.Width - srcRect.Width * fScaleX); break; case SvgPreserveAspectRatio.xMinYMid: yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2; break; case SvgPreserveAspectRatio.xMidYMid: xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2; yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2; break; case SvgPreserveAspectRatio.xMaxYMid: xOffset = (destClip.Width - srcRect.Width * fScaleX); yOffset = (destClip.Height - srcRect.Height * fScaleY) / 2; break; case SvgPreserveAspectRatio.xMinYMax: yOffset = (destClip.Height - srcRect.Height * fScaleY); break; case SvgPreserveAspectRatio.xMidYMax: xOffset = (destClip.Width - srcRect.Width * fScaleX) / 2; yOffset = (destClip.Height - srcRect.Height * fScaleY); break; case SvgPreserveAspectRatio.xMaxYMax: xOffset = (destClip.Width - srcRect.Width * fScaleX); yOffset = (destClip.Height - srcRect.Height * fScaleY); break; } destRect = new RectangleF(destClip.X + xOffset, destClip.Y + yOffset, srcRect.Width * fScaleX, srcRect.Height * fScaleY); } renderer.DrawImage(b, destRect, srcRect, GraphicsUnit.Pixel); this.ResetClip(renderer); this.PopTransforms(renderer); } } // TODO: cache images... will need a shared context for this // TODO: support preserveAspectRatio, etc } }
/// <summary> /// Applies the required transforms to <see cref="SvgRenderer"/>. /// </summary> /// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param> protected internal override bool PushTransforms(SvgRenderer renderer) { if (!base.PushTransforms(renderer)) { return(false); } if (!this.ViewBox.Equals(SvgViewBox.Empty)) { var width = this.Width.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); var height = this.Height.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); var fScaleX = width / this.ViewBox.Width; var fScaleY = height / this.ViewBox.Height; var fMinX = -this.ViewBox.MinX; var fMinY = -this.ViewBox.MinY; if (AspectRatio.Align != SvgPreserveAspectRatio.none) { if (AspectRatio.Slice) { fScaleX = Math.Max(fScaleX, fScaleY); fScaleY = Math.Max(fScaleX, fScaleY); } else { fScaleX = Math.Min(fScaleX, fScaleY); fScaleY = Math.Min(fScaleX, fScaleY); } float fViewMidX = (this.ViewBox.Width / 2) * fScaleX; float fViewMidY = (this.ViewBox.Height / 2) * fScaleY; float fMidX = width / 2; float fMidY = height / 2; switch (AspectRatio.Align) { case SvgPreserveAspectRatio.xMinYMin: break; case SvgPreserveAspectRatio.xMidYMin: fMinX += fMidX - fViewMidX; break; case SvgPreserveAspectRatio.xMaxYMin: fMinX += width - this.ViewBox.Width * fScaleX; break; case SvgPreserveAspectRatio.xMinYMid: fMinY += fMidY - fViewMidY; break; case SvgPreserveAspectRatio.xMidYMid: fMinX += fMidX - fViewMidX; fMinY += fMidY - fViewMidY; break; case SvgPreserveAspectRatio.xMaxYMid: fMinX += width - this.ViewBox.Width * fScaleX; fMinY += fMidY - fViewMidY; break; case SvgPreserveAspectRatio.xMinYMax: fMinY += height - this.ViewBox.Height * fScaleY; break; case SvgPreserveAspectRatio.xMidYMax: fMinX += fMidX - fViewMidX; fMinY += height - this.ViewBox.Height * fScaleY; break; case SvgPreserveAspectRatio.xMaxYMax: fMinX += width - this.ViewBox.Width * fScaleX; fMinY += height - this.ViewBox.Height * fScaleY; break; default: break; } } var x = _x.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this); var y = _y.ToDeviceValue(renderer, UnitRenderingType.Vertical, this); renderer.AddClip(new Region(new RectangleF(x, y, width, height))); renderer.ScaleTransform(fScaleX, fScaleY, MatrixOrder.Prepend); renderer.TranslateTransform(x, y); renderer.TranslateTransform(fMinX, fMinY); } return(true); }