Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / WPF

Convert XAML Vector Graphic to PNG

Rate me:
Please Sign up or sign in to vote.
4.87/5 (11 votes)
23 Oct 2012CPOL12 min read 74.3K   6.8K   43  
An introduction to the usage of vector graphics as a source of bitmap graphics.
namespace XAMLtoPNG
{
  using System;
  using System.Collections.Generic;
using System.Reflection;

  class Params
  {
    #region command line options
    public static string OptXSize = "-XSize";
    public static string OptYSize = "-YSize";
    public static string OptXDPI = "-XDPI";
    public static string OptYDPI = "-YDPI";

    public static string OptInputPath = "-Input";
    public static string OptOutPath = "-Output";

    public static string OptScaleMode = "-ScaleMode";
    public static string OptScaleModeOriginal = "Original";
    public static string OptScaleModeTarget = "Target";
    #endregion command line options

    #region message texts
    public static string ParamValueInvalidSizeMsg = "Command line parameter '{0}' is invalid because '{1}' is not a known option (this must be either '{2}' or '{3}').";
    public static string ParamValueInvalidStringMsg = "Command line parameter '{0}' is invalid because it has a zero length.";
    public static string ParamValueInvalidMsg = "Command line parameter '{0}' is invalid because the value '{1}' is invalid.";
    public static string ParamValueMissingMsg = "Command line parameter '{0}' is invalid because the value is missing.";

    public static string ToolUsageMsg = "XAML to PNG command line conversion tool.\n" +
                                        string.Format("Usage: {0}\n", Assembly.GetEntryAssembly().GetName().Name)

    + string.Format("{0} <size> - X size in pixels of converted png output image\n", Params.OptXSize)
    + string.Format("{0} <size> - Y size in pixels of converted png output image\n", Params.OptYSize)
    + string.Format("{0} <size> - Assumed X (Dots Per Inch) DPI of XAML input\n", Params.OptXDPI)
    + string.Format("{0} <size> - Assumed Y (Dots Per Inch) DPI of XAML input\n", Params.OptYDPI)

    + string.Format("{0} path to input XAML file or directory containing input XAML files - File name and path of XAML input file or path to directory containing XAML input files.\n", Params.OptInputPath)
    + string.Format("{0} path to ouput PNG file or directory that will contain ouput PNG files- File name and path of PNG output file or path to directory where PNG output files are to be saved.\n", Params.OptOutPath)

    + string.Format("{0} - Scale mode can be based on Original size or based on ouput size.\n", Params.OptScaleMode)
    + string.Format("  {0}\n", Params.OptScaleModeOriginal)
    + string.Format("  {0}\n", Params.OptScaleModeTarget);
    #endregion message texts

    #region Constructor
    public Params()
    {
      this.XSize = this.YSize = 64;           // Defaults for optional parameters
      this.XDPI = this.YDPI = 96;
      this.ThisScale = ScaleTO.TargetSize;
      this.InputPath = this.OutputPath = string.Empty;
                                             
                                             // Input parameter is the only required parameter
      this.InputPath = this.OutputPath = string.Empty;

      this.InputFiles = new List<string>();
      this.OutputFiles = new List<string>();
    }
    #endregion Constructor

    #region Properties
    /// <summary>
    /// X Output size in pixels
    /// </summary>
    public int XSize { get; set; }

    /// <summary>
    /// Y Output size in pixels
    /// </summary>
    public int YSize { get; set; }

    /// <summary>
    /// X Dots per Image (DPI) assumed to convert input
    /// </summary>
    public int XDPI { get; set; }

    /// <summary>
    /// Y Dots per Image (DPI) assumed to convert input
    /// </summary>
    public int YDPI { get; set; }

    /// <summary>
    /// File name and path (or just directory) of input file(s)
    /// </summary>
    public string InputPath { get; set; }

    /// <summary>
    /// File name and path (or just directory) of output file(s)
    /// </summary>
    public string OutputPath { get; set; }

    /// <summary>
    /// List of input files.
    /// </summary>
    public List<string> InputFiles { get; set; }

    /// <summary>
    /// List of output files.
    /// </summary>
    public List<string> OutputFiles { get; set; }

    /// <summary>
    /// Parameter to determine different modes of scaling.
    /// </summary>
    public ScaleTO ThisScale { get; set; }
    #endregion Properties

