Image scaling causes poor quality in firefox/internet explorer but not chrome

123,347

Solution 1

It seems that you are right. No option scales the image better:
http://www.maxrev.de/html/image-scaling.html

I've tested FF14, IE9, OP12 and GC21. Only GC has a better scaling that can be deactivated through image-rendering: -webkit-optimize-contrast. All other browsers have no/poor scaling.

Screenshot of the different output: http://www.maxrev.de/files/2012/08/screenshot_interpolation_jquery_animate.png

Update 2017

Meanwhile some more browsers support smooth scaling:

  • ME38 (Microsoft Edge) has good scaling. It can't be disabled and it works for JPEG and PNG, but not for GIF.

  • FF51 (Regarding @karthik 's comment since FF21) has good scaling that can be disabled through the following settings:

    image-rendering: optimizeQuality
    image-rendering: optimizeSpeed
    image-rendering: -moz-crisp-edges
    

    Note: Regarding MDN the optimizeQuality setting is a synonym for auto (but auto does not disable smooth scaling):

    The values optimizeQuality and optimizeSpeed present in early draft (and coming from its SVG counterpart) are defined as synonyms for the auto value.

  • OP43 behaves like GC (not suprising as it is based on Chromium since 2013) and its still this option that disables smooth scaling:

    image-rendering: -webkit-optimize-contrast
    

No support in IE9-IE11. The -ms-interpolation-mode setting worked only in IE6-IE8, but was removed in IE9.

P.S. Smooth scaling is done by default. This means no image-rendering option is needed!

Solution 2

Late answer but this works:

/* applies to GIF and PNG images; avoids blurry edges */
img[src$=".gif"], img[src$=".png"] {
    image-rendering: -moz-crisp-edges;         /* Firefox */
    image-rendering:   -o-crisp-edges;         /* Opera */
    image-rendering: -webkit-optimize-contrast;/* Webkit (non-standard naming) */
    image-rendering: crisp-edges;
    -ms-interpolation-mode: nearest-neighbor;  /* IE (non-standard property) */
}

https://developer.mozilla.org/en/docs/Web/CSS/image-rendering

Here is another link as well which talks about browser support:

https://css-tricks.com/almanac/properties/i/image-rendering/

Solution 3

One way to "normalize" the appearance in the different browsers is using your "server-side" to resize the image. An example using a C# controller:

public ActionResult ResizeImage(string imageUrl, int width)
{
    WebImage wImage = new WebImage(imageUrl);
    wImage = WebImageExtension.Resize(wImage, width);
    return File(wImage.GetBytes(), "image/png");
}

where WebImage is a class in System.Web.Helpers.

WebImageExtension is defined below:

using System.IO;
using System.Web.Helpers;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Collections.Generic;

public static class WebImageExtension
{
    private static readonly IDictionary<string, ImageFormat> TransparencyFormats =
        new Dictionary<string, ImageFormat>(StringComparer.OrdinalIgnoreCase) { { "png", ImageFormat.Png }, { "gif", ImageFormat.Gif } };

    public static WebImage Resize(this WebImage image, int width)
    {
        double aspectRatio = (double)image.Width / image.Height;
        var height = Convert.ToInt32(width / aspectRatio);

        ImageFormat format;

        if (!TransparencyFormats.TryGetValue(image.ImageFormat.ToLower(), out format))
        {
            return image.Resize(width, height);
        }

        using (Image resizedImage = new Bitmap(width, height))
        {
            using (var source = new Bitmap(new MemoryStream(image.GetBytes())))
            {
                using (Graphics g = Graphics.FromImage(resizedImage))
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.DrawImage(source, 0, 0, width, height);
                }
            }

            using (var ms = new MemoryStream())
            {
                resizedImage.Save(ms, format);
                return new WebImage(ms.ToArray());
            }
        }
    }
}

note the option InterpolationMode.HighQualityBicubic. This is the method used by Chrome.

Now you need publish in a web page. Lets going use razor:

<img src="@Url.Action("ResizeImage", "Controller", new { urlImage = "<url_image>", width = 35 })" />

And this worked very fine to me!

Ideally will be better to save the image beforehand in diferent widths, using this resize algorithm, to avoid the controller process in every image load.

