Cloudinary Blog

JPEG Image Optimization Without Compromising Quality With JPEGmini and Cloudinary

JPEG Image Optimization Without Losing Quality

Image optimization is an important step to reducing page load times, improving user experience and reducing bandwidth costs. When using the JPEG image format, which is best used for photos, the most common optimization is controlling the JPEG quality level.

By lowering JPEG quality, say to 90%, 80% or even 50%, you'll get much smaller JPEG files. But will image quality be good enough? JPEG optimization is tricky because if quality is too low, you'll get blurry images, pixelation and visible compression artifacts; if it's too high, images will look good but take too long to load.

We thought it would be great to let our users automatically optimize their JPEGs without sacrificing quality. So we partnered with JPEGmini, an online service that does exactly that - it smartly balances the need to reduce file size, with the need to deliver high quality visual results. JPEGmini's JPEG optimization can reduce the file size of your photos by up to 5x, while maintaining their original quality.

We've integrated JPEGmini with our cloud-based image management solution, allowing our users to generate JPEGs on the fly with JPEGmini’s smart optimization built in. Read on to see how it's done.


Sign up for Cloudinary free today!


Optimizing JPEG images while maintaining high image quality

Cloudinary is a cloud-based, end-to-end media management solution that automates and streamlines your entire media asset workflow, from upload to manipulation to delivery via multiple CDNs.

One of the image manipulations we offer is changing JPEG quality. Let's take a JPG image of a dog that was uploaded to Cloudinary, and assigned the ID 'happy_dog'.

The original image is a high-resolution photo of 2082x2975. Is was saved as high-quality JPG and weighs 2.5MB, which is quite a lot of data to deliver to your web or mobile viewers.

Cloudinary allows you to modify the quality level of a JPG by setting the quality parameter (or q if specified within the image URL) to a value between 1 to 100. In addition, further lossless optimizations are applied to the generated images. The following code, or dynamic manipulation URL, converts the original image on-the-fly to a JPEG with 90% quality (for illustration purposes, the image below was resized to a 250x358 thumbnail). The generated image weighs only 681KB, which is just 19% of the original high-quality size:

Ruby:
Copy to clipboard
cl_image_tag("happy_dog.jpg", :quality=>90)
PHP v1:
Copy to clipboard
cl_image_tag("happy_dog.jpg", array("quality"=>90))
PHP v2:
Copy to clipboard
(new ImageTag('happy_dog.jpg'))
  ->delivery(Delivery::quality(90));
Python:
Copy to clipboard
CloudinaryImage("happy_dog.jpg").image(quality=90)
Node.js:
Copy to clipboard
cloudinary.image("happy_dog.jpg", {quality: 90})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().quality(90)).imageTag("happy_dog.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('happy_dog.jpg', {quality: 90}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("happy_dog.jpg", {quality: 90})
React:
Copy to clipboard
<Image publicId="happy_dog.jpg" >
  <Transformation quality="90" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="happy_dog.jpg" >
  <cld-transformation quality="90" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="happy_dog.jpg" >
  <cl-transformation quality="90">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality(90)).BuildImageTag("happy_dog.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().quality(90)).generate("happy_dog.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality(90)).generate("happy_dog.jpg")!, cloudinary: cloudinary)
JPEG with quality 90%

In the example above we used 90% quality, which is quite high and ensures a good visual result. However, for photos like the one above, you may be able to set a lower JPEG quality level while is indiscernible from the original to the naked eye. Using Cloudinary's new JPEGmini add-on, you can apply a JPEG optimization with the best possible quality for the specific photo you've uploaded.

Applying JPEGmini optimization is done by simply setting the quality parameter, in the code that generates the image URL, to jpegmini. The following manipulation URL and code optimizes an image uploaded to Cloudinary using JPEGmini, while delivering the result via a CDN. The resulting photo weighs only 425KB. This means we saved almost 40% of file size compared to the 90 quality JPG or more than 80% compared to the original photo. Across an entire site, this can significantly improve user experience and minimize bandwidth costs.

Ruby:
Copy to clipboard
cl_image_tag("happy_dog.jpg", :quality=>"jpegmini", :sign_url=>true)
PHP v1:
Copy to clipboard
cl_image_tag("happy_dog.jpg", array("quality"=>"jpegmini", "sign_url"=>true))
PHP v2:
Copy to clipboard
(new ImageTag('happy_dog.jpg'))
  ->delivery(Delivery::quality(Quality::jpegmini()))
  ->signUrl(true);