    #region Methods
    /// <summary>
    /// Parse command line options and return a command line <seealso cref="Params"/> object
    /// plus error code and string (if any).
    /// </summary>
    /// <param name="args"></param>
    /// <param name="progParams"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    static public int ParseCmdLine(string[] args, out Params progParams, out string strError)
    {
      strError = string.Empty;
      progParams = new Params();

      if (args.Length == 0)
      {
         strError = Params.ToolUsageMsg;
         return -2;
      }

      for (int i = 0; i < args.Length; i++)
      {
        int iRet = 0, iNumber;
        string sValue;

        if (args[i].ToUpper() == OptXSize.ToUpper())
        {
          if ((iRet = Params.GetIntValue(args, i, OptXSize, out iNumber, out strError)) != 0)
            return iRet;

          progParams.XSize = iNumber;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptYSize.ToUpper())
        {
          if ((iRet = Params.GetIntValue(args, i, OptYSize, out iNumber, out strError)) != 0)
            return iRet;

          progParams.YSize = iNumber;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptXDPI.ToUpper())
        {
          if ((iRet = Params.GetIntValue(args, i, OptXDPI, out iNumber, out strError)) != 0)
            return iRet;

          progParams.XDPI = iNumber;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptYDPI.ToUpper())
        {
          if ((iRet = Params.GetIntValue(args, i, OptYDPI, out iNumber, out strError)) != 0)
            return iRet;

          progParams.YDPI = iNumber;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptInputPath.ToUpper())
        {
          if ((iRet = Params.GetStringValue(args, i, OptInputPath, out sValue, out strError)) != 0)
            return iRet;

          progParams.InputPath = sValue;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptOutPath.ToUpper())
        {
          if ((iRet = Params.GetStringValue(args, i, OptInputPath, out sValue, out strError)) != 0)
            return iRet;

          progParams.OutputPath = sValue;

          i++;
          continue;
        }

        if (args[i].ToUpper() == OptScaleMode.ToUpper())
        {
          ScaleTO thisScale;

          if ((iRet = Params.GetScaleValue(args, i, OptScaleMode, out thisScale, out strError)) != 0)
            return iRet;

          progParams.ThisScale = thisScale;

          i++;
          continue;
        }

        strError = string.Format("Unknown parameter: '{0}'", args[i]) + "\n\n" + Params.ToolUsageMsg;
        return -1;
      }

      try 
	    {	        
        if (System.IO.File.Exists(progParams.InputPath) == false)
        {
          if (System.IO.Directory.Exists(progParams.InputPath) == true || System.IO.Directory.Exists(progParams.InputPath + "\\") == true)
          {
            // Scan directory and Convert many source file(s) into many destination file(s)
            return ScanDirectoryAddFiles(progParams, "*.xaml", out strError);
          }
          else
          {
            strError = string.Format("Input path '{0}' does not point to an existing XAML file.", progParams.InputPath);
            return -12;
          }
        }
	    }
	    catch
	    {
        strError = string.Format("Input path '{0}' does not point to an existing XAML file.", progParams.InputPath);
        return -13;
      }

      int iReturn;
      string strOutpath;
      if ((iReturn = GetOutputPath(progParams, progParams.InputPath, out strOutpath, out strError)) != 0)
        return iReturn;

      // Convert just one source file into one destination file
      progParams.InputFiles.Add(progParams.InputPath);
      progParams.OutputFiles.Add(progParams.OutputPath);

      for (int i = 0; i < progParams.InputFiles.Count; i++)
      {
        if (progParams.InputFiles[i].ToUpper() == progParams.OutputFiles[i].ToUpper())
        {
          strError = string.Format("Output and Input path must not be equal ('{0}', '{1}').", progParams.InputFiles[i], progParams.OutputFiles[i]);
          return -11;
        }          
      }

      return 0;
    }

    /// <summary>
    /// Scan input directory and generate a collection of input and output files stored in <paramref name="progParams"/>.
    /// </summary>
    /// <param name="progParams"></param>
    /// <param name="searchPattern"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    public static int ScanDirectoryAddFiles(Params progParams, string searchPattern, out string strError)
    {
      strError = string.Empty;

      // Scan directory and convert many source file(s) into many destination file(s)
      string[] dirs = System.IO.Directory.GetFiles(progParams.InputPath, searchPattern);

      foreach (string inputFile in dirs)
      {
        int iRet;
        string strOutPath;
        if ((iRet = GetOutputPath(progParams, inputFile, out strOutPath, out strError)) != 0)
          return iRet;

        progParams.InputFiles.Add(inputFile);
        progParams.OutputFiles.Add(strOutPath);
      }

      return 0;
    }

