3

I am working with sharp node package to calculate the quality of an image.

I couldn't find any API in the package which would calculate the quality.

So I came up with an implementation that follows following steps -

  1. Accept incoming image buffer & create sharp instance
  2. Create another instance from this instance by setting quality to 100
  3. Compare the size of original sharp instance and new sharp instance
  4. If there is a difference in the size, update the quality and execute step 2 with updated quality
  5. Return the quality once comparison in step 4 gives smallest difference

I tested this approach by using an image of known quality i.e. 50 (confirmed)

EDIT - I generated images with different quality values using Photoshop

However, the above logic returns the quality as 82 (expected is something close to 50)


Problem

So the problem is I am not able to figure out the quality of image.

It is fine if the above logic returns a closest value such as 49 or 51.

However the result is totally different.


Results

As per this logic, I get following results for a given quality -

  • Actual Quality 50 - Result 82
  • Actual Quality 60 - Result 90
  • Actual Quality 70 - Result 90
  • Actual Quality 80 - Result 94
  • Actual Quality 90 - Result 98
  • Actual Quality 100 - Result 98

Code

The following code snippet is used to calculate the quality.

I do understand that it is needs improvements for precise results.

But it should at least provide close values.

async function getJpegQuality(image: sharp.Sharp, min_quality: number, max_quality: number): Promise<number> {

    if (Math.abs(max_quality - min_quality) <= 1) {
        return max_quality;
    }

    const updated_image: sharp.Sharp = sharp(await image.jpeg({ quality: max_quality }).toBuffer());
    const [metadata, updated_metadata]: sharp.Metadata[] = await Promise.all([image.metadata(), updated_image.metadata()]);

    // update quality as per size comparison
    if (metadata.size > updated_metadata.size) {
        const temp_max = Math.round(max_quality);
        max_quality = Math.round((max_quality * 2) - min_quality);
        min_quality = Math.round(temp_max);
    } else {
        max_quality = Math.round((min_quality + max_quality) / 2);
        min_quality = Math.round((min_quality + max_quality) / 2);
    }

    // recursion
    return await getJpegQuality(image, min_quality, max_quality);
}

Usage

const image: sharp.Sharp = sharp(file.originalImage.buffer);
const quality = await getJpegQuality(image, 1, 100);
console.log(quality);

Thanks!

planet_hunter
  • 3,866
  • 1
  • 26
  • 39

0 Answers0