using System; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.IO; using System.Net; using Svg.Transforms; namespace Svg { /// /// Represents and SVG image /// [SvgElement("image")] public class SvgImage : SvgVisualElement { /// /// Initializes a new instance of the class. /// public SvgImage() { Width = new SvgUnit(0.0f); Height = new SvgUnit(0.0f); } /// /// Gets an representing the top left point of the rectangle. /// public SvgPoint Location { get { return new SvgPoint(X, Y); } } [SvgAttribute("x")] public virtual SvgUnit X { get { return this.Attributes.GetAttribute("x"); } set { this.Attributes["x"] = value; } } [SvgAttribute("y")] public virtual SvgUnit Y { get { return this.Attributes.GetAttribute("y"); } set { this.Attributes["y"] = value; } } [SvgAttribute("width")] public virtual SvgUnit Width { get { return this.Attributes.GetAttribute("width"); } set { this.Attributes["width"] = value; } } [SvgAttribute("height")] public virtual SvgUnit Height { get { return this.Attributes.GetAttribute("height"); } set { this.Attributes["height"] = value; } } [SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)] public virtual Uri Href { get { return this.Attributes.GetAttribute("href"); } set { this.Attributes["href"] = value; } } /// /// Gets the bounds of the element. /// /// The bounds. public override RectangleF Bounds { get { return new RectangleF(this.Location.ToDeviceValue(), new SizeF(this.Width, this.Height)); } } /// /// Gets the for this element. /// public override GraphicsPath Path { get { return null; } protected set { } } /// /// Renders the and contents to the specified object. /// 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) { this.PushTransforms(renderer); this.SetClip(renderer); RectangleF srcRect = new RectangleF(0, 0, b.Width, b.Height); var destRect = new RectangleF(this.Location.ToDeviceValue(), new SizeF(Width.ToDeviceValue(), Height.ToDeviceValue())); 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 } } protected Image GetImage(Uri uri) { try { // handle data/uri embedded images (http://en.wikipedia.org/wiki/Data_URI_scheme) if (uri.Scheme == "data") { string uriString = uri.OriginalString; int dataIdx = uriString.IndexOf(",") + 1; if (dataIdx <= 0 || dataIdx + 1 > uriString.Length) throw new Exception("Invalid data URI"); // we're assuming base64, as ascii encoding would be *highly* unsusual for images // also assuming it's png or jpeg mimetype byte[] imageBytes = Convert.FromBase64String(uriString.Substring(dataIdx)); Image image = Image.FromStream(new MemoryStream(imageBytes)); return image; } // should work with http: and file: protocol urls var httpRequest = WebRequest.Create(uri); using (WebResponse webResponse = httpRequest.GetResponse()) { MemoryStream ms = BufferToMemoryStream(webResponse.GetResponseStream()); Image image = Bitmap.FromStream(ms); return image; } } catch (Exception ex) { Trace.TraceError("Error loading image: '{0}', error: {1} ", uri, ex.Message); return null; } } protected static MemoryStream BufferToMemoryStream(Stream input) { byte[] buffer = new byte[4 * 1024]; int len; MemoryStream ms = new MemoryStream(); while ((len = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, len); } ms.Seek(0, SeekOrigin.Begin); return ms; } public override SvgElement DeepCopy() { return DeepCopy(); } public override SvgElement DeepCopy() { var newObj = base.DeepCopy() as SvgImage; newObj.Height = this.Height; newObj.Width = this.Width; newObj.X = this.X; newObj.Y = this.Y; newObj.Href = this.Href; return newObj; } } }