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