using System;
using System.IO;
using System.IO.Compression;
using System.Xml;
using System.Text;
using System.Windows;
using System.Windows.Media;
using SharpVectors.Dom.Svg;
using SharpVectors.Runtime;
using SharpVectors.Renderers;
using SharpVectors.Renderers.Wpf;
using SharpVectors.Renderers.Utils;
namespace SharpVectors.Converters
{
///
///
/// This converts an SVG file to the corresponding XAML file, which can
/// be viewed in WPF application.
///
///
/// The root object in the converted file is .
///
///
public sealed class FileSvgConverter : SvgConverter
{
#region Private Fields
private bool _writerErrorOccurred;
private bool _fallbackOnWriterError;
///
/// Required designer variable.
///
private WpfSvgWindow _wpfWindow;
private WpfDrawingRenderer _wpfRenderer;
#endregion
#region Constructors and Destructor
///
/// Initializes a new instance of the class.
///
///
/// Initializes a new instance of the class
/// with the specified drawing or rendering settings.
///
///
/// This specifies the settings used by the rendering or drawing engine.
/// If this is , the default settings is used.
///
public FileSvgConverter(WpfDrawingSettings settings)
: this(true, false, settings)
{
}
///
/// Initializes a new instance of the class
/// with the specified drawing or rendering settings and the saving options.
///
///
/// This specifies whether to save result object tree in XAML file.
///
///
/// This specifies whether to save result object tree in ZAML file. The
/// ZAML is simply a G-Zip compressed XAML format, similar to the SVGZ.
///
///
/// This specifies the settings used by the rendering or drawing engine.
/// If this is , the default settings is used.
///
public FileSvgConverter(bool saveXaml, bool saveZaml,
WpfDrawingSettings settings)
: base(saveXaml, saveZaml, settings)
{
_wpfRenderer = new WpfDrawingRenderer(this.DrawingSettings);
_wpfWindow = new WpfSvgWindow(640, 480, _wpfRenderer);
}
#endregion
#region Public Properties
///
/// Gets a value indicating whether a writer error occurred when
/// using the custom XAML writer.
///
///
/// This is if an error occurred when using
/// the custom XAML writer; otherwise, it is .
///
public bool WriterErrorOccurred
{
get
{
return _writerErrorOccurred;
}
}
///
/// Gets or sets a value indicating whether to fall back and use
/// the .NET Framework XAML writer when an error occurred in using the
/// custom writer.
///
///
/// This is if the converter falls back to using
/// the system XAML writer when an error occurred in using the custom
/// writer; otherwise, it is . If ,
/// an exception, which occurred in using the custom writer will be
/// thrown. The default is .
///
public bool FallbackOnWriterError
{
get
{
return _fallbackOnWriterError;
}
set
{
_fallbackOnWriterError = value;
}
}
#endregion
#region Public Methods
///
/// This performs the conversion of the specified SVG file, and saves
/// the output to an XAML file.
///
///
/// This performs the conversion of the specified SVG file, and saves
/// the output to an XAML file with the same file name.
///
///
/// The full path of the SVG source file.
///
///
/// This returns if the conversion is successful;
/// otherwise, it return .
///
///
/// If the is .
///
///
/// If the is empty.
/// -or-
/// If the does not exists.
///
public bool Convert(string svgFileName)
{
return this.Convert(svgFileName, String.Empty);
}
///
/// This performs the conversion of the specified SVG file, and saves
/// the output to the specified XAML file.
///
///
/// The full path of the SVG source file.
///
///
/// The output XAML file. This is optional. If not specified, an XAML
/// file is created in the same directory as the SVG file.
///
///
/// This returns if the conversion is successful;
/// otherwise, it return .
///
///
/// If the is .
///
///
/// If the is empty.
/// -or-
/// If the does not exists.
///
public bool Convert(string svgFileName, string xamlFileName)
{
if (svgFileName == null)
{
throw new ArgumentNullException("svgFileName",
"The SVG source file cannot be null (or Nothing).");
}
if (svgFileName.Length == 0)
{
throw new ArgumentException(
"The SVG source file cannot be empty.", "svgFileName");
}
if (!File.Exists(svgFileName))
{
throw new ArgumentException(
"The SVG source file must exists.", "svgFileName");
}
if (!this.SaveXaml && !this.SaveZaml)
{
return false;
}
if (!String.IsNullOrEmpty(xamlFileName))
{
string workingDir = Path.GetDirectoryName(xamlFileName);
if (!Directory.Exists(workingDir))
{
Directory.CreateDirectory(workingDir);
}
}
return this.ProcessFile(svgFileName, xamlFileName);
}
///
/// This performs the conversion of the specified SVG source, and saves
/// the output to the specified XAML file.
///
///
/// A stream providing access to the SVG source data.
///
///
/// The output XAML file. This is optional. If not specified, an XAML
/// file is created in the same directory as the SVG file.
///
///
/// This returns if the conversion is successful;
/// otherwise, it return .
///
///
/// If the is .
/// -or-
/// If the is .
///
///
/// If the is empty.
///
public bool Convert(Stream svgStream, string xamlFileName)
{
if (svgStream == null)
{
throw new ArgumentNullException("svgStream",
"The SVG source file cannot be null (or Nothing).");
}
if (xamlFileName == null)
{
throw new ArgumentNullException("xamlFileName",
"The XAML destination file path cannot be null (or Nothing).");
}
if (xamlFileName.Length == 0)
{
throw new ArgumentException(
"The XAML destination file path cannot be empty.", "xamlFileName");
}
if (!this.SaveXaml && !this.SaveZaml)
{
return false;
}
if (!String.IsNullOrEmpty(xamlFileName))
{
string workingDir = Path.GetDirectoryName(xamlFileName);
if (!Directory.Exists(workingDir))
{
Directory.CreateDirectory(workingDir);
}
}
return this.ProcessFile(svgStream, xamlFileName);
}
///
/// This performs the conversion of the specified SVG source, and saves
/// the output to the specified XAML file.
///
///
/// A text reader providing access to the SVG source data.
///
///
/// The output XAML file. This is optional. If not specified, an XAML
/// file is created in the same directory as the SVG file.
///
///
/// This returns if the conversion is successful;
/// otherwise, it return .
///
///
/// If the is .
/// -or-
/// If the is .
///
///
/// If the is empty.
///
public bool Convert(TextReader svgTextReader, string xamlFileName)
{
if (svgTextReader == null)
{
throw new ArgumentNullException("svgTextReader",
"The SVG source file cannot be null (or Nothing).");
}
if (xamlFileName == null)
{
throw new ArgumentNullException("xamlFileName",
"The XAML destination file path cannot be null (or Nothing).");
}
if (xamlFileName.Length == 0)
{
throw new ArgumentException(
"The XAML destination file path cannot be empty.", "xamlFileName");
}
if (!this.SaveXaml && !this.SaveZaml)
{
return false;
}
if (!String.IsNullOrEmpty(xamlFileName))
{
string workingDir = Path.GetDirectoryName(xamlFileName);
if (!Directory.Exists(workingDir))
{
Directory.CreateDirectory(workingDir);
}
}
return this.ProcessFile(svgTextReader, xamlFileName);
}
///
/// This performs the conversion of the specified SVG source, and saves
/// the output to the specified XAML file.
///
///
/// An XML reader providing access to the SVG source data.
///
///
/// The output XAML file. This is optional. If not specified, an XAML
/// file is created in the same directory as the SVG file.
///
///
/// This returns if the conversion is successful;
/// otherwise, it return .
///
///
/// If the is .
/// -or-
/// If the is .
///
///
/// If the is empty.
///
public bool Convert(XmlReader svgXmlReader, string xamlFileName)
{
if (svgXmlReader == null)
{
throw new ArgumentNullException("svgXmlReader",
"The SVG source file cannot be null (or Nothing).");
}
if (xamlFileName == null)
{
throw new ArgumentNullException("xamlFileName",
"The XAML destination file path cannot be null (or Nothing).");
}
if (xamlFileName.Length == 0)
{
throw new ArgumentException(
"The XAML destination file path cannot be empty.", "xamlFileName");
}
if (!this.SaveXaml && !this.SaveZaml)
{
return false;
}
if (!String.IsNullOrEmpty(xamlFileName))
{
string workingDir = Path.GetDirectoryName(xamlFileName);
if (!Directory.Exists(workingDir))
{
Directory.CreateDirectory(workingDir);
}
}
return this.ProcessFile(svgXmlReader, xamlFileName);
}
#endregion
#region Private Methods
#region ProcessFile Method
private bool ProcessFile(string fileName, string xamlFileName)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(fileName);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
DrawingGroup renderedDrawing = _wpfRenderer.Drawing as DrawingGroup;
if (renderedDrawing == null)
{
return false;
}
SaveFile(renderedDrawing, fileName, xamlFileName);
renderedDrawing = null;
return true;
}
private bool ProcessFile(Stream svgStream, string xamlFileName)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(svgStream);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
DrawingGroup renderedDrawing = _wpfRenderer.Drawing as DrawingGroup;
if (renderedDrawing == null)
{
return false;
}
SaveFile(renderedDrawing, xamlFileName, xamlFileName);
renderedDrawing = null;
return true;
}
private bool ProcessFile(TextReader svgTextReader, string xamlFileName)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(svgTextReader);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
DrawingGroup renderedDrawing = _wpfRenderer.Drawing as DrawingGroup;
if (renderedDrawing == null)
{
return false;
}
SaveFile(renderedDrawing, xamlFileName, xamlFileName);
renderedDrawing = null;
return true;
}
private bool ProcessFile(XmlReader svgXmlReader, string xamlFileName)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(svgXmlReader);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
DrawingGroup renderedDrawing = _wpfRenderer.Drawing as DrawingGroup;
if (renderedDrawing == null)
{
return false;
}
SaveFile(renderedDrawing, xamlFileName, xamlFileName);
renderedDrawing = null;
return true;
}
#endregion
#region SaveFile Method
private bool SaveFile(Drawing drawing, string fileName, string xamlFileName)
{
_writerErrorOccurred = false;
if (String.IsNullOrEmpty(xamlFileName))
{
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
string workingDir = Path.GetDirectoryName(fileName);
xamlFileName = Path.Combine(workingDir,
fileNameWithoutExt + ".xaml");
}
else
{
string fileExt = Path.GetExtension(xamlFileName);
if (String.IsNullOrEmpty(fileExt))
{
xamlFileName += ".xaml";
}
else if (!String.Equals(fileExt, ".xaml",
StringComparison.OrdinalIgnoreCase))
{
xamlFileName = Path.ChangeExtension(xamlFileName, ".xaml");
}
}
if (File.Exists(xamlFileName))
{
File.SetAttributes(xamlFileName, FileAttributes.Normal);
File.Delete(xamlFileName);
}
if (this.UseFrameXamlWriter)
{
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.OmitXmlDeclaration = true;
writerSettings.Encoding = Encoding.UTF8;
using (FileStream xamlFile = File.Create(xamlFileName))
{
using (XmlWriter writer = XmlWriter.Create(
xamlFile, writerSettings))
{
System.Windows.Markup.XamlWriter.Save(
drawing, writer);
}
}
}
else
{
try
{
XmlXamlWriter xamlWriter = new XmlXamlWriter(
this.DrawingSettings);
using (FileStream xamlFile = File.Create(xamlFileName))
{
xamlWriter.Save(drawing, xamlFile);
}
}
catch
{
_writerErrorOccurred = true;
if (_fallbackOnWriterError)
{
if (File.Exists(xamlFileName))
{
File.Move(xamlFileName, xamlFileName + ".bak");
}
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.Indent = true;
writerSettings.OmitXmlDeclaration = true;
writerSettings.Encoding = Encoding.UTF8;
using (FileStream xamlFile = File.Create(xamlFileName))
{
using (XmlWriter writer = XmlWriter.Create(
xamlFile, writerSettings))
{
System.Windows.Markup.XamlWriter.Save(
drawing, writer);
}
}
}
else
{
throw;
}
}
}
if (this.SaveZaml)
{
string zamlFileName = Path.ChangeExtension(xamlFileName, ".zaml");
if (File.Exists(zamlFileName))
{
File.SetAttributes(zamlFileName, FileAttributes.Normal);
File.Delete(zamlFileName);
}
FileStream zamlSourceFile = new FileStream(xamlFileName, FileMode.Open,
FileAccess.Read, FileShare.Read);
byte[] buffer = new byte[zamlSourceFile.Length];
// Read the file to ensure it is readable.
int count = zamlSourceFile.Read(buffer, 0, buffer.Length);
if (count != buffer.Length)
{
zamlSourceFile.Close();
return false;
}
zamlSourceFile.Close();
FileStream zamlDestFile = File.Create(zamlFileName);
GZipStream zipStream = new GZipStream(zamlDestFile, CompressionMode.Compress, true);
zipStream.Write(buffer, 0, buffer.Length);
zipStream.Close();
zamlDestFile.Close();
}
if (!this.SaveXaml && File.Exists(xamlFileName))
{
File.Delete(xamlFileName);
}
return true;
}
#endregion
#endregion
}
}