Python:
Copy to clipboard
CloudinaryImage("happy_dog.jpg").image(quality="jpegmini", sign_url=True)
Node.js:
Copy to clipboard
cloudinary.image("happy_dog.jpg", {quality: "jpegmini", sign_url: true})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().quality("jpegmini")).signed(true).imageTag("happy_dog.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('happy_dog.jpg', {quality: "jpegmini", signUrl: true}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("happy_dog.jpg", {quality: "jpegmini"})
React:
Copy to clipboard
<Image publicId="happy_dog.jpg" signUrl="true">
  <Transformation quality="jpegmini" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="happy_dog.jpg" signUrl="true">
  <cld-transformation quality="jpegmini" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="happy_dog.jpg" sign-url="true">
  <cl-transformation quality="jpegmini">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("jpegmini")).Signed(true).BuildImageTag("happy_dog.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().quality("jpegmini")).signed(true).generate("happy_dog.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality("jpegmini")).generate("happy_dog.jpg", signUrl: true)!, cloudinary: cloudinary)
JPEGMini optimized photo

As you can see, the generated photo looks identical to the original photo, which weighs so much more.

The thumbnails above were generated on-the-fly by Cloudinary, by specifying the width and height parameters - this is an easy way to automatically create thumbnails of large images for your site or mobile app.

Note that the 250x358 thumbnail optimized by JPEGmini weighs only 15.9KB, which means saving almost 50% of file size compared to a 90 quality version of the same thumbnail which weighs 30.2KB, while the results seem identical to the human eye.

Ensuring high visual quality for all images

Reducing file size, and thus improving user experience and reducing bandwidth costs is an important goal. In parallel, you'll also want to make sure that all photos are visually clear and are displayed with acceptable (or higher) quality. JPEGmini's JPEG optimization reduces JPEG quality and image size, but only up to the point at which the JPEG still looks good to the human eye. It analyzes each image and finds the quality threshold required to keep this specific image looking good, and applies that level of quality to the image.

For example, the following image was uploaded to Cloudinary with the ID of 'blue_sky'. This image is 310x207 and weighs 87.1KB.

Ruby:
Copy to clipboard
cl_image_tag("blue_sky.jpg")
PHP v1:
Copy to clipboard
cl_image_tag("blue_sky.jpg")
PHP v2:
Copy to clipboard
(new ImageTag('blue_sky.jpg'));
Python:
Copy to clipboard
CloudinaryImage("blue_sky.jpg").image()
Node.js:
Copy to clipboard
cloudinary.image("blue_sky.jpg")
Java:
Copy to clipboard
cloudinary.url().imageTag("blue_sky.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('blue_sky.jpg').toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("blue_sky.jpg")
React:
Copy to clipboard
<Image publicId="blue_sky.jpg" >

</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="blue_sky.jpg" >

</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="blue_sky.jpg" >

</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.BuildImageTag("blue_sky.jpg")
Android:
Copy to clipboard
MediaManager.get().url().generate("blue_sky.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().generate("blue_sky.jpg")!, cloudinary: cloudinary)
Original blue sky photo

Trying to convert the image to a JPEG of quality 80 indeed reduces file size to 17.5KB, which saves 80% of the original file size. However, the result doesn't look good enough. The sky's gradient has some "noise", and so do the white lines and text.

Ruby:
Copy to clipboard
cl_image_tag("blue_sky.jpg", :quality=>80)
PHP v1:
Copy to clipboard
cl_image_tag("blue_sky.jpg", array("quality"=>80))
PHP v2:
Copy to clipboard
(new ImageTag('blue_sky.jpg'))
  ->delivery(Delivery::quality(80));
Python:
Copy to clipboard
CloudinaryImage("blue_sky.jpg").image(quality=80)
Node.js:
Copy to clipboard
cloudinary.image("blue_sky.jpg", {quality: 80})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().quality(80)).imageTag("blue_sky.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('blue_sky.jpg', {quality: 80}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("blue_sky.jpg", {quality: 80})
React:
Copy to clipboard
<Image publicId="blue_sky.jpg" >
  <Transformation quality="80" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="blue_sky.jpg" >
  <cld-transformation quality="80" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="blue_sky.jpg" >
  <cl-transformation quality="80">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality(80)).BuildImageTag("blue_sky.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().quality(80)).generate("blue_sky.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality(80)).generate("blue_sky.jpg")!, cloudinary: cloudinary)
Quality 80% blue sky JPEG photo

Setting the quality parameter to jpegmini generates a better looking image with less “noise”, so you can safely embed it in your site. The image weighs 28KB, which is larger than the 80% quality version, but still saves almost 70% of the original image's size.

