I have some code which takes an uploaded image, resizes it to 5 different sizes, then uploads those to another storage repository. I'm trying to execute the 5 image resizing operations in parallel using TPL.
Upfront I'll mention that the resizing function is a static method, but that it doesn't use any static resources (so multiple parallel calls shouldn't be stepping on each other, from what I can tell). Also very relevant is that this is in the context of ASP.NET which has some different threading concerns.
When I run the following code, I invariably get an "invalid parameter" error from one of the calls, though which call varies:
tasks = new Task<Uri>[]
{
Task.Run<Uri>(() => Upload(intId, ProfilePhotoSize.FiveHundredFixedWidth, photoStream, mediaType, minWidth)),
Task.Run<Uri>(() => Upload(intId, ProfilePhotoSize.Square220, photoStream, mediaType, minWidth)),
Task.Run<Uri>(() => Upload(intId, ProfilePhotoSize.Square140, photoStream, mediaType, minWidth)),
Task.Run<Uri>(() => Upload(intId, ProfilePhotoSize.Square80, photoStream, mediaType, minWidth)),
Task.Run<Uri>(() => Upload(intId, ProfilePhotoSize.Square50, photoStream, mediaType, minWidth))
};
await Task.WhenAll(tasks)
If I look at the images created, some will be ok, some will clearly be corrupted - and this applies not just to the "errored" image.
However, executing those five operations synchronously results in five good images:
Upload(intId, ProfilePhotoSize.FiveHundredFixedWidth, photoStream, mediaType, minWidth);
Upload(intId, ProfilePhotoSize.Square220, photoStream, mediaType, minWidth);
Upload(intId, ProfilePhotoSize.Square140, photoStream, mediaType, minWidth);
Upload(intId, ProfilePhotoSize.Square80, photoStream, mediaType, minWidth);
Upload(intId, ProfilePhotoSize.Square50, photoStream, mediaType, minWidth);
Is there a known issue with these sorts of operations, or have I maybe done something else dodgy that may be causing this?
Here is the image resizing function:
private static Stream Resize(Stream image, ResizeParameters parameters, ImageUtility.ResizeType type)
{
Image image1 = (Image) new Bitmap(image);
Image image2 = (Image) null;
Image image3 = (Image) null;
Graphics graphics = (Graphics) null;
MemoryStream memoryStream = new MemoryStream();
try
{
parameters = ImageUtility.CalculateSize(image1, parameters, type);
if (!parameters.DoNothing)
{
image2 = (Image) new Bitmap(parameters.Width, parameters.Height);
switch (type)
{
case ImageUtility.ResizeType.FixedWidth:
graphics = Graphics.FromImage(image2);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.FillRectangle(Brushes.White, 0, 0, image1.Width, image1.Height);
graphics.DrawImage(image1, 0, 0, parameters.Width, parameters.Height);
graphics.Dispose();
break;
case ImageUtility.ResizeType.PaddingSquare:
image3 = (Image) new Bitmap(parameters.SelectedWidth, parameters.SelectedHeight);
graphics = Graphics.FromImage(image3);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.FillRectangle(Brushes.White, 0, 0, parameters.SelectedWidth, parameters.SelectedHeight);
graphics.DrawImage(image1, parameters.X, parameters.Y, image1.Width, image1.Height);
graphics = Graphics.FromImage(image2);
graphics.DrawImage(image3, 0, 0, parameters.Width, parameters.Height);
graphics.Dispose();
break;
case ImageUtility.ResizeType.CropSquare:
image3 = (Image) new Bitmap(parameters.SelectedWidth, parameters.SelectedHeight);
graphics = Graphics.FromImage(image3);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.FillRectangle(Brushes.White, 0, 0, parameters.SelectedWidth, parameters.SelectedHeight);
graphics.DrawImage(image1, new Rectangle(0, 0, parameters.SelectedWidth, parameters.SelectedHeight), parameters.X, parameters.Y, image3.Width, image3.Height, GraphicsUnit.Pixel);
graphics = Graphics.FromImage(image2);
graphics.DrawImage(image3, 0, 0, parameters.Width, parameters.Height);
graphics.Dispose();
break;
}
EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, 90L);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = encoderParameter;
image2.Save((Stream) memoryStream, ImageUtility.GetEncoder(parameters.Format), encoderParams);
}
else
{
image.Seek(0L, SeekOrigin.Begin);
image.CopyTo((Stream) memoryStream);
}
memoryStream.Seek(0L, SeekOrigin.Begin);
return (Stream) memoryStream;
}
finally
{
image1.Dispose();
if (image2 != null)
image2.Dispose();
if (image3 != null)
image3.Dispose();
if (graphics != null)
graphics.Dispose();
}
}