diff --git a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
index 2fe0a275d..d7b15e7e1 100644
--- a/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
+++ b/src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
@@ -43,6 +43,11 @@ namespace ImageProcessor.Web.HttpModules
///
private const string CachedResponseTypeKey = "CACHED_IMAGE_RESPONSE_TYPE_054F217C-11CF-49FF-8D2F-698E8E6EB58F";
+ ///
+ /// The key for storing the file dependency of the current image.
+ ///
+ private const string CachedResponseFileDependency = "CACHED_IMAGE_DEPENDENCY_054F217C-11CF-49FF-8D2F-698E8E6EB58F";
+
///
/// The regular expression to search strings for.
///
@@ -215,15 +220,18 @@ namespace ImageProcessor.Web.HttpModules
HttpContext context = ((HttpApplication)sender).Context;
object responseTypeObject = context.Items[CachedResponseTypeKey];
+ object dependencyFileObject = context.Items[CachedResponseFileDependency];
- if (responseTypeObject != null)
+ if (responseTypeObject != null && dependencyFileObject != null)
{
string responseType = (string)responseTypeObject;
+ string dependencyFile = (string)dependencyFileObject;
// Set the headers
- this.SetHeaders(context, responseType);
+ this.SetHeaders(context, responseType, dependencyFile);
context.Items[CachedResponseTypeKey] = null;
+ context.Items[CachedResponseFileDependency] = null;
}
}
@@ -440,7 +448,15 @@ namespace ImageProcessor.Web.HttpModules
}
}
- string incomingEtag = context.Request.Headers["If-None-Match"];
+ // Image is from the cache so the mime-type will need to be set.
+ if (context.Items[CachedResponseTypeKey] == null)
+ {
+ context.Items[CachedResponseTypeKey] = ImageHelpers.GetExtension(cachedPath).Replace(".", "image/");
+ }
+
+ context.Items[CachedResponseFileDependency] = cachedPath;
+
+ string incomingEtag = context.Request.Headers["If" + "-None-Match"];
if (incomingEtag != null && !isNewOrUpdated)
{
@@ -449,8 +465,7 @@ namespace ImageProcessor.Web.HttpModules
context.Response.AddHeader("Content-Length", "0");
context.Response.StatusCode = (int)HttpStatusCode.NotModified;
context.Response.SuppressContent = true;
- context.Response.AddFileDependency(context.Server.MapPath(virtualCachedPath));
- this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey]);
+ this.SetHeaders(context, (string)context.Items[CachedResponseTypeKey], cachedPath);
if (!isRemote)
{
@@ -482,18 +497,28 @@ namespace ImageProcessor.Web.HttpModules
/// the HttpContext object that provides
/// references to the intrinsic server objects
///
- /// The HTTP MIME type to to send.
- private void SetHeaders(HttpContext context, string responseType)
+ ///
+ /// The HTTP MIME type to to send.
+ ///
+ ///
+ /// The dependency path for the cache dependency.
+ ///
+ private void SetHeaders(HttpContext context, string responseType, string dependencyPath)
{
HttpResponse response = context.Response;
response.ContentType = responseType;
- response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion);
+ if (response.Headers["Image-Served-By"] == null)
+ {
+ response.AddHeader("Image-Served-By", "ImageProcessor.Web/" + AssemblyVersion);
+ }
HttpCachePolicy cache = response.Cache;
cache.SetCacheability(HttpCacheability.Public);
cache.VaryByHeaders["Accept-Encoding"] = true;
+
+ context.Response.AddFileDependency(dependencyPath);
cache.SetLastModifiedFromFileDependencies();
int maxDays = DiskCache.MaxFileCachedDuration;
diff --git a/src/ImageProcessor.sln b/src/ImageProcessor.sln
index a12d17c68..8ad0ed4e9 100644
--- a/src/ImageProcessor.sln
+++ b/src/ImageProcessor.sln
@@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Web.UnitTest
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.UnitTests", "ImageProcessor.UnitTests\ImageProcessor.UnitTests.csproj", "{633B1C4C-4823-47BE-9A01-A665F3118C8C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageProcessor.Plugins.WebP", "Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ImageProcessor.Plugins.WebP.csproj", "{2CF69699-959A-44DC-A281-4E2596C25043}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
All|Any CPU = All|Any CPU
@@ -201,6 +203,21 @@ Global
{633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{633B1C4C-4823-47BE-9A01-A665F3118C8C}.Release|x86.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.All|Any CPU.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.All|Any CPU.Build.0 = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.All|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.All|Mixed Platforms.Build.0 = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.All|x86.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {2CF69699-959A-44DC-A281-4E2596C25043}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs
index 09b772455..59f975fb3 100644
--- a/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs
+++ b/src/ImageProcessor/Configuration/ImageProcessorBootstrapper.cs
@@ -4,22 +4,25 @@
// Licensed under the Apache License, Version 2.0.
//
//
-// The image processor bootstrapper.
+// The ImageProcessor bootstrapper.
//
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Configuration
{
using System;
+ using System.Collections;
using System.Collections.Generic;
+ using System.IO;
using System.Linq;
+ using System.Reflection;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Formats;
///
- /// The image processor bootstrapper.
+ /// The ImageProcessor bootstrapper.
///
public class ImageProcessorBootstrapper
{
@@ -35,8 +38,8 @@ namespace ImageProcessor.Configuration
///
private ImageProcessorBootstrapper()
{
- this.LoadSupportedImageFormats();
this.NativeBinaryFactory = new NativeBinaryFactory();
+ this.LoadSupportedImageFormats();
}
///
@@ -70,14 +73,42 @@ namespace ImageProcessor.Configuration
try
{
Type type = typeof(ISupportedImageFormat);
+ HashSet found = new HashSet();
+
+ // Get any references and used assemblies.
+ foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ this.LoadReferencedAssemblies(found, assembly);
+ }
+
+ // Get any referenced but not used assemblies.
+ Assembly executingAssembly = Assembly.GetExecutingAssembly();
+ string targetBasePath = Path.GetDirectoryName(new Uri(executingAssembly.Location).LocalPath);
+
+ // ReSharper disable once AssignNullToNotNullAttribute
+ FileInfo[] files = new DirectoryInfo(targetBasePath).GetFiles("*.dll", SearchOption.AllDirectories);
+
+ foreach (FileInfo fileInfo in files)
+ {
+ AssemblyName assemblyName = AssemblyName.GetAssemblyName(fileInfo.FullName);
+
+ if (!AppDomain.CurrentDomain.GetAssemblies()
+ .Any(a => AssemblyName.ReferenceMatchesDefinition(assemblyName, a.GetName())))
+ {
+ // In a web app, this assembly will automatically be bound from the
+ // Asp.Net Temporary folder from where the site actually runs.
+ this.LoadReferencedAssemblies(found, Assembly.Load(assemblyName));
+ }
+ }
+
List availableTypes = AppDomain.CurrentDomain
.GetAssemblies()
- .SelectMany(s => s.GetLoadableTypes())
+ .SelectMany(a => a.GetLoadableTypes())
.Where(t => type.IsAssignableFrom(t) && t.IsClass && !t.IsAbstract)
.ToList();
this.SupportedImageFormats = availableTypes
- .Select(x => (Activator.CreateInstance(x) as ISupportedImageFormat)).ToList();
+ .Select(f => (Activator.CreateInstance(f) as ISupportedImageFormat)).ToList();
}
catch (Exception ex)
{
@@ -85,5 +116,49 @@ namespace ImageProcessor.Configuration
}
}
}
+
+ ///
+ /// Loads any referenced assemblies into the current application domain.
+ ///
+ ///
+ /// The collection containing the name of already found assemblies.
+ ///
+ ///
+ /// The assembly to load from.
+ ///
+ private void LoadReferencedAssemblies(HashSet found, Assembly assembly)
+ {
+ // Used to avoid duplicates
+ ArrayList results = new ArrayList();
+
+ // Resulting info
+ Stack stack = new Stack();
+
+ // Stack of names
+ // Store root assembly (level 0) directly into results list
+ stack.Push(assembly.ToString());
+
+ // Do a preorder, non-recursive traversal
+ while (stack.Count > 0)
+ {
+ string info = (string)stack.Pop();
+
+ // Get next assembly
+ if (!found.Contains(info))
+ {
+ found.Add(info);
+ results.Add(info);
+
+ // Store it to results ArrayList
+ Assembly child = Assembly.Load(info);
+ AssemblyName[] subchild = child.GetReferencedAssemblies();
+
+ for (int i = subchild.Length - 1; i >= 0; --i)
+ {
+ stack.Push(subchild[i].ToString());
+ }
+ }
+ }
+ }
}
}
diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj
index ad69d127b..ed1aa9c64 100644
--- a/src/ImageProcessor/ImageProcessor.csproj
+++ b/src/ImageProcessor/ImageProcessor.csproj
@@ -79,7 +79,6 @@
-
@@ -87,7 +86,6 @@
-
@@ -131,10 +129,6 @@
-
-
-
-
diff --git a/src/ImageProcessorConsole/ImageProcessorConsole.csproj b/src/ImageProcessorConsole/ImageProcessorConsole.csproj
index fba366b0c..1afd8ef0e 100644
--- a/src/ImageProcessorConsole/ImageProcessorConsole.csproj
+++ b/src/ImageProcessorConsole/ImageProcessorConsole.csproj
@@ -56,6 +56,10 @@
{3B5DD734-FB7A-487D-8CE6-55E7AF9AEA7E}
ImageProcessor
+
+ {2cf69699-959a-44dc-a281-4e2596c25043}
+ ImageProcessor.Plugins.WebP
+
+
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs
similarity index 96%
rename from src/ImageProcessor/Imaging/Formats/NativeMethods.cs
rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs
index 0c42710b0..936b58256 100644
--- a/src/ImageProcessor/Imaging/Formats/NativeMethods.cs
+++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/NativeMethods.cs
@@ -8,7 +8,7 @@
//
// --------------------------------------------------------------------------------------------------------------------
-namespace ImageProcessor.Imaging.Formats
+namespace ImageProcessor.Plugins.WebP.Imaging.Formats
{
using System;
using System.IO;
@@ -23,7 +23,7 @@ namespace ImageProcessor.Imaging.Formats
internal static class NativeMethods
{
///
- /// Whether the process is running in 64bit mode. Used for calling the correct dllimport method.
+ /// Whether the process is running in 64bit mode. Used for calling the correct method.
/// Clunky I know but I couldn't get dynamic methods to work.
///
private static readonly bool Is64Bit = Environment.Is64BitProcess;
@@ -34,7 +34,7 @@ namespace ImageProcessor.Imaging.Formats
static NativeMethods()
{
string folder = Is64Bit ? "x64" : "x86";
- string name = string.Format("ImageProcessor.Resources.Unmanaged.{0}.libwebp.dll", folder);
+ string name = string.Format("ImageProcessor.Plugins.WebP.Resources.Unmanaged.{0}.libwebp.dll", folder);
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
using (MemoryStream memoryStream = new MemoryStream())
diff --git a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs
similarity index 98%
rename from src/ImageProcessor/Imaging/Formats/WebPFormat.cs
rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs
index 9f350c5c0..0bc2e2b7b 100644
--- a/src/ImageProcessor/Imaging/Formats/WebPFormat.cs
+++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Imaging/Formats/WebPFormat.cs
@@ -10,7 +10,7 @@
//
// --------------------------------------------------------------------------------------------------------------------
-namespace ImageProcessor.Imaging.Formats
+namespace ImageProcessor.Plugins.WebP.Imaging.Formats
{
using System;
using System.Collections.Generic;
@@ -22,6 +22,7 @@ namespace ImageProcessor.Imaging.Formats
using System.Text;
using ImageProcessor.Common.Exceptions;
+ using ImageProcessor.Imaging.Formats;
///
/// Provides the necessary information to support webp images.
diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..d9aa6f985
--- /dev/null
+++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Properties/AssemblyInfo.cs
@@ -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.Plugins.WebP")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("James South")]
+[assembly: AssemblyProduct("ImageProcessor.Plugins.WebP")]
+[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("bf160db5-2ea7-4c85-9b0e-f1ddf2595e37")]
+
+// 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")]
diff --git a/src/ImageProcessor/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id
similarity index 100%
rename from src/ImageProcessor/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id
rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x64/libwebp.dll.REMOVED.git-id
diff --git a/src/ImageProcessor/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id
similarity index 100%
rename from src/ImageProcessor/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id
rename to src/Plugins/ImageProcessor/ImageProcessor.Plugins.WebP/Resources/Unmanaged/x86/libwebp.dll.REMOVED.git-id
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs b/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs
index 02fc35575..1eae92d44 100644
--- a/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs
+++ b/src/TestWebsites/NET45/Test_Website_NET45/Controllers/HomeController.cs
@@ -41,6 +41,11 @@ namespace Test_Website_NET45.Controllers
return View();
}
+ public ActionResult WebP()
+ {
+ return View();
+ }
+
public ActionResult External()
{
return this.View();
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj b/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj
index 96f09d69b..c2118914f 100644
--- a/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj
+++ b/src/TestWebsites/NET45/Test_Website_NET45/Test_Website_MVC_NET45.csproj
@@ -159,6 +159,10 @@
{3b5dd734-fb7a-487d-8ce6-55e7af9aea7e}
ImageProcessor
+
+ {2cf69699-959a-44dc-a281-4e2596c25043}
+ ImageProcessor.Plugins.WebP
+
@@ -191,6 +195,9 @@
+
+
+
10.0
$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml
new file mode 100644
index 000000000..ff03d1240
--- /dev/null
+++ b/src/TestWebsites/NET45/Test_Website_NET45/Views/Home/WebP.cshtml
@@ -0,0 +1,100 @@
+@{
+ ViewBag.Title = "WebP";
+}
+
+
+ WebP
+
+
+
+
Resized
+

+
+
+
Cropped
+

+
+
+
+
+ Filter
+
+
+
blackwhite
+

+
+
+
comic
+

+
+
+
+
+
lomograph
+

+
+
+
greyscale
+

+
+
+
+
+
polaroid
+

+
+
+
sepia
+

+
+
+
+
+
gotham
+

+
+
+
hisatch
+

+
+
+
+
+
losatch
+

+
+
+
+
+
+
+
Watermark
+

+
+
+
Format
+

+
+
+
+
+
+
+
Rotate
+

+
+
+
Quality
+

+
+
+
+
+
+
+
Alpha
+

+
+
+
+
diff --git a/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml b/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml
index 74af019a2..5f8255ea4 100644
--- a/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml
+++ b/src/TestWebsites/NET45/Test_Website_NET45/Views/Shared/_Layout.cshtml
@@ -29,6 +29,7 @@
@Html.ActionLink("Png8", "Png8")
@Html.ActionLink("Bmp", "Bmp")
@Html.ActionLink("Tiff", "Tiff")
+ @Html.ActionLink("WebP", "WebP")
@Html.ActionLink("External", "External")