Browse Source

Adding transparent webp support

Former-commit-id: b58d521dd552879f628fa155468b4f47d8e23ad1
af/merge-core
James South 12 years ago
parent
commit
bebb485807
  1. 5
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  2. 71
      src/ImageProcessor/Imaging/Formats/WebPFormat.cs
  3. 27
      src/ImageProcessorConsole/Program.cs
  4. 3
      src/ImageProcessorConsole/images/input/circle.png
  5. 1
      src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id
  6. 3
      src/ImageProcessorConsole/images/output/circle.webp
  7. 3
      src/ImageProcessorConsole/images/output/rotate.webp

5
src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs

@ -359,13 +359,14 @@ namespace ImageProcessor.Web.HttpModules
IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]); IPrincipal user = context.User ?? new GenericPrincipal(new GenericIdentity(string.Empty, string.Empty), new string[0]);
// Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal? // Do we have permission to call UrlAuthorizationModule.CheckUrlAccessForPrincipal?
PermissionSet permission = new PermissionSet(PermissionState.None); PermissionSet permission = new PermissionSet(PermissionState.Unrestricted);
permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted)); permission.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted));
bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet); bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet);
bool isAllowed = true; bool isAllowed = true;
// Run the rewritten path past the auth system again, using the result as the default "AllowAccess" value // Run the rewritten path past the authorization system again.
// We can then use the result as the default "AllowAccess" value
if (hasPermission && !context.SkipAuthorization) if (hasPermission && !context.SkipAuthorization)
{ {
isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET"); isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET");

71
src/ImageProcessor/Imaging/Formats/WebPFormat.cs

@ -13,6 +13,7 @@
namespace ImageProcessor.Imaging.Formats namespace ImageProcessor.Imaging.Formats
{ {
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
@ -20,6 +21,8 @@ namespace ImageProcessor.Imaging.Formats
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using ImageProcessor.Core.Common.Exceptions;
/// <summary> /// <summary>
/// Provides the necessary information to support webp images. /// Provides the necessary information to support webp images.
/// Adapted from <see cref="http://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/1coeidT0rQU"/> /// Adapted from <see cref="http://groups.google.com/a/webmproject.org/forum/#!topic/webp-discuss/1coeidT0rQU"/>
@ -72,6 +75,35 @@ namespace ImageProcessor.Imaging.Formats
} }
} }
/// <summary>
/// Applies the given processor the current image.
/// </summary>
/// <param name="processor">The processor delegate.</param>
/// <param name="factory">The <see cref="ImageFactory" />.</param>
public override void ApplyProcessor(Func<ImageFactory, Image> processor, ImageFactory factory)
{
base.ApplyProcessor(processor, factory);
// Set the property item information from any Exif metadata.
// We do this here so that they can be changed between processor methods.
if (factory.PreserveExifData)
{
foreach (KeyValuePair<int, PropertyItem> propertItem in factory.ExifPropertyItems)
{
try
{
factory.Image.SetPropertyItem(propertItem.Value);
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Do nothing. The image format does not handle EXIF data.
// TODO: empty catch is fierce code smell.
}
}
}
}
/// <summary> /// <summary>
/// Decodes the image to process. /// Decodes the image to process.
/// </summary> /// </summary>
@ -151,49 +183,48 @@ namespace ImageProcessor.Imaging.Formats
IntPtr ptrData = pinnedWebP.AddrOfPinnedObject(); IntPtr ptrData = pinnedWebP.AddrOfPinnedObject();
uint dataSize = (uint)webpData.Length; uint dataSize = (uint)webpData.Length;
int imgWidth; int width;
int imgHeight; int height;
if (WebPGetInfo(ptrData, dataSize, out imgWidth, out imgHeight) != 1) if (WebPGetInfo(ptrData, dataSize, out width, out height) != 1)
{ {
// TODO: Throw error? throw new ImageFormatException("WebP image is corrupted.");
return null;
} }
// Create a BitmapData and Lock all pixels to be written // Create a BitmapData and Lock all pixels to be written
Bitmap bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb); Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
// Allocate memory for uncompress image // Allocate memory for uncompress image
int outputBufferSize = bmpData.Stride * imgHeight; int outputBufferSize = bitmapData.Stride * height;
IntPtr outputBuffer = Marshal.AllocHGlobal(outputBufferSize); IntPtr outputBuffer = Marshal.AllocHGlobal(outputBufferSize);
// Uncompress the image // Uncompress the image
outputBuffer = WebPDecodeBGRInto(ptrData, dataSize, outputBuffer, outputBufferSize, bmpData.Stride); outputBuffer = WebPDecodeBGRAInto(ptrData, dataSize, outputBuffer, outputBufferSize, bitmapData.Stride);
// Write image to bitmap using Marshal // Write image to bitmap using Marshal
byte[] buffer = new byte[outputBufferSize]; byte[] buffer = new byte[outputBufferSize];
Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize); Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize);
Marshal.Copy(buffer, 0, bmpData.Scan0, outputBufferSize); Marshal.Copy(buffer, 0, bitmapData.Scan0, outputBufferSize);
// Unlock the pixels // Unlock the pixels
bmp.UnlockBits(bmpData); bitmap.UnlockBits(bitmapData);
// Free memory // Free memory
pinnedWebP.Free(); pinnedWebP.Free();
Marshal.FreeHGlobal(outputBuffer); Marshal.FreeHGlobal(outputBuffer);
return bmp; return bitmap;
} }
/// <summary> /// <summary>
/// Lossly encodes the image in bitmap. /// Lossy encodes the image in bitmap.
/// </summary> /// </summary>
/// <param name="bitmap"> /// <param name="bitmap">
/// Bitmap with the image /// Bitmap with the image
/// </param> /// </param>
/// <param name="quality"> /// <param name="quality">
/// Quality. 0 = minimum ... 100 = maximimun quality /// Quality. 0 = minimum ... 100 = maximum quality
/// </param> /// </param>
/// <param name="webpData"> /// <param name="webpData">
/// The byte array containing the encoded image data. /// The byte array containing the encoded image data.
@ -207,9 +238,9 @@ namespace ImageProcessor.Imaging.Formats
try try
{ {
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
IntPtr unmanagedData; IntPtr unmanagedData;
int size = WebPEncodeBGR(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData); int size = WebPEncodeBGRA(bmpData.Scan0, bitmap.Width, bitmap.Height, bmpData.Stride, quality, out unmanagedData);
// Copy image compress data to output array // Copy image compress data to output array
webpData = new byte[size]; webpData = new byte[size];
@ -266,16 +297,16 @@ namespace ImageProcessor.Imaging.Formats
/// Size of allocated buffer /// Size of allocated buffer
/// </param> /// </param>
/// <param name="outputStride"> /// <param name="outputStride">
/// Specifies the distance between scanlines /// Specifies the distance between scan-lines
/// </param> /// </param>
/// <returns> /// <returns>
/// output_buffer if function succeeds; NULL otherwise /// output_buffer if function succeeds; NULL otherwise
/// </returns> /// </returns>
[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr WebPDecodeBGRInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride); private static extern IntPtr WebPDecodeBGRAInto(IntPtr data, uint dataSize, IntPtr outputBuffer, int outputBufferSize, int outputStride);
/// <summary> /// <summary>
/// Lossless encoding images pointed to by *data in WebP format /// Lossy encoding images pointed to by *data in WebP format
/// </summary> /// </summary>
/// <param name="rgb"> /// <param name="rgb">
/// Pointer to RGB image data /// Pointer to RGB image data
@ -299,7 +330,7 @@ namespace ImageProcessor.Imaging.Formats
/// Size of WebP Image /// Size of WebP Image
/// </returns> /// </returns>
[DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("libwebp.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int WebPEncodeBGR(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output); private static extern int WebPEncodeBGRA(IntPtr rgb, int width, int height, int stride, float qualityFactor, out IntPtr output);
/// <summary> /// <summary>
/// Frees the unmanaged memory. /// Frees the unmanaged memory.

27
src/ImageProcessorConsole/Program.cs

@ -10,8 +10,11 @@
namespace ImageProcessorConsole namespace ImageProcessorConsole
{ {
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq;
using ImageProcessor; using ImageProcessor;
using ImageProcessor.Imaging.Formats; using ImageProcessor.Imaging.Formats;
@ -37,8 +40,10 @@ namespace ImageProcessorConsole
di.Create(); di.Create();
} }
//FileInfo[] files = di.GetFiles("*.gif"); FileInfo[] files = di.GetFiles("*.jpg");
FileInfo[] files = di.GetFiles(); //FileInfo[] files = di.GetFiles();
//var files = GetFilesByExtensions(di, ".gif", ".webp");
foreach (FileInfo fileInfo in files) foreach (FileInfo fileInfo in files)
{ {
@ -47,20 +52,30 @@ namespace ImageProcessorConsole
// ImageProcessor // ImageProcessor
using (MemoryStream inStream = new MemoryStream(photoBytes)) using (MemoryStream inStream = new MemoryStream(photoBytes))
{ {
using (ImageFactory imageFactory = new ImageFactory()) using (ImageFactory imageFactory = new ImageFactory(true))
{ {
Size size = new Size(200, 200); Size size = new Size(200, 200);
// Load, resize, set the format and quality and save an image. // Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream) imageFactory.Load(inStream)
.AutoRotate()
.Constrain(size) .Constrain(size)
//.Format(new JpegFormat()) .Format(new WebPFormat())
.Quality(5)
// ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once AssignNullToNotNullAttribute
// .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".jpg"))); .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", Path.GetFileNameWithoutExtension(fileInfo.Name) + ".webp")));
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); //.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
} }
} }
} }
} }
public static IEnumerable<FileInfo> GetFilesByExtensions(DirectoryInfo dir, params string[] extensions)
{
if (extensions == null)
throw new ArgumentNullException("extensions");
IEnumerable<FileInfo> files = dir.EnumerateFiles();
return files.Where(f => extensions.Contains(f.Extension, StringComparer.OrdinalIgnoreCase));
}
} }
} }

3
src/ImageProcessorConsole/images/input/circle.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3df296a3fd58930899d308558b128db760879cb776afba8f2d6511aba3934dd0
size 6957

1
src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id

@ -0,0 +1 @@
406a6a7916628c0c0bea8243565a7162ebd5a505

3
src/ImageProcessorConsole/images/output/circle.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ac5bfc52fe066984db96d0b169a7fb7ebd76f3a1cf946ba02a167475377903c2
size 1228

3
src/ImageProcessorConsole/images/output/rotate.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3543de5854cc0a8a95b5249548abc8150040542a127ac6d89eb6338b8dfa3a83
size 1812
Loading…
Cancel
Save