Gloria
Gloria

Reputation: 1325

How to resize an image with System Drawing and lower the image size

I'm using the following code to resize images on upload. The problem is that the new image size is big. I tried changing the interpolation to low and the composition quality the High Speed but nothing seems to work. Sometimes the new smaller and resized image is as big in file size as its original uploaded image. There are other properties to use for the System.Drawing.Drawing2D but which one can affect the file size? any tips?

private static Bitmap ResizeBitmap(Bitmap b, int nWidth)
{
    int nHeight = CalculateProportionalHeight(b.Width, b.Height, nWidth);
    Bitmap result = new Bitmap(nWidth, nHeight);
    result.SetResolution(72.0F, 72.0F);


    Graphics g = Graphics.FromImage((System.Drawing.Image)result);

    g.InterpolationMode = InterpolationMode.Low;
    g.CompositingQuality = CompositingQuality.HighSpeed; 
    g.DrawImage(b, 0, 0, nWidth, nHeight);


    return result;
}

Upvotes: 1

Views: 11337

Answers (1)

Ty H.
Ty H.

Reputation: 953

In my original answer I posted this code assuming that it was not having the same issue you were with file size inflation... I was wrong. So after some tinkering, I realized that my JPG images were being saved with a JPG extension... but encoded as PNG, thus the increase in file size. Here is an updated codebase, tested reliable with PNG, GIF, and JPG. The file size will be lower when the image is smaller than the original.

First a basic method that takes a Bitmap and resizes it.

public static Bitmap Resize(Bitmap imgPhoto, Size objSize, ImageFormat enuType)
{
    int sourceWidth = imgPhoto.Width;
    int sourceHeight = imgPhoto.Height;
    int sourceX = 0;
    int sourceY = 0;

    int destX = 0;
    int destY = 0;
    int destWidth = objSize.Width;
    int destHeight = objSize.Height;

    Bitmap bmPhoto;
    if (enuType == ImageFormat.Png)
        bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format32bppArgb);
    else if (enuType == ImageFormat.Gif)
        bmPhoto = new Bitmap(destWidth, destHeight); //PixelFormat.Format8bppIndexed should be the right value for a GIF, but will throw an error with some GIF images so it's not safe to specify.
    else
        bmPhoto = new Bitmap(destWidth, destHeight, PixelFormat.Format24bppRgb);

    //For some reason the resolution properties will be 96, even when the source image is different, so this matching does not appear to be reliable.
    //bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

    //If you want to override the default 96dpi resolution do it here
    //bmPhoto.SetResolution(72, 72);

    Graphics grPhoto = Graphics.FromImage(bmPhoto);
    grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
    grPhoto.DrawImage(imgPhoto,
        new Rectangle(destX, destY, destWidth, destHeight),
        new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
        GraphicsUnit.Pixel);

    grPhoto.Dispose();
    return bmPhoto;
}

Here's how to use the Resize method...

   String strImageFile = Server.MapPath("/Images/ImageFile.jpg");
   System.Drawing.Bitmap objImage = new System.Drawing.Bitmap(strImageFile);
   System.Drawing.Size objNewSize = new System.Drawing.Size(100, 50);
   System.Drawing.Bitmap objNewImage = Resize(objImage, objNewSize, ImageFormat.Jpeg);
   objNewImage.Save(Server.MapPath("/Images/FileName_Resized.jpg"), ImageFormat.Jpeg);
   objNewImage.Dispose();

This method adds a layer of complexity, you can define a maximum size constraint, and the method will Resize the image to stay in proportion... but be no larger than... the maximum size. It will leave the image alone if it is less than or equal to the max size, returning the original Bitmap instead.

public static Bitmap SmartResize(string strImageFile, Size objMaxSize, ImageFormat enuType)
{
    Bitmap objImage = null;
    try
    {
        objImage = new Bitmap(strImageFile);
    }
    catch (Exception ex)
    {
        throw ex;
    }

    if (objImage.Width > objMaxSize.Width || objImage.Height > objMaxSize.Height)
    {
        Size objSize;
        int intWidthOverrun = 0;
        int intHeightOverrun = 0;
        if (objImage.Width > objMaxSize.Width)
            intWidthOverrun = objImage.Width - objMaxSize.Width;
        if (objImage.Height > objMaxSize.Height)
            intHeightOverrun = objImage.Height - objMaxSize.Height;

        double dblRatio;
        double dblWidthRatio = (double)objMaxSize.Width / (double)objImage.Width;
        double dblHeightRatio = (double)objMaxSize.Height / (double)objImage.Height;
        if (dblWidthRatio < dblHeightRatio)
            dblRatio = dblWidthRatio;
        else
            dblRatio = dblHeightRatio;
        objSize = new Size((int)((double)objImage.Width * dblRatio), (int)((double)objImage.Height * dblRatio));

        Bitmap objNewImage = Resize(objImage, objSize, enuType);

        objImage.Dispose();
        return objNewImage;
    }
    else
    {
        return objImage;
    }
}

Here's how to implement it...

String strImageFile = Server.MapPath("/Images/ImageFile.png");
System.Drawing.Size objMaxSize = new System.Drawing.Size(100, 100);
System.Drawing.Bitmap objNewImage = SmartResize(strImageFile, objMaxSize, ImageFormat.Png);
objNewImage.Save(Server.MapPath("/Images/FileName_Resized.png"), ImageFormat.Png);
objNewImage.Dispose();

Upvotes: 1

Related Questions