Ruby:
Copy to clipboard
cl_image_tag("blue_sky.jpg", :quality=>"jpegmini", :sign_url=>true)
PHP v1:
Copy to clipboard
cl_image_tag("blue_sky.jpg", array("quality"=>"jpegmini", "sign_url"=>true))
PHP v2:
Copy to clipboard
(new ImageTag('blue_sky.jpg'))
  ->delivery(Delivery::quality(Quality::jpegmini()))
  ->signUrl(true);
Python:
Copy to clipboard
CloudinaryImage("blue_sky.jpg").image(quality="jpegmini", sign_url=True)
Node.js:
Copy to clipboard
cloudinary.image("blue_sky.jpg", {quality: "jpegmini", sign_url: true})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().quality("jpegmini")).signed(true).imageTag("blue_sky.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('blue_sky.jpg', {quality: "jpegmini", signUrl: true}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("blue_sky.jpg", {quality: "jpegmini"})
React:
Copy to clipboard
<Image publicId="blue_sky.jpg" signUrl="true">
  <Transformation quality="jpegmini" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="blue_sky.jpg" signUrl="true">
  <cld-transformation quality="jpegmini" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="blue_sky.jpg" sign-url="true">
  <cl-transformation quality="jpegmini">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("jpegmini")).Signed(true).BuildImageTag("blue_sky.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().quality("jpegmini")).signed(true).generate("blue_sky.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality("jpegmini")).generate("blue_sky.jpg", signUrl: true)!, cloudinary: cloudinary)
JPEGmini optimized blue sky photo

Complex image manipulations

Cloudinary lets you apply various manipulations to your images. We've shown you a few above and many more image manipulations are supported. The JPEGmini optimization can be combined with any other image manipulations supported by Cloudinary. Here's a taste of advanced editing you can do with Cloudinary's image manipulations, combined with JPEGmini.

The following dynamic manipulation URL and sample code crops the dog's photo to a 200x230 ellipse, applies a smart photo-improving filter, adds a shadow, and finally, optimizes the result using JPEGmini for best delivery.

