From b84f28b007ae7e357661ee8708809848917edace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Fri, 21 Feb 2020 19:16:14 +0100 Subject: [PATCH] Added Sample console application (#676) * Added SvgConsole application * Added input directory support * Added multiple output files support * Added Log and Error methods * Updated README.md --- Samples/SvgConsole/Program.cs | 205 +++++++++++++++++++++++++++ Samples/SvgConsole/README.md | 76 ++++++++++ Samples/SvgConsole/SvgConsole.csproj | 27 ++++ Source/Svg.sln | 15 ++ appveyor.yml | 1 + doc/Samples.md | 4 + 6 files changed, 328 insertions(+) create mode 100644 Samples/SvgConsole/Program.cs create mode 100644 Samples/SvgConsole/README.md create mode 100644 Samples/SvgConsole/SvgConsole.csproj diff --git a/Samples/SvgConsole/Program.cs b/Samples/SvgConsole/Program.cs new file mode 100644 index 0000000..4d54127 --- /dev/null +++ b/Samples/SvgConsole/Program.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Invocation; +using System.IO; +using System.Threading.Tasks; +using Svg; + +namespace SvgConsole +{ + class Settings + { + public FileInfo[] InputFiles { get; set; } + public DirectoryInfo InputDirectory { get; set; } + public FileInfo[] OutputFiles { get; set; } + public DirectoryInfo OutputDirectory { get; set; } + public float? Width { get; set; } + public float? Height { get; set; } + } + + class Program + { + static void Log(string message) + { + Console.WriteLine(message); + } + + static void Error(Exception ex) + { + Log($"{ex.Message}"); + Log($"{ex.StackTrace}"); + if (ex.InnerException != null) + { + Error(ex.InnerException); + } + } + + static void GetFiles(DirectoryInfo directory, string pattern, List paths) + { + var files = Directory.EnumerateFiles(directory.FullName, pattern); + if (files != null) + { + foreach (var path in files) + { + paths.Add(new FileInfo(path)); + } + } + } + + static void Save(FileInfo inputPath, string outputPath, float? width, float? height) + { + var svgDocument = SvgDocument.Open(inputPath.FullName); + + if (svgDocument == null) + { + Log($"Error: Failed to load input file: {inputPath.FullName}"); + return; + } + + if (width.HasValue) + { + svgDocument.Width = width.Value; + } + + if (height.HasValue) + { + svgDocument.Height = height.Value; + } + + using (var bitmap = svgDocument.Draw()) + { + bitmap.Save(outputPath); + } + } + + static void Run(Settings settings) + { + var paths = new List(); + + if (settings.InputFiles != null) + { + foreach (var file in settings.InputFiles) + { + paths.Add(file); + } + } + + if (settings.InputDirectory != null) + { + var directory = settings.InputDirectory; + GetFiles(directory, "*.svg", paths); + GetFiles(directory, "*.svgz", paths); + } + + if (settings.OutputDirectory != null && !string.IsNullOrEmpty(settings.OutputDirectory.FullName)) + { + if (!Directory.Exists(settings.OutputDirectory.FullName)) + { + Directory.CreateDirectory(settings.OutputDirectory.FullName); + } + } + + if (settings.OutputFiles != null) + { + if (paths.Count > 0 && paths.Count != settings.OutputFiles.Length) + { + Log($"Error: The number of the output files must match the number of the input files."); + return; + } + } + + for (int i = 0; i < paths.Count; i++) + { + var inputPath = paths[i]; + var outputFile = settings.OutputFiles != null ? settings.OutputFiles[i] : null; + try + { + var outputPath = string.Empty; + + if (outputFile != null) + { + outputPath = outputFile.FullName; + } + else + { + var inputExtension = inputPath.Extension; + outputPath = Path.ChangeExtension(inputPath.FullName, ".png"); + if (settings.OutputDirectory != null && !string.IsNullOrEmpty(settings.OutputDirectory.FullName)) + { + outputPath = Path.Combine(settings.OutputDirectory.FullName, Path.GetFileName(outputPath)); + } + } + + Directory.SetCurrentDirectory(Path.GetDirectoryName(inputPath.FullName)); + + Save(inputPath, outputPath, settings.Width, settings.Height); + } + catch (Exception ex) + { + Log($"Error: {inputPath.FullName}"); + Error(ex); + } + } + } + + static async Task Main(string[] args) + { + var optionInputFiles = new Option(new[] { "--inputFiles", "-f" }, "The relative or absolute path to the input files") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var optionInputDirectory = new Option(new[] { "--inputDirectory", "-d" }, "The relative or absolute path to the input directory") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var optionOutputDirectory = new Option(new[] { "--outputDirectory", "-o" }, "The relative or absolute path to the output directory") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var optionOutputFiles = new Option(new[] { "--outputFiles" }, "The relative or absolute path to the output files") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var optionWidth = new Option(new[] { "--width" }, "The output image width override") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var optionHeight = new Option(new[] { "--height" }, "The output image height override") + { + Argument = new Argument(getDefaultValue: () => null) + }; + + var rootCommand = new RootCommand() + { + Description = "Converts svg files to encoded png images." + }; + + rootCommand.AddOption(optionInputFiles); + rootCommand.AddOption(optionInputDirectory); + rootCommand.AddOption(optionOutputDirectory); + rootCommand.AddOption(optionOutputFiles); + rootCommand.AddOption(optionWidth); + rootCommand.AddOption(optionHeight); + + rootCommand.Handler = CommandHandler.Create((Settings settings) => + { + try + { + Run(settings); + } + catch (Exception ex) + { + Error(ex); + } + }); + + return await rootCommand.InvokeAsync(args); + } + } +} diff --git a/Samples/SvgConsole/README.md b/Samples/SvgConsole/README.md new file mode 100644 index 0000000..10d322e --- /dev/null +++ b/Samples/SvgConsole/README.md @@ -0,0 +1,76 @@ +# SvgConsole + +## .NET Core + +Install latest [.NET Core SDK](https://dotnet.microsoft.com/download). + +## Publish + +### Windows + +``` +cd Samples/SvgConsole +dotnet publish -f netcoreapp2.2 -c Release -r win-x64 -o SvgConsole-win-x64-netcoreapp2.2 +cd SvgConsole-win-x64-netcoreapp2.2 +``` + +### Linux + +``` +cd Samples/SvgConsole +dotnet publish -f netcoreapp2.2 -c Release -r linux-x64 -o SvgConsole-linux-x64-netcoreapp2.2 +cd SvgConsole-linux-x64-netcoreapp2.2 +``` + +### macOS + +``` +cd Samples/SvgConsole +dotnet publish -f netcoreapp2.2 -c Release -r osx-x64 -o SvgConsole-osx-x64-netcoreapp2.2 +cd SvgConsole-osx-x64-netcoreapp2.2 +``` + +### Other + +* [.NET Core RID Catalog](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog) +* [dotnet publish](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish) + +## Usage + +``` +SvgConsole: + Converts svg files to encoded png images. + +Usage: + SvgConsole [options] + +Options: + -f, --inputFiles The relative or absolute path to the input files + -d, --inputDirectory The relative or absolute path to the input directory + -o, --outputDirectory The relative or absolute path to the output directory + --outputFiles The relative or absolute path to the output files + --width The output image width override + --height The output image height override + --version Show version information + -?, -h, --help Show help and usage information +``` + +``` +./SvgConsole -f ~/svg/Example.svg +``` + +``` +./SvgConsole -f ~/svg/Example.svg --outputFiles ~/png/Example.png +``` + +``` +./SvgConsole -f ~/svg/Example.svg -o ~/png +``` + +``` +./SvgConsole -d ~/svg/ +``` + +``` +./SvgConsole -d ~/svg -o ~/png +``` diff --git a/Samples/SvgConsole/SvgConsole.csproj b/Samples/SvgConsole/SvgConsole.csproj new file mode 100644 index 0000000..241bb98 --- /dev/null +++ b/Samples/SvgConsole/SvgConsole.csproj @@ -0,0 +1,27 @@ + + + + Exe + netcoreapp2.2 + False + True + True + SvgConsole + 7.3 + + + + True + True + + + + + + + + + + + + diff --git a/Source/Svg.sln b/Source/Svg.sln index 382c840..7905f85 100644 --- a/Source/Svg.sln +++ b/Source/Svg.sln @@ -29,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XMLOutputTester", "..\Sampl EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{2EC3F3A0-F097-43EF-A603-9B82E3061469}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SvgConsole", "..\Samples\SvgConsole\SvgConsole.csproj", "{9379360C-CB0B-4035-AE8F-8863A420FDCF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -111,6 +113,18 @@ Global {8CEEB917-63E2-4AE7-B0D1-50A840050975}.Release|Mixed Platforms.Build.0 = Release|x86 {8CEEB917-63E2-4AE7-B0D1-50A840050975}.Release|x86.ActiveCfg = Release|x86 {8CEEB917-63E2-4AE7-B0D1-50A840050975}.Release|x86.Build.0 = Release|x86 + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|x86.ActiveCfg = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Debug|x86.Build.0 = Debug|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|Any CPU.Build.0 = Release|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|x86.ActiveCfg = Release|Any CPU + {9379360C-CB0B-4035-AE8F-8863A420FDCF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -122,6 +136,7 @@ Global {9782B15C-D0BA-4A4E-9A03-F97082AF9256} = {038E2E7B-BC03-4DA7-AA5F-CA8BD95BD0F2} {F34CF345-E7EF-4354-B49A-AFE7A78442A7} = {038E2E7B-BC03-4DA7-AA5F-CA8BD95BD0F2} {8CEEB917-63E2-4AE7-B0D1-50A840050975} = {038E2E7B-BC03-4DA7-AA5F-CA8BD95BD0F2} + {9379360C-CB0B-4035-AE8F-8863A420FDCF} = {038E2E7B-BC03-4DA7-AA5F-CA8BD95BD0F2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {5096EEB3-8F41-44B5-BCF9-58743A59AB21} diff --git a/appveyor.yml b/appveyor.yml index 14c7c47..755ca43 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,6 +8,7 @@ environment: before_build: - ps: nuget restore Source\Svg.csproj +- ps: nuget restore Samples\SvgConsole\SvgConsole.csproj - ps: nuget restore Tests\Svg.UnitTests\Svg.UnitTests.csproj - ps: nuget install NUnit.ConsoleRunner -Version 3.10.0 -OutputDirectory tools - ps: | diff --git a/doc/Samples.md b/doc/Samples.md index 8d47930..c1f5deb 100644 --- a/doc/Samples.md +++ b/doc/Samples.md @@ -31,6 +31,10 @@ Entities Another small command line application that loads an example file that references entities not present in the file, and provides these entities with matching styles dynamically in the `SvgDocument.Open` call. +SvgConsole +---------- +This is a simple command-line application to convert one or many input SVG files to PNG images. It shows how to open a SVG document and create bitmap, and how to save resulting bitmap to a PNG file. + --- As you can see, there are currently very few code samples. We encourage you to add your own sample code in pull requests, or provide code snippets that can be made into samples.