mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: e865fcd09f0aa9249ba9f1116fcf027bd3e48e14 Former-commit-id: 530db416ac1747fb424c93ab286efb673af738c7af/merge-core
18 changed files with 495 additions and 5 deletions
@ -0,0 +1,36 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="ImageProcessingModule.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// PostProcesses any image requests within the web application.
|
|||
// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
using System.Web; |
|||
|
|||
[assembly: PreApplicationStartMethod(typeof(ImageProcessor.Web.PostProcessor.ApplicationEvents), "Start")] |
|||
namespace ImageProcessor.Web.PostProcessor |
|||
{ |
|||
using ImageProcessor.Web.Helpers; |
|||
using ImageProcessor.Web.HttpModules; |
|||
|
|||
/// <summary>
|
|||
/// PostProcesses any image requests within the web application.
|
|||
/// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
/// </summary>
|
|||
public static class ApplicationEvents |
|||
{ |
|||
public static void Start() |
|||
{ |
|||
ImageProcessingModule.OnPostProcessing += PostProcess; |
|||
} |
|||
|
|||
private static async void PostProcess(object sender, PostProcessingEventArgs e) |
|||
{ |
|||
await PostProcessor.PostProcessImage(e.CachedImagePath); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProjectGuid>{55D08737-7D7E-4995-8892-BD9F944329E6}</ProjectGuid> |
|||
<OutputType>Library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>ImageProcessor.Web.PostProcessor</RootNamespace> |
|||
<AssemblyName>ImageProcessor.Web.PostProcessor</AssemblyName> |
|||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> |
|||
<FileAlignment>512</FileAlignment> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Web" /> |
|||
<Reference Include="System.Xml.Linq" /> |
|||
<Reference Include="System.Data.DataSetExtensions" /> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="System.Data" /> |
|||
<Reference Include="System.Xml" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="ApplicationEvents.cs" /> |
|||
<Compile Include="PostProcessingResultEventArgs.cs" /> |
|||
<Compile Include="PostProcessorBootstrapper.cs" /> |
|||
<Compile Include="PostProcessor.cs" /> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\ImageProcessor.Web\ImageProcessor.Web.csproj"> |
|||
<Project>{D011A778-59C8-4BFA-A770-C350216BF161}</Project> |
|||
<Name>ImageProcessor.Web</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\ImageProcessor\ImageProcessor.csproj"> |
|||
<Project>{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}</Project> |
|||
<Name>ImageProcessor</Name> |
|||
</ProjectReference> |
|||
</ItemGroup> |
|||
<ItemGroup /> |
|||
<ItemGroup> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x86\png.cmd" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x64\gifsicle.exe" /> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x86\gifsicle.exe" /> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x86\jpegtran.exe" /> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x86\optipng.exe" /> |
|||
<EmbeddedResource Include="Resources\Unmanaged\x86\pngout.exe" /> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
|||
Other similar extension points exist, see Microsoft.Common.targets. |
|||
<Target Name="BeforeBuild"> |
|||
</Target> |
|||
<Target Name="AfterBuild"> |
|||
</Target> |
|||
--> |
|||
</Project> |
|||
@ -0,0 +1,103 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="PostProcessingResultEventArgs.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The post processing result event arguments.
|
|||
// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.PostProcessor |
|||
{ |
|||
using System; |
|||
using System.IO; |
|||
using System.Text; |
|||
|
|||
/// <summary>
|
|||
/// The post processing result event arguments.
|
|||
/// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
/// </summary>
|
|||
public class PostProcessingResultEventArgs : EventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PostProcessingResultEventArgs"/> class.
|
|||
/// </summary>
|
|||
/// <param name="originalFileName">The original file name.</param>
|
|||
/// <param name="resultFileName">The result file name.</param>
|
|||
public PostProcessingResultEventArgs(string originalFileName, string resultFileName) |
|||
{ |
|||
FileInfo original = new FileInfo(originalFileName); |
|||
FileInfo result = new FileInfo(resultFileName); |
|||
|
|||
if (original.Exists) |
|||
{ |
|||
this.OriginalFileName = original.FullName; |
|||
this.OriginalFileSize = original.Length; |
|||
} |
|||
|
|||
if (result.Exists) |
|||
{ |
|||
this.ResultFileName = result.FullName; |
|||
this.ResultFileSize = result.Length; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the original file size in bytes.
|
|||
/// </summary>
|
|||
public long OriginalFileSize { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the original file name.
|
|||
/// </summary>
|
|||
public string OriginalFileName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the result file size in bytes.
|
|||
/// </summary>
|
|||
public long ResultFileSize { get; set; } |
|||
|
|||
/// <summary>
|
|||
///
|
|||
/// </summary>
|
|||
public string ResultFileName { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the difference in filesize in bytes.
|
|||
/// </summary>
|
|||
public long Saving |
|||
{ |
|||
get { return this.OriginalFileSize - this.ResultFileSize; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the difference in filesize as a percentage.
|
|||
/// </summary>
|
|||
public double Percent |
|||
{ |
|||
get |
|||
{ |
|||
return Math.Round(100 - this.ResultFileSize / (double)this.OriginalFileSize * 100, 1); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a string that represents the current object.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// A string that represents the current object.
|
|||
/// </returns>
|
|||
public override string ToString() |
|||
{ |
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
stringBuilder.AppendLine("Optimized " + Path.GetFileName(this.OriginalFileName)); |
|||
stringBuilder.AppendLine("Before: " + this.OriginalFileSize + " bytes"); |
|||
stringBuilder.AppendLine("After: " + this.ResultFileSize + " bytes"); |
|||
stringBuilder.AppendLine("Saving: " + this.Saving + " bytes / " + Percent + "%"); |
|||
|
|||
return stringBuilder.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="PostProcessor.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The image postprocessor.
|
|||
// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.PostProcessor |
|||
{ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using System.Globalization; |
|||
using System.IO; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// The image postprocessor.
|
|||
/// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
/// </summary>
|
|||
internal static class PostProcessor |
|||
{ |
|||
public async static Task PostProcessImage(string sourceFile) |
|||
{ |
|||
string targetFile = Path.GetTempFileName(); |
|||
PostProcessingResultEventArgs result = await RunProcessAsync(sourceFile, targetFile); |
|||
|
|||
if (result != null && result.Saving > 0 && result.ResultFileSize > 0) |
|||
{ |
|||
File.Copy(result.ResultFileName, result.OriginalFileName, true); |
|||
File.Delete(result.ResultFileName); |
|||
} |
|||
else |
|||
{ |
|||
File.Delete(targetFile); |
|||
} |
|||
} |
|||
|
|||
private static Task<PostProcessingResultEventArgs> RunProcessAsync(string sourceFile, string targetFile) |
|||
{ |
|||
TaskCompletionSource<PostProcessingResultEventArgs> tcs = new TaskCompletionSource<PostProcessingResultEventArgs>(); |
|||
ProcessStartInfo start = new ProcessStartInfo("cmd") |
|||
{ |
|||
WindowStyle = ProcessWindowStyle.Hidden, |
|||
WorkingDirectory = PostProcessorBootstrapper.WorkingPath, |
|||
Arguments = GetArguments(sourceFile, targetFile), |
|||
UseShellExecute = false, |
|||
CreateNoWindow = true, |
|||
}; |
|||
|
|||
if (string.IsNullOrWhiteSpace(start.Arguments)) |
|||
{ |
|||
tcs.SetResult(null); |
|||
return tcs.Task; |
|||
} |
|||
|
|||
Process process = new Process |
|||
{ |
|||
StartInfo = start, |
|||
EnableRaisingEvents = true |
|||
}; |
|||
|
|||
process.Exited += (sender, args) => |
|||
{ |
|||
tcs.SetResult(new PostProcessingResultEventArgs(sourceFile, targetFile)); |
|||
process.Dispose(); |
|||
}; |
|||
|
|||
process.Start(); |
|||
|
|||
return tcs.Task; |
|||
} |
|||
|
|||
private static string GetArguments(string sourceFile, string targetFile) |
|||
{ |
|||
if (!Uri.IsWellFormedUriString(sourceFile, UriKind.RelativeOrAbsolute) && !File.Exists(sourceFile)) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
string ext; |
|||
|
|||
string extension = Path.GetExtension(sourceFile); |
|||
if (extension != null) |
|||
{ |
|||
ext = extension.ToLowerInvariant(); |
|||
} |
|||
else |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
switch (ext) |
|||
{ |
|||
case ".png": |
|||
return string.Format(CultureInfo.CurrentCulture, "/c png.cmd \"{0}\" \"{1}\"", sourceFile, targetFile); |
|||
|
|||
case ".jpg": |
|||
case ".jpeg": |
|||
return string.Format(CultureInfo.CurrentCulture, "/c jpegtran -copy all -optimize -progressive \"{0}\" \"{1}\"", sourceFile, targetFile); |
|||
|
|||
case ".gif": |
|||
return string.Format(CultureInfo.CurrentCulture, "/c gifsicle --crop-transparency --no-comments --no-extensions --no-names --optimize=3 --batch \"{0}\" --output=\"{1}\"", sourceFile, targetFile); |
|||
} |
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
// <copyright file="PostProcessorBootstrapper.cs" company="James South">
|
|||
// Copyright (c) James South.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
// <summary>
|
|||
// The postprocessor bootstrapper.
|
|||
// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
// </summary>
|
|||
// --------------------------------------------------------------------------------------------------------------------
|
|||
|
|||
namespace ImageProcessor.Web.PostProcessor |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Reflection; |
|||
|
|||
using ImageProcessor.Configuration; |
|||
|
|||
/// <summary>
|
|||
/// The postprocessor bootstrapper.
|
|||
/// Many thanks to Azure Image Optimizer <see href="https://github.com/ligershark/AzureJobs"/>
|
|||
/// </summary>
|
|||
internal static class PostProcessorBootstrapper |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes static members of the <see cref="PostProcessorBootstrapper"/> class.
|
|||
/// </summary>
|
|||
static PostProcessorBootstrapper() |
|||
{ |
|||
RegisterExecutables(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the working directory path.
|
|||
/// </summary>
|
|||
public static string WorkingPath { get; private set; } |
|||
|
|||
/// <summary>
|
|||
/// Registers the embedded executables.
|
|||
/// </summary>
|
|||
public static void RegisterExecutables() |
|||
{ |
|||
// None of the tools used here are called using dllimport so we don't go through the normal registration channel.
|
|||
string folder = ImageProcessorBootstrapper.Instance.NativeBinaryFactory.Is64BitEnvironment ? "x64" : "x86"; |
|||
Assembly assembly = Assembly.GetExecutingAssembly(); |
|||
WorkingPath = Path.GetFullPath(Path.Combine(new Uri(assembly.Location).LocalPath, "..\\imageprocessor.postprocessor\\")); |
|||
|
|||
// Create the folder for storing temporary images.
|
|||
// ReSharper disable once AssignNullToNotNullAttribute
|
|||
DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(WorkingPath)); |
|||
if (!directoryInfo.Exists) |
|||
{ |
|||
directoryInfo.Create(); |
|||
} |
|||
|
|||
// Get the resources and copy them across.
|
|||
Dictionary<string, string> resources = new Dictionary<string, string> |
|||
{ |
|||
{"gifsicle.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged." + folder + ".gifsicle.exe"}, |
|||
{"jpegtran.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.jpegtran.exe"}, |
|||
{"optipng.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.optipng.exe"}, |
|||
{"pngout.exe","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.pngout.exe"}, |
|||
{"png.cmd","ImageProcessor.Web.PostProcessor.Resources.Unmanaged.x86.png.cmd" } |
|||
}; |
|||
|
|||
// Write the files out to the bin folder.
|
|||
foreach (KeyValuePair<string, string> resource in resources) |
|||
{ |
|||
using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource.Value)) |
|||
{ |
|||
if (resourceStream != null) |
|||
{ |
|||
using (FileStream fileStream = File.OpenWrite(Path.Combine(WorkingPath, resource.Key))) |
|||
{ |
|||
resourceStream.CopyTo(fileStream); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle("ImageProcessor.Web.PostProcessor")] |
|||
[assembly: AssemblyDescription("")] |
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("ImageProcessor.Web.PostProcessor")] |
|||
[assembly: AssemblyCopyright("Copyright © 2014")] |
|||
[assembly: AssemblyTrademark("")] |
|||
[assembly: AssemblyCulture("")] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible(false)] |
|||
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|||
[assembly: Guid("089f0bac-b115-4c40-a955-64da08aa0989")] |
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion("1.0.0.0")] |
|||
[assembly: AssemblyFileVersion("1.0.0.0")] |
|||
@ -0,0 +1,13 @@ |
|||
#Resource locations |
|||
|
|||
###gifsicle |
|||
http://www.lcdf.org/gifsicle/ |
|||
|
|||
###jpegtran |
|||
http://jpegclub.org/jpegtran/ |
|||
|
|||
###optipng |
|||
http://optipng.sourceforge.net/ |
|||
|
|||
###pngout |
|||
http://advsys.net/ken/utils.htm |
|||
@ -0,0 +1 @@ |
|||
8fdba772314bc58249bc68118054cadfabf200ba |
|||
@ -0,0 +1 @@ |
|||
58c7376ac5c2b3f95a36c286d35d4151abc8fafc |
|||
@ -0,0 +1 @@ |
|||
c4b33334d3a5ce903fee18d9573571d93ac81bd4 |
|||
@ -0,0 +1 @@ |
|||
81cff3c5fe3cf669ef6e158240cc0034ed3711fd |
|||
@ -0,0 +1,2 @@ |
|||
optipng %1 -out %2 -o3 -i0 -quiet |
|||
pngout %2 %2 /s1 /y /v /q |
|||
Binary file not shown.
@ -0,0 +1 @@ |
|||
<StyleCopSettings Version="105" /> |
|||
Loading…
Reference in new issue