112

How can I resize an image, with the image quality unaffected?

Nick Gallimore
  • 1,222
  • 13
  • 31
public static
  • 12,702
  • 26
  • 66
  • 86

11 Answers11

222

As rcar says, you can't without losing some quality, the best you can do in c# is:

Bitmap newImage = new Bitmap(newWidth, newHeight);
using (Graphics gr = Graphics.FromImage(newImage))
{
    gr.SmoothingMode = SmoothingMode.HighQuality;
    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
    gr.DrawImage(srcImage, new Rectangle(0, 0, newWidth, newHeight));
}
Community
  • 1
  • 1
Kris Erickson
  • 33,454
  • 26
  • 120
  • 175
  • 3
    I might add that (if possible) the user should start with a Bitmap image that is, say, twice as large as it needs to be and then scale down. The resulting image should be pretty smooth. – Pretzel Nov 21 '08 at 20:54
  • +1 for scale down. never up, whilst you can scale up, even coding an unsharp mask will not get you a good result. – Mauro Nov 05 '10 at 08:54
  • 2
    gr.SmoothingMode = SmoothingMode.HighQuality is better code. Currently, HighQuality and AntiAlias are the same thing, but maybe in the future Microsoft will invent something new. HighQuality should always be an alias for the best. – Eyal Jul 25 '12 at 17:17
  • 6
    Method 'System.Drawing.Image.Save(string filename, ImageFormat format)' saves JPGs with quality 75. The image was blurry and not acceptable by the client. What fixed the quality issue was to use Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams) instead and specify a quality value closer to 100. – Ricardo stands with Ukraine Oct 08 '13 at 15:27
  • 3
    This leaves artifacts on the border of the image sometimes... – jjxtra Jan 21 '14 at 05:45
  • 1
    I had artifacts on the border on using this. Any suggesstions? – Gopichandar Apr 08 '15 at 12:56
  • Is there a method to make it like http://i.imgur.com/RSjRttp.png to resize with blur effect? – Roar May 10 '16 at 09:40
  • @Roar there is no built in method for doing something like, you can certainly do it with a bit of code, but that would be a whole new SO question. – Kris Erickson May 11 '16 at 16:28
32

Unless you're doing vector graphics, there's no way to resize an image without potentially losing some image quality.

Randy
  • 3,972
  • 19
  • 25
26
private static Image resizeImage(Image imgToResize, Size size)
{
    int sourceWidth = imgToResize.Width;
    int sourceHeight = imgToResize.Height;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)size.Width / (float)sourceWidth);
    nPercentH = ((float)size.Height / (float)sourceHeight);

    if (nPercentH < nPercentW)
        nPercent = nPercentH;
    else
        nPercent = nPercentW;

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Bitmap b = new Bitmap(destWidth, destHeight);
    Graphics g = Graphics.FromImage((Image)b);
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;

    g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
    g.Dispose();

    return (Image)b;
}

from here

Rémi
  • 3,867
  • 5
  • 28
  • 44
ozba
  • 6,522
  • 4
  • 33
  • 40
5

I believe what you're looking to do is "Resize/Resample" your images. Here is a good site that gives instructions and provides a utility class(That I also happen to use):

http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx

Ashlocke
  • 1,477
  • 4
  • 15
  • 13
3

You can't resize an image without losing some quality, simply because you are reducing the number of pixels.

Don't reduce the size client side, because browsers don't do a good job of resizing images.

What you can do is programatically change the size before you render it, or as a user uploads it.

Here is an article that explains one way to do this in c#: http://www.codeproject.com/KB/GDI-plus/imageresize.aspx

AaronS
  • 7,649
  • 5
  • 30
  • 56
  • "browsers don't do a good job of resizing images" - this might have been true in '08, but luckily we're miles ahead in this area now (to a great extent due to old IE versions slowly fading away). – Camilo Martin Feb 15 '13 at 12:23
3

Unless you resize up, you cannot do this with raster graphics.

What you can do with good filtering and smoothing is to resize without losing any noticable quality.

You can also alter the DPI metadata of the image (assuming it has some) which will keep exactly the same pixel count, but will alter how image editors think of it in 'real-world' measurements.

