SvgImage.cs 5.77 KB
Newer Older
1
2
using System;
using System.Diagnostics;
3
using System.Drawing;
4
5
6
7
using System.Drawing.Drawing2D;
using System.IO;
using System.Net;
using Svg.Transforms;
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

namespace Svg
{
    /// <summary>
    /// Represents and SVG image
    /// </summary>
    [SvgElement("image")]
    public class SvgImage : SvgVisualElement
    {
        /// <summary>
		/// Initializes a new instance of the <see cref="SvgImage"/> class.
        /// </summary>
		public SvgImage()
        {
            Width = new SvgUnit(0.0f);
            Height = new SvgUnit(0.0f);
        }

        /// <summary>
        /// Gets an <see cref="SvgPoint"/> representing the top left point of the rectangle.
        /// </summary>
        public SvgPoint Location
        {
            get { return new SvgPoint(X, Y); }
        }

		[SvgAttribute("x")]
		public virtual SvgUnit X
		{
			get { return this.Attributes.GetAttribute<SvgUnit>("x"); }
			set { this.Attributes["x"] = value; }
		}

		[SvgAttribute("y")]
		public virtual SvgUnit Y
		{
			get { return this.Attributes.GetAttribute<SvgUnit>("y"); }
			set { this.Attributes["y"] = value; }
		}


		[SvgAttribute("width")]
		public virtual SvgUnit Width
		{
			get { return this.Attributes.GetAttribute<SvgUnit>("width"); }
			set { this.Attributes["width"] = value; }
		}

		[SvgAttribute("height")]
		public virtual SvgUnit Height
		{
			get { return this.Attributes.GetAttribute<SvgUnit>("height"); }
			set { this.Attributes["height"] = value; }
		}

		[SvgAttribute("href", SvgAttributeAttribute.XLinkNamespace)]
		public virtual Uri Href
		{
			get { return this.Attributes.GetAttribute<Uri>("href"); }
			set { this.Attributes["href"] = value; }
		}



        /// <summary>
        /// Gets the bounds of the element.
        /// </summary>
        /// <value>The bounds.</value>
        public override RectangleF Bounds
        {
			get { return new RectangleF(this.Location.ToDeviceValue(), new SizeF(this.Width, this.Height)); }
        }

        /// <summary>
        /// Gets the <see cref="GraphicsPath"/> for this element.
        /// </summary>
        public override GraphicsPath Path
        {
            get
            {
				return null;
            }
90
91
92
            protected set
            {
            }
93
94
95
96
        }

        /// <summary>
        /// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
97
98
99
        /// </summary>
        protected override void Render(SvgRenderer renderer)
        {
C Moore's avatar
C Moore committed
100
101
102
            if (!Visible || !Displayable)
                return;

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
            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
            {
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
                // 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;
                }

146
147
148
149
150
151
                // should work with http: and file: protocol urls
                var httpRequest = WebRequest.Create(uri);

                using (WebResponse webResponse = httpRequest.GetResponse())
                {
                    MemoryStream ms = BufferToMemoryStream(webResponse.GetResponseStream());
152
153
                    Image image = Bitmap.FromStream(ms);
                    return image;
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
                }
            }
            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;
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
        }


		public override SvgElement DeepCopy()
		{
			return DeepCopy<SvgImage>();
		}

		public override SvgElement DeepCopy<T>()
		{
 			var newObj = base.DeepCopy<T>() as SvgImage;
			newObj.Height = this.Height;
			newObj.Width = this.Width;
			newObj.X = this.X;
			newObj.Y = this.Y;
			newObj.Href = this.Href;
			return newObj;
		}
    }
}