    /// <summary>
    /// Determine the output path in dependence of whether the:
    /// 1) OutputPath has length of zero     -> Output is equal input (with *.png extension instead of *.xaml)
    /// 2) OutputPath points to a directory. -> Output is based on output directory plus file name from input plus *.xaml extension
    /// 3) OutputPath points to a file.      -> Output is written to this file.
    /// </summary>
    /// <param name="progParams"></param>
    /// <param name="inputPath"></param>
    /// <param name="strOutpath"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    public static int GetOutputPath(Params progParams, string inputPath, out string strOutpath, out string strError)
    {
      strError = strOutpath = string.Empty;

      // Compute output based on input but with different file extension "*.png"
      if (progParams.OutputPath.Length == 0)
      {
        try
        {
          string sFileName = System.IO.Path.GetFileNameWithoutExtension(inputPath) + ".png";
          strOutpath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(inputPath), sFileName);
        }
        catch
        {
          strError = string.Format("Input path '{0}' is not valid.", inputPath);
          return -14;
        }
      }
      else
      {
        try
        {
          // Complete output path with output filename if the path points at an existing directory
          if (System.IO.Directory.Exists(progParams.OutputPath) == true)
          {
            string sFileName = System.IO.Path.GetFileNameWithoutExtension(inputPath) + ".png";
            strOutpath = System.IO.Path.Combine(progParams.OutputPath, sFileName);
          }
          else
            strOutpath = progParams.OutputPath;
        }
        catch
        {
          strError = string.Format("Output path '{0}' is not valid directory ouput path.", inputPath);
          return -15;
        }
      }

      return 0;
    }

    /// <summary>
    /// Standard method to convert command line parameter string to int datatype.
    /// </summary>
    /// <param name="args"></param>
    /// <param name="CurrIndex"></param>
    /// <param name="ParamName"></param>
    /// <param name="intNumber"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    public static int GetIntValue(string[] args,
                                  int CurrIndex,
                                  string ParamName,
                                  out int intNumber,
                                  out string strError)
    {
      strError = string.Empty;
      intNumber = -1;

      if (args.Length <= (CurrIndex + 1))
      {
        strError = string.Format(ParamValueMissingMsg, ParamName);
        return -1;
      }

      try
      {
        intNumber = int.Parse(args[CurrIndex + 1]);
      }
      catch (Exception)
      {
        strError = string.Format(ParamValueInvalidMsg, ParamName, args[CurrIndex + 1]);
        return -2;
      }

      return 0;
    }

    /// <summary>
    /// Standard method to convert command line parameter into string datatype.
    /// </summary>
    /// <param name="args"></param>
    /// <param name="CurrIndex"></param>
    /// <param name="ParamName"></param>
    /// <param name="stringValue"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    public static int GetStringValue(string[] args,
                                     int CurrIndex,
                                     string ParamName,
                                     out string stringValue,
                                     out string strError)
    {
      strError = string.Empty;
      stringValue = string.Empty;

      if (args.Length <= (CurrIndex + 1))
      {
        strError = string.Format(ParamValueMissingMsg, ParamName);
        return -1;
      }

      stringValue = args[CurrIndex + 1];

      if (stringValue.Trim().Length == 0)
      {
        strError = string.Format(ParamValueInvalidStringMsg, ParamName);
        return -1;
      }

      return 0;
    }

    /// <summary>
    /// Standard method to convert command line parameter string into an enaum <seealso cref="ScaleTO"/> datatype.
    /// </summary>
    /// <param name="args"></param>
    /// <param name="CurrIndex"></param>
    /// <param name="ParamName"></param>
    /// <param name="scaleValue"></param>
    /// <param name="strError"></param>
    /// <returns></returns>
    public static int GetScaleValue(string[] args,
                                    int CurrIndex,
                                    string ParamName,
                                    out ScaleTO scaleValue,
                                    out string strError)
    {
      strError = string.Empty;
      scaleValue = ScaleTO.OriginalSize;

      if (args.Length <= (CurrIndex + 1))
      {
        strError = string.Format(ParamValueMissingMsg, ParamName);
        return -1;
      }

      string stringValue = args[CurrIndex + 1];

      if (stringValue.Trim().Length == 0)
      {
        strError = string.Format(ParamValueInvalidStringMsg, ParamName);
        return -1;
      }

      if (stringValue.ToUpper() == OptScaleModeOriginal.ToUpper())
      {
        scaleValue = ScaleTO.OriginalSize;
        return 0;
      }

      if (stringValue.ToUpper() == OptScaleModeTarget.ToUpper())
      {
        scaleValue = ScaleTO.TargetSize;
        return 0;
      }

      strError = string.Format(ParamValueInvalidSizeMsg, ParamName, stringValue, OptScaleModeOriginal, OptScaleModeTarget);
      return -1;
    }
    #endregion Methods
  }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
The Windows Presentation Foundation (WPF) and C# are among my favorites and so I developed Edi

and a few other projects on GitHub. I am normally an algorithms and structure type but WPF has such interesting UI sides that I cannot help myself but get into it.

https://de.linkedin.com/in/dirkbahle

Comments and Discussions