using System; using System.IO; using System.IO.Compression; using System.Xml; using System.Reflection; using System.Globalization; using System.ComponentModel; using System.Windows; using System.Windows.Media; using System.Windows.Markup; using System.Windows.Controls; using System.Windows.Resources; using SharpVectors.Runtime; using SharpVectors.Renderers.Wpf; namespace SharpVectors.Converters { /// /// This is a control for viewing SVG file in WPF /// applications. /// /// /// It extends the drawing canvas, , instead of /// generic control, therefore any interactivity support /// implemented in the drawing canvas will be available in the /// . /// public class SvgCanvas : SvgDrawingCanvas, IUriContext { #region Private Fields private bool _isAutoSized; private bool _autoSize; private bool _textAsGeometry; private bool _includeRuntime; private bool _optimizePath; private DrawingGroup _svgDrawing; private CultureInfo _culture; private Uri _baseUri; private Uri _sourceUri; #endregion #region Constructors and Destructor /// /// Initializes a new instance of the class. /// public SvgCanvas() { _textAsGeometry = false; _includeRuntime = true; _optimizePath = true; } #endregion #region Public Properties /// /// Gets or sets the path to the SVG file to load into this /// . /// /// /// A specifying the path to the SVG source file. /// The file can be located on a computer, network or assembly resources. /// Settings this to will close any opened diagram. /// public Uri Source { get { return _sourceUri; } set { _sourceUri = value; if (_sourceUri == null) { this.OnUnloadDiagram(); } else { this.OnSettingsChanged(); } } } /// /// Gets or sets a value indicating whether to automatically resize this /// based on the size of the loaded drawing. /// /// /// This is if this is /// automatically resized based on the size of the loaded drawing; /// otherwise, it is . The default is /// , and the user-defined size or the parent assigned /// layout size is used. /// public bool AutoSize { get { return _autoSize; } set { _autoSize = value; this.OnAutoSizeChanged(); } } /// /// Gets or sets a value indicating whether the path geometry is /// optimized using the . /// /// /// This is if the path geometry is optimized /// using the ; otherwise, it is /// . The default is . /// public bool OptimizePath { get { return _optimizePath; } set { _optimizePath = value; this.OnSettingsChanged(); } } /// /// Gets or sets a value indicating whether the texts are rendered as /// path geometry. /// /// /// This is if texts are rendered as path /// geometries; otherwise, this is . The default /// is . /// public bool TextAsGeometry { get { return _textAsGeometry; } set { _textAsGeometry = value; this.OnSettingsChanged(); } } /// /// Gets or sets a value indicating whether the SharpVectors.Runtime.dll /// classes are used in the generated output. /// /// /// This is if the SharpVectors.Runtime.dll /// classes and types are used in the generated output; otherwise, it is /// . The default is . /// /// /// The use of the SharpVectors.Runtime.dll prevents the hard-coded /// font path generated by the class, support /// for embedded images etc. /// public bool IncludeRuntime { get { return _includeRuntime; } set { _includeRuntime = value; this.OnSettingsChanged(); } } /// /// Gets or sets the main culture information used for rendering texts. /// /// /// An instance of the specifying the main /// culture information for texts. The default is the English culture. /// /// /// /// This is the culture information passed to the /// class instance for the text rendering. /// /// /// The library does not currently provide any means of splitting texts /// into its multi-language parts. /// /// public CultureInfo CultureInfo { get { return _culture; } set { if (value != null) { _culture = value; this.OnSettingsChanged(); } } } #endregion #region Public Methods #endregion #region Protected Methods /// /// Raises the Initialized event. This method is invoked whenever IsInitialized is set to true. /// /// Event data for the event. protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); if (_sourceUri != null) { if (_svgDrawing == null) { DrawingGroup drawing = this.CreateDrawing(); if (drawing != null) { this.OnLoadDrawing(drawing); } } } } /// /// This handles changes in the rendering settings of this control. /// protected virtual void OnSettingsChanged() { if (!this.IsInitialized || _sourceUri == null) { return; } DrawingGroup drawing = this.CreateDrawing(); if (drawing != null) { this.OnLoadDrawing(drawing); } } /// /// This handles changes in the automatic resizing property of this control. /// protected virtual void OnAutoSizeChanged() { if (_autoSize) { if (this.IsInitialized && _svgDrawing != null) { Rect rectDrawing = _svgDrawing.Bounds; if (!rectDrawing.IsEmpty) { this.Width = rectDrawing.Width; this.Height = rectDrawing.Height; _isAutoSized = true; } } } else { if (_isAutoSized) { this.Width = Double.NaN; this.Height = Double.NaN; } } } /// /// Performs the conversion of a valid SVG source file to the /// . /// /// /// This returns if successful; otherwise, it /// returns . /// protected virtual DrawingGroup CreateDrawing() { Uri svgSource = this.GetAbsoluteUri(); DrawingGroup drawing = null; if (svgSource == null) { return drawing; } try { string scheme = svgSource.Scheme; if (String.IsNullOrEmpty(scheme)) { return null; } WpfDrawingSettings settings = new WpfDrawingSettings(); settings.IncludeRuntime = _includeRuntime; settings.TextAsGeometry = _textAsGeometry; settings.OptimizePath = _optimizePath; if (_culture != null) { settings.CultureInfo = _culture; } switch (scheme) { case "file": //case "ftp": //case "https": case "http": using (FileSvgReader reader = new FileSvgReader(settings)) { drawing = reader.Read(svgSource); } break; case "pack": StreamResourceInfo svgStreamInfo = null; if (svgSource.ToString().IndexOf("siteoforigin", StringComparison.OrdinalIgnoreCase) >= 0) { svgStreamInfo = Application.GetRemoteStream(svgSource); } else { svgStreamInfo = Application.GetResourceStream(svgSource); } Stream svgStream = (svgStreamInfo != null) ? svgStreamInfo.Stream : null; if (svgStream != null) { string fileExt = Path.GetExtension(svgSource.ToString()); bool isCompressed = !String.IsNullOrEmpty(fileExt) && String.Equals(fileExt, ".svgz", StringComparison.OrdinalIgnoreCase); if (isCompressed) { using (svgStream) { using (GZipStream zipStream = new GZipStream(svgStream, CompressionMode.Decompress)) { using (FileSvgReader reader = new FileSvgReader(settings)) { drawing = reader.Read(zipStream); } } } } else { using (svgStream) { using (FileSvgReader reader = new FileSvgReader(settings)) { drawing = reader.Read(svgStream); } } } } break; } } catch { if (DesignerProperties.GetIsInDesignMode(new DependencyObject()) || LicenseManager.UsageMode == LicenseUsageMode.Designtime) { return drawing; } throw; } return drawing; } #endregion #region Private Methods private void OnLoadDrawing(DrawingGroup drawing) { if (drawing == null) { return; } this.OnUnloadDiagram(); this.RenderDiagrams(drawing); _svgDrawing = drawing; this.OnAutoSizeChanged(); } private void OnUnloadDiagram() { this.UnloadDiagrams(); if (_isAutoSized) { this.Width = Double.NaN; this.Height = Double.NaN; } } private Uri GetAbsoluteUri() { if (_sourceUri == null) { return null; } Uri svgSource = _sourceUri; if (svgSource.IsAbsoluteUri) { return svgSource; } else { // Try getting a local file in the same directory.... string svgPath = svgSource.ToString(); if (svgPath[0] == '\\' || svgPath[0] == '/') { svgPath = svgPath.Substring(1); } svgPath = svgPath.Replace('/', '\\'); Assembly assembly = Assembly.GetExecutingAssembly(); string localFile = Path.Combine(Path.GetDirectoryName( assembly.Location), svgPath); if (File.Exists(localFile)) { return new Uri(localFile); } // Try getting it as resource file... if (_baseUri != null) { return new Uri(_baseUri, svgSource); } else { string asmName = assembly.GetName().Name; string uriString = String.Format( "pack://application:,,,/{0};component/{1}", asmName, svgPath); return new Uri(uriString); } } } #endregion #region IUriContext Members /// /// Gets or sets the base URI of the current application context. /// /// /// The base URI of the application context. /// public Uri BaseUri { get { return _baseUri; } set { _baseUri = value; } } #endregion } }