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