RWS / dxa-web-application-java

SDL Digital Experience Accelerator Java Spring MVC web application
25 stars 37 forks source link

Images looses quality when resizing #14

Open prateek508 opened 8 years ago

prateek508 commented 8 years ago

We have noticed that the picture loses quality when resizing. The reason for this disparity in quality is due to the different filtering algorithms in use. If downscaling by more than two times, the BILINEAR and BICUBIC algorithms tend to lose information due to the way pixels are sampled from the source image; the older AreaAveragingFilter algorithm used by Image.getScaledInstance() is quite different and does not suffer from this problem as much, but it requires much more processing time in general.

To combat this issue, you can use a multi-step approach when downscaling by more than two times; this helps prevent the information loss issue and produces a much higher quality result.

You need to use several resizing steps in order to get a good image. The helper method for scaling image is below.

  public static BufferedImage getScaledInstance(BufferedImage img,
        int targetWidth, int targetHeight, int type, boolean higherQuality) {
    BufferedImage ret = (BufferedImage) img;
    int w, h;
    if (higherQuality) {
        // Use multi-step technique: start with original size, then
        // scale down in multiple passes with drawImage()
        // until the target size is reached
        w = img.getWidth();
        h = img.getHeight();
    } else {
        // Use one-step technique: scale directly from original
        // size to target size with a single drawImage() call
        w = targetWidth;
        h = targetHeight;
    }
    do {
        if (higherQuality && w > targetWidth) {
            w /= 2;
            if (w < targetWidth) {
                w = targetWidth;
            }
        }
        if (higherQuality && h > targetHeight) {
            h /= 2;
            if (h < targetHeight) {
                h = targetHeight;
            }
        }

        BufferedImage tmp = new BufferedImage(w, h, type);
        Graphics2D g2 = tmp.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        g2.setRenderingHint(RenderingHints.KEY_RENDERING,
                RenderingHints.VALUE_RENDER_QUALITY);
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g2.drawImage(ret, 0, 0, w, h, null);
        g2.dispose();

        ret = tmp;
    } while (w != targetWidth || h != targetHeight);

    return ret;
}

Attached images showing original image resized using single shot and new improved iterative method. The image quality is improved visually. highquality lowquality

jhorsman commented 8 years ago

Intresting one Prateek. DXA has two methods of image resizing, with SDL CID (the CID Maven profile in the dxa-example-webapp) or the default DD4T resizing. Which one did you use?

p.s. could you format the code blocks in your issue description? see https://guides.github.com/features/mastering-markdown/

prateek508 commented 8 years ago

Hi Jan, We found this in default DD4T resizing. When using above helper method using iteartive approach to downsize image, the quality gets improved visually as seen in the images above. Thanks.

jhorsman commented 8 years ago

I think this issue would be a good addition to https://github.com/dd4t/dd4t-2-java/issues

prateek508 commented 8 years ago

Ok. I will add it. Thanks

rpannekoek commented 7 years ago

TSI-1941 (internal issue ID for tracking purposes)