Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image quality getting bad #54

Closed
canvas-manik opened this issue Oct 16, 2015 · 15 comments
Closed

Image quality getting bad #54

canvas-manik opened this issue Oct 16, 2015 · 15 comments

Comments

@canvas-manik
Copy link

Hi,

I am new to image optimization. I just want to optimize my images tomake them small in size and dimension, but maintaining quality. I used the following code:

new Jimp("img.jpg", function (err, image) {
        if(!err){
            var origImageDim = {width:this.bitmap.width,height:this.bitmap.height};
            var dimensions = calculateImageDimensions(origImageDim.width,origImageDim.height,600,400);//Get proportionate dimensions
            var imageClone = image.clone();
            image.cover(dimensions.width, dimensions.height).write("destFolder/img.jpg", function(err, image){
                    if(!err){
                        console.log("Image optimised successfully");
                    }
                    else{
                        console.log(err);
                    }
                }
            )
        }
    }

    function calculateImageDimensions(width,height,maxWidth,maxHeight){
    // calculate the width and height, constraining the proportions
    if (width > height) {
        if (width > maxWidth) {
            height = Math.round(height *= maxWidth / width);
            width = maxWidth;
        }
    }
    else {
        if (height > maxHeight) {
            width = Math.round(width *= maxHeight / height);
            height = maxHeight;
        }
    }
    return {width:width,height:height};
}

The problem i am facing is that the quality of the resultant image is getting bad and the size (KB's) is getting bigger. Can you please help? Am I doing anything wrong?

orig-image
resultant-image

@oliver-moran
Copy link
Collaborator

Hi, @canvas-manik. A lot of these methods are provided for you:

new Jimp("large.jpg", function (err, image) {
    // resize the image to 400px high, set JPEG quality to 60, and save
    image.resize(Jimp.AUTO, 400).quality(60).write("small.jpg");
}); 

One thing you might not be aware of is the JPEG image quality (and compression) setting. Your source image appears to be at quality 70. Jimp saves at quality 100 (max) by default. Reducing this to 60 significantly brings down the KB size.

With regard to quality of appearance, any resize method is destructive and might affect appearance. Jimp uses a bi-cubic two-pass scaling algorithm, which is pretty good: https://en.wikipedia.org/wiki/Bicubic_interpolation But any scaling will (by definition) mess with your pixels.

Let me know if this works for you.

@canvas-manik
Copy link
Author

Yeah, I tried that as well. the quality is getting very bad. Even though the size might get okay. Is there some way to retain the same quality reducing the dimensions and KBs. PFA the images with 60%, 80%, 90% quality.

sujatha-4kqxh0gy-60
sujatha-4kqxh0gy-80
sujatha-4kqxh0gy-90

@oliver-moran
Copy link
Collaborator

There's a couple of possible issues.

The first thing is that it's a pretty low quality image to begin with. It looks like its been through the JPEG rinse a few times. For example, look at the artifacts in the original around the saddle, pedal and handlebars.

Secondly, resizing will mess with your pixels. You can't retake the photograph only smaller. The scaling algorithm will do its best but, by definition, if you half the size of the image, you're trying to squeeze four pixels into one. You will lose some detail in doing so. Different techniques do that differently with different outcomes but none can do the impossible.

Lastly, you're saving it again as a JPEG. That's lossy and will further will further reduce the quality:

http://petapixel.com/2010/02/04/saving-jpeg-photos-hundreds-of-times/

Taking all that into account I performed the same operation in Gimp. I compared that to the output of Jimp using PNG, JPEG, and BMP. See the output below.

Original - 535x700, 108K

original

Gimp (JPEG) - 300x400, 35K

small-gimp

Jimp (JPEG) - 300x400 31K

small-jimp

Jimp (PNG) - 300x400 307k

small-jimp

@canvas-manik
Copy link
Author

Thanks a lot Oliver for your response. Yes, you are right, while uploading the images from the browser, I am using HTML Canvas object to optimize /EXIF rotate the images before sending them to server. I am not sure what are the best practices for that. Can you share something out of your experiences?
My goal is to upload the images to my site, while doing so, I want:

  1. To reduce the size on client when the image is uploaded, to save bandwidth for user
  2. Retain quality of the images
  3. Reduce the page footprint, for that I want to make the uploaded images to smaller sizes, say a thumbnail (80 * 80)/card(400 * 400) and load the smaller sizes of images initially. Load the full size images (1000 * 700) only when required.

I am using NodeJS on the backend, and angular js on the front-end.

Any help is deeply appreciated.

Regards,
Manik Mittal

@canvas-manik
Copy link
Author

Thanks a lot Oliver,

After uploading the original images, it looks like it is working fine.

Thanks,
Manik Mittal

@iamstarkov
Copy link
Contributor

@canvas-manik can this issue be closed then?

@canvas-manik
Copy link
Author

Closing this issue, as issue is resolved.

@canvas-manik
Copy link
Author

Thanks Vladimir,

I have closed the issue.

Regards,
Manik Mittal

From: Vladimir Starkov [mailto:notifications@github.com]
Sent: Wednesday, October 28, 2015 2:44 PM
To: oliver-moran/jimp jimp@noreply.github.com
Cc: Manik Mittal manik.mittal@kanvzinc.com
Subject: Re: [jimp] Image quality getting bad (#54)

@canvas-manikhttps://github.com/canvas-manik can this issue be closed then?


Reply to this email directly or view it on GitHubhttps://github.com//issues/54#issuecomment-151775318.

@lovell
Copy link

lovell commented Nov 9, 2015

"Jimp uses a bi-cubic two-pass scaling algorithm"

@oliver-moran Hello, has jimp switched from bilinear to bicubic interpolation recently? I'll be updating sharp's performance test results soon and want to ensure I'm correctly categorising it.

@oliver-moran
Copy link
Collaborator

@lovell - No, it hasn't changed. It was the only one I could find!

I had it in my head (since Day 1) that it was bi-cubic but I may be wrong. The original project I pulled it from has been taken down and it's beyond my knowledge to tell the difference by looking at the code.

If you can tell, here's the resizer: https://github.com/oliver-moran/jimp/blob/master/resize.js

@lovell
Copy link

lovell commented Nov 10, 2015

@oliver-moran Thanks for the quick reply. https://github.com/taisel/JS-Image-Resizer looks like the (resuscitated) project you're referring to. If so, @taisel should be able to answer the bilinear vs bicubic question.

@taisel
Copy link

taisel commented Nov 16, 2015

There's two modes of scaling if you refer to the demo presented at http://taisel.github.io/JS-Image-Resizer/

One is bilinear, another is neither, but results in preserving the image crispness (it looks like nearest neighbor integer upscale+bilinear for a comparable end result). Downscaling is always the custom algorithm, since the algorithm is equivalent to multiple passes of bilinear limited to 2x downscaling in each pass, so it doesn't miss a source input pixel. That's emphasized in the demo with one of the images shown (context2d uses bilinear usually). If you downscaled with context2d (presuming bilinear) multiple times in a ratio of no more than 2x to get the same final image size, you'd get the same result as the custom algorithm.

I hope I explained the peculiarities here.

@taisel
Copy link

taisel commented Nov 16, 2015

If you all want bicubic as an upscaling algorithm, or want to propose another downscaling mode of operation, feel free to chime in. That resizing project is ancient and in need of update. It was done as an experiment, and is in public domain, as it was done in free time.

@taisel
Copy link

taisel commented Nov 16, 2015

Looking at JIMP's code, bilinear is being used instead of the custom algorithm for upscaling. As in, interpolation is being explicitly requested with "true". Also, if you're constantly rescaling the image over and over to the same dimensions (like streaming video through the library), the Resize object can be retained across multiple calls. It's also not recommended to enable web worker usage, since in practice it's slower than same thread (The code is so old it was made before transferable objects were a thing).

@lovell
Copy link

lovell commented Nov 17, 2015

Thanks for the detailed information @taisel!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants