Maludasek Maludasek - 1 month ago 41
ASP.NET (C#) Question

C# async Bitmap resize

I want to do async task for Bitmap resizing. I thought i would add await to Graphics.DrawImage or Bitmap.Save but i can't. Here is my code:

Controller:

//public async System.Threading.Tasks.Task<ActionResult> AddPicture(int? id, HttpPostedFileBase file)
[HttpPost]
public ActionResult AddPicture(int? id, HttpPostedFileBase file)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Product product = db.Products.Find(id);
if (product == null)
{
return HttpNotFound();
}
if (file != null && file.ContentLength > 0)
{
string extension = Path.GetExtension(file.FileName);
if (extension != ".jpg")
{
ModelState.AddModelError("jpg", "Error");
}
else
{
// file stream to byte[]
MemoryStream target = new MemoryStream();
file.InputStream.CopyTo(target);
byte[] TempByteArray = target.ToArray();
// byte[] to Bitmap
ImageConverter imageConverter = new ImageConverter();
Image TempImage = (Image)imageConverter.ConvertFrom(TempByteArray);
Bitmap FinalBitmap = new Bitmap(TempImage);
Bitmap Thumbnail = ResizeImage(FinalBitmap, 150, 150);
Bitmap FullPicture = ResizeImage(FinalBitmap, 800, 600);
var ThumbnailPath = Path.Combine(Server.MapPath("~/Content/Images/Thumbnails/"), product.ProductCode + ".jpg");
Thumbnail.Save(ThumbnailPath, ImageFormat.Jpeg);
var FullPicturePath = Path.Combine(Server.MapPath("~/Content/Images/"), product.ProductCode + ".jpg");
FullPicture.Save(FullPicturePath, ImageFormat.Jpeg);
}
}
else
{
ModelState.AddModelError("missingfile", "Error");
}
return View(product);
}


Resize function:

public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

double ratioW = (double)width / (double)image.Width;
double ratioH = (double)height / (double)image.Height;
double ratio = ratioW < ratioH ? ratioW : ratioH;
int insideWidth = (int)(image.Width * ratio);
int insideHeight = (int)(image.Height * ratio);

using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
//graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
graphics.DrawImage(image, new Rectangle((width / 2) - (insideWidth / 2), (height / 2) - (insideHeight / 2), insideWidth, insideHeight), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}


Is there anything i can do to make it async?

Thanx

Answer

I assume you are looking for something like this, see the article below for details:

Creating an Asynchronous Gizmos Action Method

public async Task<ActionResult> GizmosAsync()
{ 
    ViewBag.SyncOrAsync = "Asynchronous";
    var gizmoService = new GizmoService();
    return View("Gizmos", await gizmoService.GetGizmosAsync());
}

In order to make something like that work in your case you would need to either wrap your method(s) inside a

await Task.Run(()=>{  ... DrawImage() ... })

or

you need to use an Async method version instead of your normal sync method for image processing (for example graphics.DrawImageAsync if it exists) - unfortunately I don't believe the *Async version of the method is available so your only option is to spawn a new task (which will run on a thread pool thread).

Your changes would look something like this (I only modified the async/await parts):

public async Task<ActionResult> AddPicture(int? id, HttpPostedFileBase file)
{
    ....
            Bitmap Thumbnail = await ResizeImage(FinalBitmap, 150, 150);
            Bitmap FullPicture = await ResizeImage(FinalBitmap, 800, 600);
    ....
}


public async Task<Bitmap> ResizeImage(Image image, int width, int height)
{
    ....
            await Task.Run(()=>{ graphics.DrawImage(....) });
    ...

}

Comments