And just to cover all bases, if you really meant just the file size of the image and not the actual image dimensions, I suggest you look at a lossless encoding of the image data. My suggestion for this would be to resave the image as a .png file (I tend to use paint as a free transcoder for images in windows. Load image in paint, save as in the new format)

workmad3
  • 25,101
  • 4
  • 35
  • 56
2

Here you can find also add watermark codes in this class :

public class ImageProcessor
    {
        public Bitmap Resize(Bitmap image, int newWidth, int newHeight, string message)
        {
            try
            {
                Bitmap newImage = new Bitmap(newWidth, Calculations(image.Width, image.Height, newWidth));

                using (Graphics gr = Graphics.FromImage(newImage))
                {
                    gr.SmoothingMode = SmoothingMode.AntiAlias;
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    gr.DrawImage(image, new Rectangle(0, 0, newImage.Width, newImage.Height));

                    var myBrush = new SolidBrush(Color.FromArgb(70, 205, 205, 205));

                    double diagonal = Math.Sqrt(newImage.Width * newImage.Width + newImage.Height * newImage.Height);

                    Rectangle containerBox = new Rectangle();

                    containerBox.X = (int)(diagonal / 10);
                    float messageLength = (float)(diagonal / message.Length * 1);
                    containerBox.Y = -(int)(messageLength / 1.6);

                    Font stringFont = new Font("verdana", messageLength);

                    StringFormat sf = new StringFormat();

                    float slope = (float)(Math.Atan2(newImage.Height, newImage.Width) * 180 / Math.PI);

                    gr.RotateTransform(slope);
                    gr.DrawString(message, stringFont, myBrush, containerBox, sf);
                    return newImage;
                }
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        public int Calculations(decimal w1, decimal h1, int newWidth)
        {
            decimal height = 0;
            decimal ratio = 0;


            if (newWidth < w1)
            {
                ratio = w1 / newWidth;
                height = h1 / ratio;

                return height.To<int>();
            }

            if (w1 < newWidth)
            {
                ratio = newWidth / w1;
                height = h1 * ratio;
                return height.To<int>();
            }

            return height.To<int>();
        }

    }
cagin
  • 5,772
  • 14
  • 74
  • 130
2

See if you like the image resizing quality of this open source ASP.NET module. There's a live demo, so you can mess around with it yourself. It yields results that are (to me) impossible to distinguish from Photoshop output. It also has similar file sizes - MS did a good job on their JPEG encoder.

  • Well, JPEG is a relatively straightforward format. There's not much you can do to beat reference implementations in terms of quality/filesize because at the end it's just DCT coefficients with generic compression. – Camilo Martin Feb 15 '13 at 12:20
1

There is something out there, context aware resizing, don't know if you will be able to use it, but it's worth looking at, that's for sure

A nice video demo (Enlarging appears towards the middle) http://www.youtube.com/watch?v=vIFCV2spKtg

Here there could be some code. http://www.semanticmetadata.net/2007/08/30/content-aware-image-resizing-gpl-implementation/

Was that overkill? Maybe there are some easy filters you can apply to an enlarged image to blur the pixels a bit, you could look into that.

Victor
  • 9,210
  • 3
  • 26
  • 39
1

Are you resizing larger, or smaller? By a small % or by a larger factor like 2x, 3x? What do you mean by quality for your application? And what type of images - photographs, hard-edged line drawings, or what? Writing your own low-level pixel grinding code or trying to do it as much as possible with existing libraries (.net or whatever)?

There is a large body of knowledge on this topic. The key concept is interpolation.

Browsing recommendations:
* http://www.all-in-one.ee/~dersch/interpolator/interpolator.html
* http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
* for C#: https://secure.codeproject.com/KB/GDI-plus/imageprocessing4.aspx?display=PrintAll&fid=3657&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=26&select=629945 * this is java-specific but might be educational - http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

DarenW
  • 16,549
  • 7
  • 63
  • 102
0

Here is a forum thread that provides a C# image resizing code sample. You could use one of the GD library binders to do resampling in C#.

jimg
  • 484
  • 6
  • 12