├── packages ├── Fody.1.28.3 │ ├── Tools │ │ ├── uninstall.ps1 │ │ └── install.ps1 │ ├── Fody.dll │ ├── Content │ │ └── FodyWeavers.xml │ ├── FodyCommon.dll │ ├── Mono.Cecil.dll │ ├── Fody.1.28.3.nupkg │ ├── FodyIsolated.dll │ ├── Mono.Cecil.Mdb.dll │ ├── Mono.Cecil.Pdb.dll │ ├── Mono.Cecil.Rocks.dll │ └── build │ │ └── Fody.targets ├── Costura.Fody.1.3.3.0 │ ├── Costura.Fody.dll │ ├── Tools │ │ ├── init.ps1 │ │ └── commands.psm1 │ ├── Costura.Fody.1.3.3.0.nupkg │ └── Content │ │ ├── FodyWeavers.xml.install.xdt │ │ └── FodyWeavers.xml.uninstall.xdt ├── NDesk.Options.0.2.1 │ ├── lib │ │ └── NDesk.Options.dll │ └── NDesk.Options.0.2.1.nupkg └── repositories.config ├── src └── Downsize │ ├── FodyWeavers.xml │ ├── packages.config │ ├── DirectoryHelper.cs │ ├── ImageExtensions.cs │ ├── App.config │ ├── Properties │ └── AssemblyInfo.cs │ ├── ImageHelper.cs │ ├── ImageScalerService.cs │ ├── ImageProcessor.cs │ ├── LoggingService.cs │ ├── Downsize.csproj │ ├── ImageConfigSection.cs │ └── Program.cs ├── Downsize.sln ├── .gitignore └── readme.md /packages/Fody.1.28.3/Tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | -------------------------------------------------------------------------------- /src/Downsize/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Fody.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Content/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Fody.1.28.3/FodyCommon.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/FodyCommon.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Mono.Cecil.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Mono.Cecil.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Fody.1.28.3.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Fody.1.28.3.nupkg -------------------------------------------------------------------------------- /packages/Fody.1.28.3/FodyIsolated.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/FodyIsolated.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Mono.Cecil.Mdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Mono.Cecil.Mdb.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Mono.Cecil.Pdb.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Mono.Cecil.Pdb.dll -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Mono.Cecil.Rocks.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Fody.1.28.3/Mono.Cecil.Rocks.dll -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Costura.Fody.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Costura.Fody.1.3.3.0/Costura.Fody.dll -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Tools/init.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | Import-Module (Join-Path $toolsPath commands.psm1) -------------------------------------------------------------------------------- /packages/NDesk.Options.0.2.1/lib/NDesk.Options.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/NDesk.Options.0.2.1/lib/NDesk.Options.dll -------------------------------------------------------------------------------- /packages/NDesk.Options.0.2.1/NDesk.Options.0.2.1.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/NDesk.Options.0.2.1/NDesk.Options.0.2.1.nupkg -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Costura.Fody.1.3.3.0.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChaseFlorell/Downsize/HEAD/packages/Costura.Fody.1.3.3.0/Costura.Fody.1.3.3.0.nupkg -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Content/FodyWeavers.xml.install.xdt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Content/FodyWeavers.xml.uninstall.xdt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Downsize/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/Fody.1.28.3/Tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | 4 | # Need to load MSBuild assembly if it's not loaded yet. 5 | Add-Type -AssemblyName 'Microsoft.Build, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' 6 | 7 | # Grab the loaded MSBuild project for the project 8 | $buildProject = [Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($project.FullName) | Select-Object -First 1 9 | 10 | $fodyPathProperty = $buildProject.GetProperty("FodyPath") 11 | 12 | # Dont do a null check since is seems evaluating the value causes powershit to have a conniption 13 | try 14 | { 15 | $buildProject.RemoveProperty($fodyPathProperty); 16 | } 17 | catch{} 18 | 19 | $project.Save() 20 | 21 | -------------------------------------------------------------------------------- /src/Downsize/DirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace Downsize 7 | { 8 | public class DirectoryHelper 9 | { 10 | public static void SetupPaths(Dictionary> expectedImages, bool dry) 11 | { 12 | foreach ( 13 | var path in 14 | expectedImages.Select(meta => Path.GetDirectoryName(meta.Value.Item1)).Where(path => path != null && !Directory.Exists(path))) 15 | { 16 | if (dry) 17 | { 18 | LoggingService.WriteVerbose("Would have created directory {0}", path); 19 | } 20 | else 21 | { 22 | Directory.CreateDirectory(path); 23 | LoggingService.WriteVerbose("Created directory {0}", path); 24 | } 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /src/Downsize/ImageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Drawing.Imaging; 3 | 4 | namespace Downsize 5 | { 6 | public static class ImageExtensions 7 | { 8 | /// 9 | /// Extension method to help save out images. If codec is null, it'll save as original format 10 | /// 11 | /// Image to save 12 | /// Path to save it to 13 | /// Codec to save as (can be null). 14 | /// 15 | public static void Save(this Image image, string path, ImageCodecInfo codec, bool dryRun) 16 | { 17 | if (dryRun) 18 | { 19 | LoggingService.WriteLine("Would have created {0}", path); 20 | } 21 | else 22 | { 23 | if (codec == null) 24 | { 25 | // Saves as original 26 | image.Save(path); 27 | } 28 | else 29 | { 30 | // Saves with customized codec 31 | image.Save(path, codec, null); 32 | } 33 | LoggingService.WriteLine("Created {0}", path); 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Downsize.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Downsize", "src\Downsize\Downsize.csproj", "{3AC668DE-B358-4B20-84C8-0B60361CC096}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root", "root", "{6D7498E4-A143-4184-AC4E-CDFB72993FCB}" 9 | ProjectSection(SolutionItems) = preProject 10 | readme.md = readme.md 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {3AC668DE-B358-4B20-84C8-0B60361CC096}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {3AC668DE-B358-4B20-84C8-0B60361CC096}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {3AC668DE-B358-4B20-84C8-0B60361CC096}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 22 | {3AC668DE-B358-4B20-84C8-0B60361CC096}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3AC668DE-B358-4B20-84C8-0B60361CC096}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/Downsize/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Downsize/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ImageScaler")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ImageScaler")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("745d6808-8804-4684-bdef-b22a9a94171e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.1.0.0")] 36 | [assembly: AssemblyFileVersion("0.1.0.0")] 37 | -------------------------------------------------------------------------------- /src/Downsize/ImageHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing.Imaging; 4 | using System.Linq; 5 | 6 | namespace Downsize 7 | { 8 | public static class ImageHelper 9 | { 10 | public static ImageFormat ParseImageFormat(string format) 11 | { 12 | switch (format.Replace(".", "")) 13 | { 14 | case "png": 15 | return ImageFormat.Png; 16 | case "jpg": 17 | return ImageFormat.Jpeg; 18 | case "jpeg": 19 | return ImageFormat.Jpeg; 20 | default: 21 | return null; 22 | } 23 | } 24 | 25 | public static Dictionary> BuildImageInfo(string rootDir, string newName, string extension) 26 | { 27 | var section = ImageConfigSection.GetConfigSection(); 28 | IEnumerable images; 29 | if (section != null) 30 | { 31 | images = from ImageConfigElement i in section.ImageCollection select i; 32 | } 33 | else 34 | { 35 | images = ImageConfigSection.DefaultCollection(); 36 | } 37 | var dict = new Dictionary>(); 38 | foreach (var image in images) 39 | { 40 | var path = string.Format(image.PathFormat, rootDir, newName) + extension; 41 | dict.Add(image.Key, new Tuple(path, image.Scale)); 42 | } 43 | 44 | return dict; 45 | } 46 | 47 | 48 | public static ImageCodecInfo GetImageCodecInfo(ImageFormat format) 49 | { 50 | if (format == null) 51 | { 52 | return null; 53 | } 54 | var codecs = ImageCodecInfo.GetImageEncoders(); 55 | return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Downsize/ImageScalerService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | 5 | namespace Downsize 6 | { 7 | public class ImageScalerService 8 | { 9 | public Image Scale(int newWidth, int newHeight, string stPhotoPath) 10 | { 11 | using (var imgPhoto = Image.FromFile(stPhotoPath)) 12 | { 13 | var sourceWidth = imgPhoto.Width; 14 | var sourceHeight = imgPhoto.Height; 15 | 16 | const int sourceX = 0; 17 | const int sourceY = 0; 18 | int destinationX = 0, destinationY = 0; 19 | 20 | float nPercent; 21 | var nPercentW = newWidth/(float) sourceWidth; 22 | var nPercentH = newHeight/(float) sourceHeight; 23 | if (nPercentH < nPercentW) 24 | { 25 | nPercent = nPercentH; 26 | destinationX = Convert.ToInt16((newWidth - 27 | sourceWidth*nPercent)/2); 28 | } 29 | else 30 | { 31 | nPercent = nPercentW; 32 | destinationY = Convert.ToInt16((newHeight - 33 | sourceHeight*nPercent)/2); 34 | } 35 | 36 | var destinationWidth = (int) (sourceWidth*nPercent); 37 | var destinationHeight = (int) (sourceHeight*nPercent); 38 | 39 | 40 | var bmPhoto = new Bitmap(newWidth, newHeight); 41 | bmPhoto.SetResolution(imgPhoto.HorizontalResolution, 42 | imgPhoto.VerticalResolution); 43 | 44 | using (var grPhoto = Graphics.FromImage(bmPhoto)) 45 | { 46 | grPhoto.SmoothingMode = SmoothingMode.HighQuality; 47 | grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic; 48 | grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality; 49 | grPhoto.DrawImage(imgPhoto, 50 | new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight), 51 | new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), 52 | GraphicsUnit.Pixel); 53 | } 54 | return bmPhoto; 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Downsize/ImageProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | 6 | namespace Downsize 7 | { 8 | public class ImageProcessor 9 | { 10 | private readonly bool _dry; 11 | private readonly string _here; 12 | private readonly ImageScalerService _scalerService; 13 | 14 | public ImageProcessor(bool dry) 15 | { 16 | _dry = dry; 17 | _scalerService = new ImageScalerService(); 18 | _here = Directory.GetCurrentDirectory(); 19 | } 20 | 21 | public void Process(FileInfo image, string outPath, string prefix, string suffix, ImageFormat format) 22 | { 23 | LoggingService.WriteLine("Processing {0}", image.Name); 24 | var outFileName = string.Format("{0}{1}{2}", prefix, Path.GetFileNameWithoutExtension(image.FullName), suffix); 25 | var rootDir = string.IsNullOrWhiteSpace(outPath) ? Path.GetDirectoryName(_here) : new DirectoryInfo(outPath).FullName; 26 | var extension = format == null ? image.Extension : string.Format(".{0}", format.ToString().ToLower()); 27 | LoggingService.WriteVerbose("New File Name: {0}{1}", outFileName, extension); 28 | 29 | 30 | int defaultHeight; 31 | int defaultWidth; 32 | 33 | using (var img = Image.FromFile(image.FullName)) 34 | { 35 | defaultHeight = img.Height; 36 | defaultWidth = img.Width; 37 | } 38 | 39 | LoggingService.WriteVerbose("Original Dimensions: {0}W by {1}H", defaultWidth, defaultHeight); 40 | 41 | var expectedImages = ImageHelper.BuildImageInfo(rootDir, outFileName, extension); 42 | 43 | DirectoryHelper.SetupPaths(expectedImages, _dry); 44 | 45 | var codec = ImageHelper.GetImageCodecInfo(format); 46 | 47 | foreach (var expectedImage in expectedImages) 48 | { 49 | var path = expectedImage.Value.Item1; 50 | var scale = expectedImage.Value.Item2; 51 | var scaledWidth = (int) Math.Ceiling(defaultWidth/scale); 52 | var scaledHeight = (int) Math.Ceiling(defaultHeight/scale); 53 | var scaledImage = _scalerService.Scale(scaledWidth, scaledHeight, image.FullName); 54 | scaledImage.Save(path, codec, _dry); 55 | 56 | LoggingService.WriteVerbose("New Dimensions for {0}: {1}W by {2}H", expectedImage.Key, scaledWidth, scaledHeight); 57 | } 58 | LoggingService.WriteLine(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | .vs/ 9 | 10 | # Databases 11 | *.sqlite3 12 | *.mdf 13 | *.ldf 14 | 15 | # Build results 16 | 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | [Bb]uild-[Aa]rtifacts/ 22 | 23 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 24 | # !packages/*/build/ 25 | 26 | # MSTest test Results 27 | [Tt]est[Rr]esult*/ 28 | [Bb]uild[Ll]og.* 29 | 30 | *_i.c 31 | *_p.c 32 | *.ilk 33 | *.meta 34 | *.obj 35 | *.pch 36 | *.pdb 37 | *.pgc 38 | *.pgd 39 | *.rsp 40 | *.sbr 41 | *.tlb 42 | *.tli 43 | *.tlh 44 | *.tmp 45 | *.tmp_proj 46 | *.log 47 | *.vspscc 48 | *.vssscc 49 | .builds 50 | *.pidb 51 | *.log 52 | *.scc 53 | 54 | # Visual C++ cache files 55 | ipch/ 56 | *.aps 57 | *.ncb 58 | *.opensdf 59 | *.sdf 60 | *.cachefile 61 | 62 | # Visual Studio profiler 63 | *.psess 64 | *.vsp 65 | *.vspx 66 | 67 | # Guidance Automation Toolkit 68 | *.gpState 69 | 70 | # ReSharper is a .NET coding add-in 71 | _ReSharper*/ 72 | *.[Rr]e[Ss]harper 73 | 74 | # TeamCity is a build add-in 75 | _TeamCity* 76 | 77 | # DotCover is a Code Coverage Tool 78 | *.dotCover 79 | 80 | # NCrunch 81 | *.ncrunch* 82 | .*crunch*.local.xml 83 | 84 | # Installshield output folder 85 | [Ee]xpress/ 86 | 87 | # DocProject is a documentation generator add-in 88 | DocProject/buildhelp/ 89 | DocProject/Help/*.HxT 90 | DocProject/Help/*.HxC 91 | DocProject/Help/*.hhc 92 | DocProject/Help/*.hhk 93 | DocProject/Help/*.hhp 94 | DocProject/Help/Html2 95 | DocProject/Help/html 96 | 97 | # Click-Once directory 98 | publish/ 99 | 100 | # Publish Web Output 101 | *.Publish.xml 102 | 103 | # NuGet Packages Directory 104 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 105 | # packages/ 106 | 107 | # Windows Azure Build Output 108 | csx 109 | *.build.csdef 110 | 111 | # Windows Store app package directory 112 | AppPackages/ 113 | 114 | # Others 115 | sql/ 116 | *.Cache 117 | ClientBin/ 118 | [Ss]tyle[Cc]op.* 119 | ~$* 120 | *~ 121 | *.dbmdl 122 | *.[Pp]ublish.xml 123 | *.pfx 124 | *.publishsettings 125 | 126 | # RIA/Silverlight projects 127 | Generated_Code/ 128 | 129 | # Backup & report files from converting an old project file to a newer 130 | # Visual Studio version. Backup files are not needed, because we have git ;-) 131 | _UpgradeReport_Files/ 132 | Backup*/ 133 | UpgradeLog*.XML 134 | UpgradeLog*.htm 135 | 136 | # SQL Server files 137 | App_Data/*.mdf 138 | App_Data/*.ldf 139 | 140 | # ========================= 141 | # Windows detritus 142 | # ========================= 143 | 144 | # Windows image file caches 145 | Thumbs.db 146 | ehthumbs.db 147 | 148 | # Folder config file 149 | Desktop.ini 150 | 151 | # Recycle Bin used on file shares 152 | $RECYCLE.BIN/ 153 | 154 | # Mac crap 155 | .DS_Store 156 | 157 | # Misc Junk 158 | .vs/ -------------------------------------------------------------------------------- /src/Downsize/LoggingService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace Downsize 5 | { 6 | public static class LoggingService 7 | { 8 | private static bool _logToFile; 9 | private static bool _verbose; 10 | private static string _logFilePath; 11 | private static bool _quiet; 12 | 13 | public static void Init(string logDir, bool logToFile, bool verbose, bool quiet) 14 | { 15 | _logToFile = logToFile; 16 | _verbose = verbose; 17 | _quiet = quiet; 18 | 19 | if (!logToFile) return; 20 | 21 | var timeStamp = DateTime.Now.ToString("yyMMdd"); 22 | if (!Directory.Exists(logDir)) 23 | { 24 | Directory.CreateDirectory(logDir); 25 | } 26 | _logFilePath = string.Format("{0}\\Log-{1}.log", logDir, timeStamp); 27 | } 28 | 29 | public static void WriteLine(string message = "") 30 | { 31 | if (!_quiet) 32 | { 33 | Console.WriteLine(message); 34 | } 35 | WriteLog(string.Format("NORMAL: \t{0}", message)); 36 | } 37 | 38 | public static void WriteError(string message = "") 39 | { 40 | Console.ForegroundColor = ConsoleColor.Red; 41 | if (!_quiet) 42 | { 43 | Console.WriteLine(message); 44 | } 45 | Console.ResetColor(); 46 | WriteLog(string.Format("ERROR: \t{0}", message)); 47 | } 48 | 49 | public static void WriteVerbose(string message = "") 50 | { 51 | if (!_verbose) return; 52 | Console.ForegroundColor = ConsoleColor.Yellow; 53 | if (!_quiet) 54 | { 55 | Console.WriteLine(message); 56 | } 57 | Console.ResetColor(); 58 | WriteLog(string.Format("VERBOSE: \t{0}", message)); 59 | } 60 | 61 | public static void WriteLine(string messageFormat, params object[] arg) 62 | { 63 | var message = string.Format(messageFormat, arg); 64 | WriteLine(message); 65 | } 66 | 67 | public static void WriteError(string messageFormat, params object[] arg) 68 | { 69 | var message = string.Format(messageFormat, arg); 70 | WriteError(message); 71 | } 72 | 73 | 74 | public static void WriteVerbose(string messageFormat, params object[] arg) 75 | { 76 | var message = string.Format(messageFormat, arg); 77 | WriteVerbose(message); 78 | } 79 | 80 | private static void WriteLog(string message) 81 | { 82 | if (!_logToFile || string.IsNullOrWhiteSpace(message) || message.Trim().ToLower() == "normal:") return; 83 | 84 | using (var file = File.Open(_logFilePath, FileMode.Append)) 85 | using (var writer = new StreamWriter(file)) 86 | { 87 | writer.WriteLine("{0}\t{1}", DateTime.Now, message); 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /packages/Fody.1.28.3/build/Fody.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | $(NCrunchOriginalSolutionDir) 7 | 8 | 9 | 10 | 11 | $(SolutionDir) 12 | 13 | 14 | 15 | 16 | $(MSBuildProjectDirectory)..\..\..\ 17 | 18 | 19 | 20 | 21 | 22 | 23 | $(KeyOriginatorFile) 24 | 25 | 26 | 27 | 28 | $(AssemblyOriginatorKeyFile) 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | $(ProjectDir)$(IntermediateOutputPath) 39 | $(SignAssembly) 40 | $(MSBuildThisFileDirectory)..\ 41 | 42 | 45 | 49 | 50 | 61 | 62 | 63 | 64 | 67 | 71 | 72 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ###Downsize### 2 | 3 | Downsize is a simple helper tool to help you manage the images (jpg and png) in your cross-platform applications. 4 | 5 | ###Rational### 6 | 7 | Whenever you create an application, you inevitably have have images as a part of your solution. The problem comes in the fact that there is so many screen resolutions for you to support, that managing the image assets can become very frustrating. That's where `Downsize` comes into play. 8 | 9 | ###What does it do?### 10 | 11 | Simply put, Downsize takes your image and creates all of the required output image versions for both Android and iOS (Windows support coming). 12 | 13 | ###How do I use it?### 14 | 15 | The easiest way is to simply drag and drop your image resource over top of the `downsize.exe`. It will automatically generate the required images for you. 16 | **BUT there's a catch**. Downsize will ALWAYS assume that you've given it the largest version of your file. That means that the original image is set to the iOS `@3x` or the Android `xxhdpi` versions. Downsize will then downsize your images to `@2x`, `@1x`, `xhdpi`, `hdpi`, `mdpi`, and `ldpi`. It will also appropriately name your original file and save it for `@3x` and `xxhdpi`. 17 | 18 | ###Example### 19 | 20 | Given that you have the need for an image on your screen that is 40x40. The first thing you should do is calculate the xxhdpi/@3x resolution for that image. In this case it will be 120x120. So go ahead and create your image asset at that resolution. Once you've saved it out, simply drag-and-drop that image over top of the `Downsize.exe`, and watch as a new Android and iOS folder are created and all of the resolutions generated. 21 | 22 | Need more power? You can pass additional variables at the command line as needed. Simply type `downsize.exe /?` to see what they are. 23 | 24 | ###More..### 25 | 26 | Downsize can be used by itself, or with the additional config file. If you wish to customize the output format of your images, simply edit the config file and have it accompany your `Downsize.exe` 27 | 28 | ```xml 29 | 30 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | ###Contributing### 51 | 52 | This is my first stab at this tool, and it might be missing feature X, or platform Y. If you want something that it can't currently provide, I love pull requests. If it's a bigger change, a fresh Issue goes along ways before PR. 53 | 54 | ###License### 55 | 56 | [Microsoft Public License (Ms-PL)](http://www.microsoft.com/en-us/openness/licenses.aspx#MPL) -------------------------------------------------------------------------------- /src/Downsize/Downsize.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3AC668DE-B358-4B20-84C8-0B60361CC096} 8 | Exe 9 | Properties 10 | Downsize 11 | Downsize 12 | v4.5 13 | 512 14 | 62627cda 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | ..\..\packages\NDesk.Options.0.2.1\lib\NDesk.Options.dll 56 | True 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/Downsize/ImageConfigSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Configuration; 3 | 4 | namespace Downsize 5 | { 6 | public class ImageConfigSection : ConfigurationSection 7 | { 8 | [ConfigurationProperty("ImageCollection")] 9 | public ImageConfigElementCollection ImageCollection 10 | { 11 | get { return this["ImageCollection"] as ImageConfigElementCollection; } 12 | } 13 | 14 | public static ImageConfigSection GetConfigSection() 15 | { 16 | return ConfigurationManager.GetSection("ImageConfigSection") as ImageConfigSection; 17 | } 18 | 19 | public static IEnumerable DefaultCollection() 20 | { 21 | return new List 22 | { 23 | new ImageConfigElement("ldpi",@"{0}\Android\drawable-ldpi\{1}",4), 24 | new ImageConfigElement("mdpi",@"{0}\Android\drawable-mdpi\{1}",3), 25 | new ImageConfigElement("hdpi",@"{0}\Android\drawable-hdpi\{1}",2), 26 | new ImageConfigElement("xhdpi",@"{0}\Android\drawable-xhdpi\{1}",1.5), 27 | new ImageConfigElement("xxhdpi",@"{0}\Android\drawable-xxhdpi\{1}",1), 28 | new ImageConfigElement("iOS@1x",@"{0}\iOS\{1}",3), 29 | new ImageConfigElement("iOS@2x",@"{0}\iOS\{1}@2x",1.5), 30 | new ImageConfigElement("iOS@3x",@"{0}\iOS\{1}@3x",1) 31 | }; 32 | } 33 | } 34 | 35 | public class ImageConfigElementCollection : ConfigurationElementCollection 36 | { 37 | public ImageConfigElement this[int index] 38 | { 39 | get { return BaseGet(index) as ImageConfigElement; } 40 | } 41 | 42 | protected override ConfigurationElement CreateNewElement() 43 | { 44 | return new ImageConfigElement(); 45 | } 46 | 47 | protected override object GetElementKey(ConfigurationElement element) 48 | { 49 | return ((ImageConfigElement) element).Key; 50 | } 51 | } 52 | 53 | public class ImageConfigElement : ConfigurationElement 54 | { 55 | private readonly string _key; 56 | private readonly string _pathFormat; 57 | private readonly double? _scale; 58 | 59 | public ImageConfigElement(string key, string pathFormat, double scale) 60 | { 61 | _key = key; 62 | _pathFormat = pathFormat; 63 | _scale = scale; 64 | } 65 | 66 | public ImageConfigElement() { } 67 | 68 | [ConfigurationProperty("key", IsRequired = true)] 69 | public string Key 70 | { 71 | get 72 | { 73 | if (string.IsNullOrWhiteSpace(_key)) 74 | { 75 | return this["key"] as string; 76 | } 77 | return _key; 78 | } 79 | } 80 | 81 | [ConfigurationProperty("pathFormat", IsRequired = true)] 82 | public string PathFormat 83 | { 84 | get 85 | { 86 | if (string.IsNullOrWhiteSpace(_pathFormat)) 87 | { 88 | return this["pathFormat"] as string; 89 | } 90 | return _pathFormat; 91 | } 92 | } 93 | 94 | [ConfigurationProperty("scale", IsRequired = true)] 95 | public double Scale 96 | { 97 | get 98 | { 99 | if (_scale == null) 100 | { 101 | double scale; 102 | double.TryParse(this["scale"].ToString(), out scale); 103 | return scale; 104 | } 105 | return (double) _scale; 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /packages/Costura.Fody.1.3.3.0/Tools/commands.psm1: -------------------------------------------------------------------------------- 1 | function Resolve-ProjectName { 2 | param( 3 | [parameter(ValueFromPipelineByPropertyName = $true)] 4 | [string[]]$ProjectName 5 | ) 6 | 7 | if($ProjectName) { 8 | $projects = Get-Project $ProjectName 9 | } 10 | else { 11 | # All projects by default 12 | $projects = Get-Project 13 | } 14 | 15 | $projects 16 | } 17 | 18 | function Get-MSBuildProject { 19 | param( 20 | [parameter(ValueFromPipelineByPropertyName = $true)] 21 | [string[]]$ProjectName 22 | ) 23 | Process { 24 | (Resolve-ProjectName $ProjectName) | % { 25 | $path = $_.FullName 26 | @([Microsoft.Build.Evaluation.ProjectCollection]::GlobalProjectCollection.GetLoadedProjects($path))[0] 27 | } 28 | } 29 | } 30 | 31 | function Install-CleanReferencesTarget() 32 | { 33 | $buildProject = Get-MSBuildProject 34 | 35 | if ($buildProject.Xml.Targets | Where-Object { "CleanReferenceCopyLocalPaths" -contains $_.Name }) 36 | { 37 | Write-Host "Target CleanReferenceCopyLocalPaths already exists." -foregroundcolor Black -backgroundcolor Yellow 38 | 39 | return 40 | } 41 | 42 | $usingTask = $buildProject.Xml.AddUsingTask("CosturaCleanup", "`$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll", "") 43 | $usingTask.TaskFactory = "CodeTaskFactory" 44 | $parameterGroup = $usingTask.AddParameterGroup() 45 | $configParam = $parameterGroup.AddParameter("Config", "false", "true", "Microsoft.Build.Framework.ITaskItem") 46 | $filesParam = $parameterGroup.AddParameter("Files", "false", "true", "Microsoft.Build.Framework.ITaskItem[]") 47 | $taskBody = $usingTask.AddUsingTaskBody("true", " 48 | 49 | 50 | 51 | 52 | 53 | (); 59 | var attribute = config.Attribute(`"ExcludeAssemblies`"); 60 | if (attribute != null) 61 | foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty)) 62 | excludedAssemblies.Add(item); 63 | var element = config.Element(`"ExcludeAssemblies`"); 64 | if (element != null) 65 | foreach (var item in element.Value.Split(new[] { `"\r\n`", `"\n`" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty)) 66 | excludedAssemblies.Add(item); 67 | 68 | var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase)); 69 | 70 | foreach (var item in filesToCleanup) 71 | File.Delete(item); 72 | ]]> 73 | ") 74 | 75 | $target = $buildProject.Xml.AddTarget("CleanReferenceCopyLocalPaths") 76 | $target.AfterTargets = "AfterBuild;NonWinFodyTarget" 77 | $deleteTask = $target.AddTask("CosturaCleanup") 78 | $deleteTask.SetParameter("Config", "FodyWeavers.xml") 79 | $deleteTask.SetParameter("Files", "@(ReferenceCopyLocalPaths->`'`$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)`')") 80 | 81 | $buildProject.Save() 82 | 83 | Write-Host "Added target CleanReferenceCopyLocalPaths." 84 | } 85 | 86 | function Uninstall-CleanReferencesTarget() 87 | { 88 | $buildProject = Get-MSBuildProject 89 | 90 | $target = $buildProject.Xml.Targets | Where-Object { "CleanReferenceCopyLocalPaths" -contains $_.Name } 91 | $usingTask = $buildProject.Xml.UsingTasks | Where-Object { "CosturaCleanup" -contains $_.TaskName } 92 | 93 | if (!$target) 94 | { 95 | Write-Host "Target CleanReferenceCopyLocalPaths did not exist." -foregroundcolor Black -backgroundcolor Yellow 96 | 97 | return 98 | } 99 | 100 | $buildProject.Xml.RemoveChild($usingTask) 101 | $buildProject.Xml.RemoveChild($target) 102 | 103 | $buildProject.Save() 104 | 105 | Write-Host "Removed target CleanReferenceCopyLocalPaths." 106 | } -------------------------------------------------------------------------------- /src/Downsize/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing.Imaging; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using NDesk.Options; 8 | 9 | namespace Downsize 10 | { 11 | internal class Program 12 | { 13 | private static string _appName; 14 | public static string AppName 15 | { 16 | get { return _appName ?? (_appName = Assembly.GetExecutingAssembly().GetName().Name); } 17 | } 18 | 19 | private static void Main(string[] args) 20 | { 21 | var helpRequested = false; 22 | var log = false; 23 | var verbose = false; 24 | var quiet = false; 25 | var images = new List(); 26 | var outPath = AppDomain.CurrentDomain.BaseDirectory; 27 | var prefix = string.Empty; 28 | var suffix = string.Empty; 29 | ImageFormat format = null; 30 | var dry = false; 31 | 32 | var options = new OptionSet 33 | { 34 | { 35 | "i|img|image=", "Image to resize \nnote: this MUST be your largest version (xxhdpi/@3x)", 36 | v => images.Add(new FileInfo(v)) 37 | }, 38 | { 39 | "f|format=", "Output format (png, jpg)", 40 | v => format = ImageHelper.ParseImageFormat(v) 41 | }, 42 | { 43 | "o|out|outpath=", "Path to save out the image\ndefaults to current directory of downsize.exe", 44 | v => outPath = v 45 | }, 46 | { 47 | "pre|prefix=", "Prefix to prepend to the image name", 48 | v => prefix = v 49 | }, 50 | { 51 | "suf|suffix=", "Suffix to append to the image name", 52 | v => suffix = v 53 | }, 54 | { 55 | "l|log", "write a log file to the output directory", 56 | v => log = v != null 57 | }, 58 | { 59 | "s|q|silent|quiet", "Don't write out to console", 60 | v => quiet = v != null 61 | }, 62 | { 63 | "d|dry|dryrun", "Summary of what would happen", 64 | v => dry = v != null 65 | }, 66 | { 67 | "v|verbose", "Write verbose information", 68 | v => verbose = v != null 69 | }, 70 | { 71 | "?|h|help", "show help message and exit", 72 | v => helpRequested = v != null 73 | } 74 | }; 75 | 76 | try 77 | { 78 | var p = options.Parse(args); 79 | images.AddRange(p.Select(unParsed => new FileInfo(unParsed))); 80 | } 81 | catch (OptionException e) 82 | { 83 | Console.Write("{0}: ", AppName); 84 | Console.WriteLine(e.Message); 85 | Console.WriteLine("Try `{0} --help' for more information.", AppName); 86 | Console.WriteLine(); 87 | return; 88 | } 89 | 90 | if (helpRequested) 91 | { 92 | ShowHelp(options); 93 | return; 94 | } 95 | 96 | LoggingService.Init(outPath, log, verbose, quiet); 97 | LoggingService.WriteLine("Begin Processing Images!"); 98 | LoggingService.WriteVerbose("Writing files to {0}", outPath); 99 | 100 | var processor = new ImageProcessor(dry); 101 | foreach (var image in images) 102 | { 103 | try 104 | { 105 | processor.Process(image, outPath, prefix, suffix, format); 106 | } 107 | catch (Exception ex) 108 | { 109 | LoggingService.WriteError("An error occurred while processing {0}", image); 110 | LoggingService.WriteError(ex.Message); 111 | } 112 | } 113 | LoggingService.WriteLine("Finished Processing Images!"); 114 | } 115 | 116 | private static void ShowHelp(OptionSet p) 117 | { 118 | Console.WriteLine(); 119 | Console.WriteLine("Help:\n"); 120 | Console.WriteLine("Usage: {0} [OPTIONS]", AppName); 121 | Console.WriteLine("Options:"); 122 | p.WriteOptionDescriptions(Console.Out); 123 | } 124 | } 125 | } --------------------------------------------------------------------------------