Home Precisely scale image
Reply: 3

Precisely scale image

just.me Published in 2017-11-14 17:48:20Z

I am trying to precisely and predictably scale an image in C# to a different resolution, both up and down. When I open the resulting images with external tools such as Gimp, the results are not satisfying with my current settings.

public Image Square(Image image, int res) {
    Bitmap sq = new Bitmap(res, res, image.PixelFormat);
    Graphics canvas = Graphics.FromImage(sq);
    canvas.CompositingQuality = CompositingQuality.HighQuality;
    canvas.SmoothingMode = SmoothingMode.None;
    canvas.InterpolationMode = InterpolationMode.Bicubic;
    canvas.DrawImage(sq, 0, 0, res, res);
    return sq;

The results are okay when scaling down (but far from perfect), but there are side-effects when scaling up:

This picture has a resolution of 2x2 pixels. The alpha channel is set to opaque for all pixels.

After scaling it to 4x4 pixels, this is the result:

Apparently, the C# graphics library introduced transparency while scaling the picture. This method should still work if the given image has transparent pictures, so removing the alpha channel is not an option.

Similarly, when scaling pictures down, there are problems at the edges of the resulting images as well, usually either very dark or transparent.

Is there any way to circumvent this behavior?

Edit: I already tried NearestNeighbor for downscaling only, but it results in this:

Edit 2: With WrapMode.TileFlipXY, the transparent edge is gone, but red only makes up 25% of the image instead of 50% as it should be:

tadman Reply to 2017-11-14 17:51:56Z

You're asking for bicubic interpolation and you're getting it. What you want is the "nearest neighbor" option as outlined in the docs:

canvas.InterpolationMode = InterpolationMode.NearestNeighbor;
j4nw Reply to 2017-11-14 18:21:03Z

A way to avoid edge artifacts is to wrap the image:

using (ImageAttributes wrapMode = new ImageAttributes())
    g.DrawImage(input, rect, 0, 0, input.Width, input.Height, GraphicsUnit.Pixel, wrapMode);

Direct copy/paste from:

Ghost-borders ('ringing') when resizing in GDI+

Derrick Moeller
Derrick Moeller Reply to 2017-11-14 18:43:58Z

I believe you need to combine NearestNeighbor interpolation with Half pixel offset. As pointed out in a similar question here.

canvas.InterpolationMode = InterpolationMode.NearestNeighbor;
canvas.PixelOffsetMode = PixelOffsetMode.Half;
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.323693 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO