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
}
}