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 a SVG file to object, and can
/// optionally save the result to a file as XAML.
///
public sealed class FileSvgReader : SvgConverter
{
#region Private Fields
private bool _writerErrorOccurred;
private bool _fallbackOnWriterError;
private DirectoryInfo _workingDir;
///
/// This is the last drawing generated.
///
private DrawingGroup _drawing;
///
/// 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 FileSvgReader(WpfDrawingSettings settings)
: this(false, false, null, settings)
{
}
///
/// Initializes a new instance of the class
/// with the specified drawing or rendering settings, the saving options
/// and the working directory.
///
///
/// 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.
///
///
/// The working directory, where converted outputs are saved.
///
///
/// This specifies the settings used by the rendering or drawing engine.
/// If this is , the default settings is used.
///
public FileSvgReader(bool saveXaml, bool saveZaml,
DirectoryInfo workingDir, WpfDrawingSettings settings)
: base(saveXaml, saveZaml, settings)
{
_wpfRenderer = new WpfDrawingRenderer(this.DrawingSettings);
_wpfWindow = new WpfSvgWindow(640, 480, _wpfRenderer);
_workingDir = workingDir;
if (_workingDir != null)
{
if (!_workingDir.Exists)
{
_workingDir.Create();
}
}
}
#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;
}
}
///
/// Gets the last created drawing.
///
///
/// A specifying the last converted drawing.
///
public DrawingGroup Drawing
{
get
{
return _drawing;
}
}
#endregion
#region Public Methods
///
/// Reads in the specified SVG file and converts it to WPF drawing.
///
///
/// Reads in the specified SVG file and converts it to WPF drawing.
///
///
/// The full path of the SVG source file.
///
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
///
/// If the is empty.
/// -or-
/// If the does not exists.
///
public DrawingGroup Read(string svgFileName)
{
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 (_workingDir == null)
{
svgFileName = Path.GetFullPath(svgFileName);
_workingDir = new DirectoryInfo(
Path.GetDirectoryName(svgFileName));
}
return this.LoadFile(svgFileName);
}
///
/// Reads in the specified SVG file and converts it to WPF drawing.
///
///
/// A specifying the path to the SVG file.
///
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
public DrawingGroup Read(Uri svgUri)
{
if (svgUri == null)
{
throw new ArgumentNullException("svgUri",
"The SVG source file cannot be null (or Nothing).");
}
return this.LoadFile(svgUri);
}
///
/// Reads in the specified SVG file stream and converts it to WPF drawing.
///
/// The source SVG file stream.
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
public DrawingGroup Read(Stream svgStream)
{
if (svgStream == null)
{
throw new ArgumentNullException("svgStream",
"The SVG source file cannot be null (or Nothing).");
}
return this.LoadFile(svgStream);
}
///
/// Reads in the specified source from the SVG file reader and converts
/// it to WPF drawing.
///
///
/// A text reader providing access to the SVG file data.
///
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
public DrawingGroup Read(TextReader svgTextReader)
{
if (svgTextReader == null)
{
throw new ArgumentNullException("svgTextReader",
"The SVG source file cannot be null (or Nothing).");
}
return this.LoadFile(svgTextReader);
}
///
/// Reads in the specified source SVG file reader and converts it to
/// WPF drawing.
///
///
/// An XML reader providing access to the SVG file data.
///
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
public DrawingGroup Read(XmlReader svgXmlReader)
{
if (svgXmlReader == null)
{
throw new ArgumentNullException("svgTextReader",
"The SVG source file cannot be null (or Nothing).");
}
return this.LoadFile(svgXmlReader);
}
///
/// Reads in the specified SVG file, converting it to WPF drawing and
/// saving the results to the specified directory if successful.
///
///
/// The full path of the SVG source file.
///
///
/// The destination of the output XAML file, if the saving properties
/// are enabled.
///
///
/// This returns the representing the SVG file,
/// if successful; otherwise, it returns .
///
///
/// If the is .
///
///
/// If the is empty.
/// -or-
/// If the does not exists.
///
public DrawingGroup Read(string svgFileName, DirectoryInfo destinationDir)
{
_workingDir = destinationDir;
if (_workingDir != null)
{
if (!_workingDir.Exists)
{
_workingDir.Create();
}
}
return this.Read(svgFileName);
}
///
/// Saves the last converted file to the specified file name.
///
///
/// The full path of the output file.
///
///
/// A value indicating whether to save the output to XAML file.
///
///
/// A value indicating whether to save the output to ZAML file, which
/// is a G-zip compression of the XAML file.
///
///
/// This returns if either
/// or is and the operation
/// is successful.
///
///
///
/// If the output serialization properties are not enabled, this method
/// can be used to save the output to a file.
///
///
/// This will not change the output serialization properties of this object.
///
///
///
/// If there is no converted drawing from a previous conversion process
/// to be saved.
///
public bool Save(string fileName, bool asXaml, bool asZaml)
{
if (_drawing == null)
{
throw new InvalidOperationException(
"There is no converted drawing for the saving operation.");
}
// We save the current states and properties...
bool saveXaml = this.SaveXaml;
bool saveZaml = this.SaveZaml;
this.SaveXaml = asXaml;
this.SaveZaml = asZaml;
DirectoryInfo workingDir = _workingDir;
fileName = Path.GetFullPath(fileName);
_workingDir = new DirectoryInfo(Path.GetDirectoryName(fileName));
bool savedResult = this.SaveFile(fileName);
// Restore the current states and properties...
this.SaveXaml = saveXaml;
this.SaveZaml = saveZaml;
_workingDir = workingDir;
return savedResult;
}
#endregion
#region Load Method
private DrawingGroup LoadFile(string fileName)
{
_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);
_drawing = _wpfRenderer.Drawing as DrawingGroup;
if (_drawing == null)
{
return null;
}
SaveFile(fileName);
return _drawing;
}
private DrawingGroup LoadFile(Stream stream)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(stream);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
_drawing = _wpfRenderer.Drawing as DrawingGroup;
if (_drawing == null)
{
return null;
}
return _drawing;
}
private DrawingGroup LoadFile(Uri svgUri)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(svgUri);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
_drawing = _wpfRenderer.Drawing as DrawingGroup;
if (_drawing == null)
{
return null;
}
return _drawing;
}
private DrawingGroup LoadFile(TextReader textReader)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(textReader);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
_drawing = _wpfRenderer.Drawing as DrawingGroup;
if (_drawing == null)
{
return null;
}
return _drawing;
}
private DrawingGroup LoadFile(XmlReader xmlReader)
{
_wpfRenderer.LinkVisitor = new LinkVisitor();
_wpfRenderer.ImageVisitor = new EmbeddedImageVisitor();
_wpfRenderer.FontFamilyVisitor = new FontFamilyVisitor();
_wpfWindow.LoadDocument(xmlReader);
_wpfRenderer.InvalidRect = SvgRectF.Empty;
_wpfRenderer.Render(_wpfWindow.Document as SvgDocument);
_drawing = _wpfRenderer.Drawing as DrawingGroup;
if (_drawing == null)
{
return null;
}
return _drawing;
}
#endregion
#region SaveFile Method
private bool SaveFile(string fileName)
{
if (_workingDir == null || (!this.SaveXaml && !this.SaveZaml))
{
return false;
}
_writerErrorOccurred = false;
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
string xamlFileName = Path.Combine(_workingDir.FullName,
fileNameWithoutExt + ".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 the file exist, we back it up and save a new file...
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
}
}