Browse Source

Adding transparent webp support

Former-commit-id: b58d521dd552879f628fa155468b4f47d8e23ad1
pull/17/head
James South 12 years ago
parent
commit
81a175a7db
  1. 5
      src/ImageProcessor.Web/NET45/HttpModules/ImageProcessingModule.cs
  2. 71
      src/ImageProcessor/Imaging/Formats/WebPFormat.cs
  3. 27
      src/ImageProcessorConsole/Program.cs
  4. BIN
      src/ImageProcessorConsole/images/input/circle.png
  5. 1
      src/ImageProcessorConsole/images/input/rotate.jpg.REMOVED.git-id
  6. BIN
      src/ImageProcessorConsole/images/output/circle.webp
  7. BIN
      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]);
// 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));
bool hasPermission = permission.IsSubsetOf(AppDomain.CurrentDomain.PermissionSet);
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)
{
isAllowed = UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualCachedPath, user, "GET");

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

@ -13,6 +13,7 @@
namespace ImageProcessor.Imaging.Formats
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Imaging;
@ -20,6 +21,8 @@ namespace ImageProcessor.Imaging.Formats
using System.Runtime.InteropServices;
using System.Text;
using ImageProcessor.Core.Common.Exceptions;
/// <summary>
/// Provides the necessary information to support webp images.
/// 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>
/// Decodes the image to process.
/// </summary>
@ -151,49 +183,48 @@ namespace ImageProcessor.Imaging.Formats
IntPtr ptrData = pinnedWebP.AddrOfPinnedObject();
uint dataSize = (uint)webpData.Length;
int imgWidth;
int imgHeight;
int width;
int height;
if (WebPGetInfo(ptrData, dataSize, out imgWidth, out imgHeight) != 1)
if (WebPGetInfo(ptrData, dataSize, out width, out height) != 1)
{
// TODO: Throw error?
return null;
throw new ImageFormatException("WebP image is corrupted.");
}
// Create a BitmapData and Lock all pixels to be written
Bitmap bmp = new Bitmap(imgWidth, imgHeight, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
// Allocate memory for uncompress image
int outputBufferSize = bmpData.Stride * imgHeight;
int outputBufferSize = bitmapData.Stride * height;
IntPtr outputBuffer = Marshal.AllocHGlobal(outputBufferSize);
// 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
byte[] buffer = new byte[outputBufferSize];
Marshal.Copy(outputBuffer, buffer, 0, outputBufferSize);
Marshal.Copy(buffer, 0, bmpData.Scan0, outputBufferSize);
Marshal.Copy(buffer, 0, bitmapData.Scan0, outputBufferSize);
// Unlock the pixels
bmp.UnlockBits(bmpData);
bitmap.UnlockBits(bitmapData);
// Free memory
pinnedWebP.Free();
Marshal.FreeHGlobal(outputBuffer);
return bmp;
return bitmap;
}
/// <summary>
/// Lossly encodes the image in bitmap.
/// Lossy encodes the image in bitmap.
/// </summary>
/// <param name="bitmap">
/// Bitmap with the image
/// </param>
/// <param name="quality">
/// Quality. 0 = minimum ... 100 = maximimun quality
/// Quality. 0 = minimum ... 100 = maximum quality
/// </param>
/// <param name="webpData">
/// The byte array containing the encoded image data.
@ -207,9 +238,9 @@ namespace ImageProcessor.Imaging.Formats
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;
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
webpData = new byte[size];
@ -266,16 +297,16 @@ namespace ImageProcessor.Imaging.Formats
/// Size of allocated buffer
/// </param>
/// <param name="outputStride">
/// Specifies the distance between scanlines
/// Specifies the distance between scan-lines
/// </param>
/// <returns>
/// output_buffer if function succeeds; NULL otherwise
/// </returns>
[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>
/// Lossless encoding images pointed to by *data in WebP format
/// Lossy encoding images pointed to by *data in WebP format
/// </summary>
/// <param name="rgb">
/// Pointer to RGB image data
@ -299,7 +330,7 @@ namespace ImageProcessor.Imaging.Formats
/// Size of WebP Image
/// </returns>
[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>
/// Frees the unmanaged memory.

27
src/ImageProcessorConsole/Program.cs

@ -10,8 +10,11 @@
namespace ImageProcessorConsole
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using ImageProcessor;
using ImageProcessor.Imaging.Formats;
@ -37,8 +40,10 @@ namespace ImageProcessorConsole
di.Create();
}
//FileInfo[] files = di.GetFiles("*.gif");
FileInfo[] files = di.GetFiles();
FileInfo[] files = di.GetFiles("*.jpg");
//FileInfo[] files = di.GetFiles();
//var files = GetFilesByExtensions(di, ".gif", ".webp");
foreach (FileInfo fileInfo in files)
{
@ -47,20 +52,30 @@ namespace ImageProcessorConsole
// ImageProcessor
using (MemoryStream inStream = new MemoryStream(photoBytes))
{
using (ImageFactory imageFactory = new ImageFactory())
using (ImageFactory imageFactory = new ImageFactory(true))
{
Size size = new Size(200, 200);
// Load, resize, set the format and quality and save an image.
imageFactory.Load(inStream)
.AutoRotate()
.Constrain(size)
//.Format(new JpegFormat())
.Format(new WebPFormat())
.Quality(5)
// 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", fileInfo.Name)));
.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)));
}
}
}
}
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));
}
}
}

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

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

@ -0,0 +1 @@
406a6a7916628c0c0bea8243565a7162ebd5a505

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Loading…
Cancel
Save