Ruby:
Copy to clipboard
cl_image_tag("happy_dog.jpg", :sign_url=>true, :transformation=>[
  {:effect=>"improve", :gravity=>"north", :height=>230, :radius=>"max", :width=>200, :crop=>"fill"},
  {:effect=>"shadow", :quality=>"jpegmini"}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("happy_dog.jpg", array("sign_url"=>true, "transformation"=>array(
  array("effect"=>"improve", "gravity"=>"north", "height"=>230, "radius"=>"max", "width"=>200, "crop"=>"fill"),
  array("effect"=>"shadow", "quality"=>"jpegmini")
  )))
PHP v2:
Copy to clipboard
(new ImageTag('happy_dog.jpg'))
  ->resize(Resize::fill()->width(200)->height(230)->gravity(Gravity::compass(Compass::north())))
  ->roundCorners(RoundCorners::max())
  ->adjust(Adjust::improve())
  ->effect(Effect::shadow())
  ->delivery(Delivery::quality(Quality::jpegmini()))
  ->signUrl(true);
Python:
Copy to clipboard
CloudinaryImage("happy_dog.jpg").image(sign_url=True, transformation=[
  {'effect': "improve", 'gravity': "north", 'height': 230, 'radius': "max", 'width': 200, 'crop': "fill"},
  {'effect': "shadow", 'quality': "jpegmini"}
  ])
Node.js:
Copy to clipboard
cloudinary.image("happy_dog.jpg", {sign_url: true, transformation: [
  {effect: "improve", gravity: "north", height: 230, radius: "max", width: 200, crop: "fill"},
  {effect: "shadow", quality: "jpegmini"}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .effect("improve").gravity("north").height(230).radius("max").width(200).crop("fill").chain()
  .effect("shadow").quality("jpegmini")).signed(true).imageTag("happy_dog.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('happy_dog.jpg', {signUrl: true, transformation: [
  {effect: "improve", gravity: "north", height: 230, radius: "max", width: 200, crop: "fill"},
  {effect: "shadow", quality: "jpegmini"}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("happy_dog.jpg", {transformation: [
  {effect: "improve", gravity: "north", height: 230, radius: "max", width: 200, crop: "fill"},
  {effect: "shadow", quality: "jpegmini"}
  ]})
React:
Copy to clipboard
<Image publicId="happy_dog.jpg" signUrl="true">
  <Transformation effect="improve" gravity="north" height="230" radius="max" width="200" crop="fill" />
  <Transformation effect="shadow" quality="jpegmini" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="happy_dog.jpg" signUrl="true">
  <cld-transformation effect="improve" gravity="north" height="230" radius="max" width="200" crop="fill" />
  <cld-transformation effect="shadow" quality="jpegmini" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="happy_dog.jpg" sign-url="true">
  <cl-transformation effect="improve" gravity="north" height="230" radius="max" width="200" crop="fill">
  </cl-transformation>
  <cl-transformation effect="shadow" quality="jpegmini">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Effect("improve").Gravity("north").Height(230).Radius("max").Width(200).Crop("fill").Chain()
  .Effect("shadow").Quality("jpegmini")).Signed(true).BuildImageTag("happy_dog.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .effect("improve").gravity("north").height(230).radius("max").width(200).crop("fill").chain()
  .effect("shadow").quality("jpegmini")).signed(true).generate("happy_dog.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setEffect("improve").setGravity("north").setHeight(230).setRadius("max").setWidth(200).setCrop("fill").chain()
  .setEffect("shadow").setQuality("jpegmini")).generate("happy_dog.jpg", signUrl: true)!, cloudinary: cloudinary)
Further manipulated JPEGmini optimized photo

Securing your manipulation URLs

JPEGmini is a computing-intensive operation, and you probably want to prevent unauthorized use of it. As a result, you may have noticed that all the manipulation URLs in this blog posts were signed (for example, in the last image, the URL included the secret s--J23CuGrX--). By signing URLs, you apply a layer of security, ensuring that the JPEGmini JPEG optimization can't be performed by just anyone directly typing a URL.

Another way to prevent external users from performing the JPEGmini optimization, is to “eagerly” generate optimized JPEGs while uploading your images. For more details about these options and the JPEGmini add-on in general, please refer to the documentation.

Summary

In this post we showed how JPEGmini can be used to smartly balance between JPEG compression and a high-quality visual result, and how simple it is to apply JPEGmini's optimization using Cloudinary's cloud-based image management service.

You can add the free tier of the JPEGmini add-on to your Cloudinary account and try it out on your photos using our interactive Media Library.  

As always, any feedback or comments you have would be much appreciated, either in the comments below or via Facebook or Twitter.

Want to Learn More About Image Formats?

Recent Blog Posts

Create Lightweight Sites With Low-Code and No-Code Technology

Consumers expect modern websites to be mainly visual. But, the more compelling and complex the related media is, the more data is involved, compounding the site’s weight. In today’s content-craving world, delivering unoptimized media can cost you because it leads to sluggish page loads, resulting in visitors abandoning your site in search of a faster alternative. In fact, a page load that takes more than three seconds can cause as many as 40% of your visitors to bounce. Given this competitive, digital-first environment, you can’t afford to lose page views, for time is of the essence.

Read more
A Blueprint for AWS-Secured Webhook Listeners for Cloudinary

tl;dr: An AWS-secured and optimized Cloudinary webhook listener for extending the Cloudinary service

Code: Github

A webhook is a communication medium for sending notifications from one platform to another about events that occurred. In place are user-defined HTTP callbacks that are triggered by specific events. When a triggered event takes place on the source site, the webhook listens to the event, collects the data, and sends it to the URL you specified in the form of an HTTP request.

Read more
New Accessibility Features for Cloudinary’s Product Gallery Widget

Cloudinary’s Product Gallery widget, which launched in 2019, has enabled many brands to effectively and efficiently showcase their products in a sleek and captivating manner, saving countless hours of development time and accelerating release cycles. By adding Cloudinary’s Product Gallery widget with its customizable UI to their product page, retailers reap numerous benefits, often turning visitors into customers in short order.

Read more
Why Successful Businesses Engage With and Convert Audiences With Visual Media

Most business buyers prefer to research purchase options online, as do many shoppers. No wonder online retail sales in the U.S. rose by 32.4% in 2020—an impressive gain of $105 billion.

For B2B and B2C businesses, text-heavy websites are no longer adequate in attracting shoppers. Instead, engaging visual media—spin images, videos, 3D models, augmented reality—are becoming a must for conveying eye-catching details and differentiators about products or services.

Read more
Making User-Generated Content (UGC) Shoppable With Cloudinary

User-generated content (UGC) is a powerful marketing tool. Not only does video complement marketing efforts for e-commerce by enabling customers to explore products in greater detail, but UGC also adds an element of trust. As a bonus, user-generated video is an exceptional opportunity for e-businesses to attract website traffic without their marketing team having to create promotional videos from scratch. User-generated content drives conversions and brand loyalty as a direct result of authentic interaction.

Read more