Issue with WIC image resizing on ASP.NET MVC 2
- by Dave
I am attempting to implement image resizing on user uploads in ASP.NET MVC 2 using a version of the method found: here on asp.net.
This works great on my dev machine, but as soon as I put it on my production machine, I start getting the error 'Exception from HRESULT: 0x88982F60' which is supposed to mean that there is an issue decoding the image. However, when I use WICExplorer to open the image, it looks ok. I've also tried this with dozens of images of various sources and still get the error (though possible, I doubt all of them are corrupted).
Here is the relevant code (with my debugging statements in there):
MVC Controller
[Authorize, HttpPost]
public ActionResult Upload(string file)
{
//Check file extension
string fx = file.Substring(file.LastIndexOf('.')).ToLowerInvariant();
string key;
if (ConfigurationManager.AppSettings["ImageExtensions"].Contains(fx))
{
key = Guid.NewGuid().ToString() + fx;
}
else
{
return Json("extension not found");
}
//Check file size
if (Request.ContentLength <= Convert.ToInt32(ConfigurationManager.AppSettings["MinImageSize"]) ||
Request.ContentLength >= Convert.ToInt32(ConfigurationManager.AppSettings["MaxImageSize"]))
{
return Json("content length out of bounds: " + Request.ContentLength);
}
ImageResizerResult irr, irr2;
//Check if this image is coming from FF, Chrome or Safari (XHR)
HttpPostedFileBase hpf = null;
if (Request.Files.Count <= 0)
{
//Scale and encode image and thumbnail
irr = ImageResizer.CreateMaxSizeImage(Request.InputStream);
irr2 = ImageResizer.CreateThumbnail(Request.InputStream);
}
//Or IE
else
{
hpf = Request.Files[0] as HttpPostedFileBase;
if (hpf.ContentLength == 0)
return Json("hpf.length = 0");
//Scale and encode image and thumbnail
irr = ImageResizer.CreateMaxSizeImage(hpf.InputStream);
irr2 = ImageResizer.CreateThumbnail(hpf.InputStream);
}
//Check if image and thumbnail encoded and scaled correctly
if (irr == null || irr.output == null
|| irr2 == null || irr2.output == null)
{
if (irr != null && irr.output != null)
irr.output.Dispose();
if (irr2 != null && irr2.output != null)
irr2.output.Dispose();
if(irr == null)
return Json("irr null");
if (irr2 == null)
return Json("irr2 null");
if (irr.output == null)
return Json("irr.output null. irr.error = " + irr.error);
if (irr2.output == null)
return Json("irr2.output null. irr2.error = " + irr2.error);
}
if (irr.output.Length > Convert.ToInt32(ConfigurationManager.AppSettings["MaxImageSize"])
|| irr2.output.Length > Convert.ToInt32(ConfigurationManager.AppSettings["MaxImageSize"]))
{
if(irr.output.Length > Convert.ToInt32(ConfigurationManager.AppSettings["MaxImageSize"]))
return Json("irr.output.Length > maximage size. irr.output.Length = " + irr.output.Length + ", irr.error = " + irr.error);
return Json("irr2.output.Length > maximage size. irr2.output.Length = " + irr2.output.Length + ", irr2.error = " + irr2.error);
}
//Store scaled and encoded image and thumbnail
....
return Json("success");
}
The code is always failing when checking if the output stream is null (i.e. irr.output == null is true).
ImageResizerResult and ImageResizer
public class ImageResizerResult : IDisposable
{
public MemoryIStream output;
public int width;
public int height;
public string error;
public void Dispose() { output.Dispose(); }
}
public static class ImageResizer
{
private static Object thislock = new Object();
public static ImageResizerResult CreateMaxSizeImage(Stream input)
{
uint maxSize = Convert.ToUInt32(ConfigurationManager.AppSettings["MaxImageDimension"]);
try
{
lock (thislock)
{
// Read the source image
var photo = ByteArrayFromStream(input);
var factory = (IWICComponentFactory)new WICImagingFactory();
var inputStream = factory.CreateStream();
inputStream.InitializeFromMemory(photo, (uint)photo.Length);
var decoder = factory.CreateDecoderFromStream(inputStream, null, WICDecodeOptions.WICDecodeMetadataCacheOnDemand);
var frame = decoder.GetFrame(0);
// Compute target size
uint width, height, outWidth, outHeight;
frame.GetSize(out width, out height);
if (width > height)
{
//Check if width is greater than maxSize
if (width > maxSize)
{
outWidth = maxSize;
outHeight = height * maxSize / width;
}
//Width is less than maxSize, so use existing dimensions
else
{
outWidth = width;
outHeight = height;
}
}
else
{
//Check if height is greater than maxSize
if (height > maxSize)
{
outWidth = width * maxSize / height;
outHeight = maxSize;
}
//Height is less than maxSize, so use existing dimensions
else
{
outWidth = width;
outHeight = height;
}
}
// Prepare output stream to cache file
var outputStream = new MemoryIStream();
// Prepare JPG encoder
var encoder = factory.CreateEncoder(Consts.GUID_ContainerFormatJpeg, null);
encoder.Initialize(outputStream, WICBitmapEncoderCacheOption.WICBitmapEncoderNoCache);
// Prepare output frame
IWICBitmapFrameEncode outputFrame;
var arg = new IPropertyBag2[1];
encoder.CreateNewFrame(out outputFrame, arg);
var propBag = arg[0];
var propertyBagOption = new PROPBAG2[1];
propertyBagOption[0].pstrName = "ImageQuality";
propBag.Write(1, propertyBagOption, new object[] { 0.85F });
outputFrame.Initialize(propBag);
outputFrame.SetResolution(96, 96);
outputFrame.SetSize(outWidth, outHeight);
// Prepare scaler
var scaler = factory.CreateBitmapScaler();
scaler.Initialize(frame, outWidth, outHeight, WICBitmapInterpolationMode.WICBitmapInterpolationModeFant);
// Write the scaled source to the output frame
outputFrame.WriteSource(scaler, new WICRect { X = 0, Y = 0, Width = (int)outWidth, Height = (int)outHeight });
outputFrame.Commit();
encoder.Commit();
return new ImageResizerResult { output = outputStream, height = (int)outHeight, width = (int)outWidth };
}
}
catch (Exception e)
{
return new ImageResizerResult { error = "Create maxsizeimage = " + e.Message };
}
}
}
Thoughts on where this is going wrong?
Thanks in advance for the effort.