(Sorry for my poor english, I'm brazilian...)

Solution 4

Your problem is that you are relying on the browser to resize your images. Browsers have notoriously poor image scaling algorithms, which will cause the ugly pixelization.

You should resize your images in a graphics program first before you use them on the webpage.

Also, you have a spelling mistake: it should say moz-crisp-edges; however, that won't help you in your case (because that resizing algorithm won't give you a high quality resize: https://developer.mozilla.org/En/CSS/Image-rendering)

Solution 5

You should try to maintain a proper aspect ratio between the sizes you're scaling from and to. For example, if your target size is 28px, then your source size should be a power of that, such as 56 (28 x 2) or 112 (28 x 4). This ensures you can scale by 50% or 25% rather than the 0.233333% you're currently using.

Share:
123,347
Andrew Rasmussen
Author by

Andrew Rasmussen

Founder of Canny. Used to work on ReactJS at Facebook.

Updated on August 30, 2020

Comments

  • Andrew Rasmussen
    Andrew Rasmussen almost 4 years

    See http://jsfiddle.net/aJ333/1/ in Chrome and then in either Firefox or Internet Explorer. The image is originally 120px, and I'm scaling down to 28px, but it looks bad pretty much no matter what you scale it down to.

    The image is a PNG and it has an alpha channel (transparency).

    Here's the relevant code:

    HTML:

    <a href="http://tinypic.com?ref=2z5jbtg" target="_blank">
        <img src="http://i44.tinypic.com/2z5jbtg.png" border="0" alt="Image and video hosting by TinyPic">
    </a>​
    

    CSS:

    a {
        width: 28px;
        height: 28px;
        display: block;
    }
    
    img {
        max-width: 100%;
        max-height: 100%;
        image-rendering: -moz-crisp-edges;
        -ms-interpolation-mode: bicubic;
    }
    

    The image-rendering and -ms-interpolation-mode lines of CSS didn't seem to do anything, but I found them online while doing some research on the problem.

  • andrewdotnich
    andrewdotnich about 12 years
    This is true, but it does make it incredibly hard to visualize bigger image bounding boxes while keeping the existing placeholder image…
  • Peter Burns
    Peter Burns over 11 years
    confirmed in IE10 for sure, although Google Chrome does smooth the downsized images for me in the latest version. All browsers should do this. So frustrating!
  • Sami Ahmed Siddiqui
    Sami Ahmed Siddiqui over 11 years
    Given recent developments in reactive web design, this is no longer on option. These days, a reactive design often employs larger images and then scales them down to meet whatever mediaquery breakpoints are set in the CSS.
  • Sami Ahmed Siddiqui
    Sami Ahmed Siddiqui over 11 years
    Similarly, the only way to achieve crisp images on high DPI displays like the retina displays on iphones and ipads is to create an image that is twice as large and scale it to 50%.
  • Mahdi
    Mahdi over 11 years
    While I don't agree with the retina argument (you should only serve retina images when needed), there are plenty of other situations scaling will happen. Like any time you have an animation that involves resizing.
  • Learning
    Learning almost 11 years
    Where is using System.Web.Helpers; it generates error do we need to download any library for this..
  • F Lekschas
    F Lekschas almost 11 years
    I've tested it in FF3.6 and both (JPG+PNG) look as good as in the current version of Chrome (29) without any CSS option. Could you explain why scaling should be bad?
  • Nathan Crause
    Nathan Crause over 9 years
    Not a valid solution if you have an image in a responsive website which needs to dynamically scale. unless you propose a scaled image for every single possible resolution, in which case you're going to increase your load-time.
  • LessQuesar
    LessQuesar over 9 years
    This isn't a fix for browser rendering. Its one solution among a gazillion that can resize the image on the server.
  • gdibble
    gdibble over 9 years
    good point when that is possible, however some users will upload strange proportions in large user use-cases
  • user3338098
    user3338098 almost 9 years
    downsampling only makes the problem worse, the point is to use a large image and then have the browser scale down to subpixel resolutions to prevent pixilation, yet browsers don't appear to do that properly.
  • andrew.butkus
    andrew.butkus over 8 years
    this doesnt answer the original question as the question was to do with the quality of an image when downscaled in certain browsers, and this relates to best web practices when considering future proofing.
  • Antony D'Andrea
    Antony D'Andrea over 7 years
    Problem with this solution is that it previously looked fine in other browsers and then they all look rubbish.
  • mgutt
    mgutt over 7 years
    @FLekschas I retested all browsers and Firefox supports now a good scaling. Microsoft Edge, too.
  • ganders
    ganders about 7 years
    so what is the resolution for this, create a version of the png file that is 28px tall so it doesn't have to scale in the anchor element?
  • trysis
    trysis about 7 years
    I wonder how feasible it would be to do this, then have a function on the client that goes back to the server to do all this again whenever it thinks the image might be resized. Right now (2017) this is only needed on Internet Explorer, but still.
  • Andrew Rasmussen
    Andrew Rasmussen almost 7 years
    It's so funny that in 2017 the solution is to rotate the image by enough that it gets rendered differently by the browser but isn't noticeable to the user... so hacky