Question

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();
  }
}

No correct solution

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top