JPEGmini Image Optimization

Cloudinary is a cloud-based service that provides an end-to-end image management solution including uploads, storage, manipulations, optimizations and delivery.

Cloudinary offers a very rich set of image manipulation and optimization capabilities. Cloudinary seamlessly applies advanced image size shrinking logic to make sure that your images are as small as possible without degrading their viewing quality. In addition, Cloudinary's image transformation supports controlling the JPG quality level in order to control the balance between image file size and display quality.

JPEGmini is a patent-pending JPEG photo optimization technology, which significantly reduces the size of photographs without affecting their perceptual quality. Cloudinary provides an add-on for using JPEGmini's image optimization capabilities, fully integrated into Cloudinary's image management and manipulation pipeline.

With JPEGmini's image optimization add-on, you can extend Cloudinary's powerful image manipulation and optimization capabilities by automatically converting images to their best matching quality for faster delivery. When using the JPEGmini add-on, your images will be automatically optimized using advanced visual algorithms achieving file size reduction while maintaining a very high visual quality.

Using JPEGmini

Before you start, if you haven't done so already, please sign-up to a free Cloudinary account. After signing up, you can try the JPEGmini image optimization add-on for free and later on subscribe to an add-on plan that best matches your usage requirements.

Take a look at the following 'brown_sheep' photo that was uploaded to Cloudinary. This image file weighs 207KB.

Ruby:
cl_image_tag("brown_sheep.jpg")
PHP:
cl_image_tag("brown_sheep.jpg")
Python:
CloudinaryImage("brown_sheep.jpg").image()
Node.js:
cloudinary.image("brown_sheep.jpg")
Java:
cloudinary.url().imageTag("brown_sheep.jpg");
JS:
cloudinary.imageTag('brown_sheep.jpg').toHtml();
jQuery:
$.cloudinary.image("brown_sheep.jpg")
React:
<Image publicId="brown_sheep.jpg" >

</Image>
Vue.js:
<cld-image publicId="brown_sheep.jpg" >

</cld-image>
Angular:
<cl-image public-id="brown_sheep.jpg" >

</cl-image>
.Net:
cloudinary.Api.UrlImgUp.BuildImageTag("brown_sheep.jpg")
Android:
MediaManager.get().url().generate("brown_sheep.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().generate("brown_sheep.jpg")!, cloudinary: cloudinary)
brown_sheep

JPEG images can be created with different quality levels. There's a trade off between the desired reduction in file size and the deterioration in photo quality. Most websites prefer to aim at high quality of all displayed images, therefore they usually embed JPG images of about 90% quality. However, lower quality may still be adequate for different images.

The Cloudinary URL below dynamically converts the image to the best matching JPG quality using the JPEGmini add-on. While the original and smartly converted images look the same, the JPEGmini optimized one weighs just 115KB. This means that we saved 44% of the original image size. Less bytes mean faster loading time, better user experience and reduced bandwidth costs.

Ruby:
cl_image_tag("brown_sheep.jpg", :quality=>"jpegmini")
PHP:
cl_image_tag("brown_sheep.jpg", array("quality"=>"jpegmini"))
Python:
CloudinaryImage("brown_sheep.jpg").image(quality="jpegmini")
Node.js:
cloudinary.image("brown_sheep.jpg", {quality: "jpegmini"})
Java:
cloudinary.url().transformation(new Transformation().quality("jpegmini")).imageTag("brown_sheep.jpg");
JS:
cloudinary.imageTag('brown_sheep.jpg', {quality: "jpegmini"}).toHtml();
jQuery:
$.cloudinary.image("brown_sheep.jpg", {quality: "jpegmini"})
React:
<Image publicId="brown_sheep.jpg" >
  <Transformation quality="jpegmini" />
</Image>
Vue.js:
<cld-image publicId="brown_sheep.jpg" >
  <cld-transformation quality="jpegmini" />
</cld-image>
Angular:
<cl-image public-id="brown_sheep.jpg" >
  <cl-transformation quality="jpegmini">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("jpegmini")).BuildImageTag("brown_sheep.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().quality("jpegmini")).generate("brown_sheep.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality("jpegmini")).generate("brown_sheep.jpg")!, cloudinary: cloudinary)
with JPEGmini

Signed URLs

Cloudinary's dynamic image manipulation URLs are quite powerful and enable agile web and mobile development. However, due to the potential costs of users accessing unplanned dynamic URLs with JPEGmini quality directives, image manipulation add-on URLs are required (by default) to be signed using Cloudinary's authenticated API and with the sign_url parameter set to true.

The following code example generates a 200x150 resized version of the 'brown_sheep' image with a signed Cloudinary URL and the quality transformation parameter set to jpegmini. The generated Cloudinary URL includes a signature component s--ERIdO8k8--. Only URLs with a valid signature that matches the requested image manipulation will be approved for on-the-fly image manipulation and delivery.

Ruby:
cl_image_tag("brown_sheep.jpg", :height=>150, :quality=>"jpegmini", :width=>200, :crop=>"fill", :sign_url=>true)
PHP:
cl_image_tag("brown_sheep.jpg", array("height"=>150, "quality"=>"jpegmini", "width"=>200, "crop"=>"fill", "sign_url"=>true))
Python:
CloudinaryImage("brown_sheep.jpg").image(height=150, quality="jpegmini", width=200, crop="fill", sign_url=True)
Node.js:
cloudinary.image("brown_sheep.jpg", {height: 150, quality: "jpegmini", width: 200, crop: "fill", sign_url: true})
Java:
cloudinary.url().transformation(new Transformation().height(150).quality("jpegmini").width(200).crop("fill")).signed(true).imageTag("brown_sheep.jpg");
JS:
cloudinary.imageTag('brown_sheep.jpg', {height: 150, quality: "jpegmini", width: 200, crop: "fill", signUrl: true}).toHtml();
jQuery:
$.cloudinary.image("brown_sheep.jpg", {height: 150, quality: "jpegmini", width: 200, crop: "fill"})
React:
<Image publicId="brown_sheep.jpg" signUrl="true">
  <Transformation height="150" quality="jpegmini" width="200" crop="fill" />
</Image>
Vue.js:
<cld-image publicId="brown_sheep.jpg" signUrl="true">
  <cld-transformation height="150" quality="jpegmini" width="200" crop="fill" />
</cld-image>
Angular:
<cl-image public-id="brown_sheep.jpg" sign-url="true">
  <cl-transformation height="150" quality="jpegmini" width="200" crop="fill">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Height(150).Quality("jpegmini").Width(200).Crop("fill")).Signed(true).BuildImageTag("brown_sheep.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().height(150).quality("jpegmini").width(200).crop("fill")).signed(true).generate("brown_sheep.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setHeight(150).setQuality("jpegmini").setWidth(200).setCrop("fill")).generate("brown_sheep.jpg", signUrl: true)!, cloudinary: cloudinary)
signed url

For more details on signed URLs, see the following blog post: On-the-fly image manipulations secured with signed URLs.

Note
You can optionally remove the default signed URL requirement for a particular add-on by selecting it in the Allow unsigned add-on transformations section of the Security account settings in the Cloudinary console.

Eager transformations

As an alternative to signed URLs, you can eagerly generate all converted images during upload. This way you already use Cloudinary's authenticated API for requesting JPEGmini image optimization, therefore, accessing the generated images can be done using regular unsigned Cloudinary URLs.

The following code sample uploads a local JPG file to Cloudinary, assigns a custom public ID and eagerly generates the same 200x150 thumbnail that was smartly optimized using JPEGmini as in the signed-URL example above.

Ruby:
Cloudinary::Uploader.upload("local_file.jpg", 
  :public_id => "brown_sheep",
  :eager => { :quality => "jpegmini", :crop => "fill", 
    :width => 200, :height => 150 })
PHP:
\Cloudinary\Uploader::upload("local_file.jpg", 
  array(
    "public_id" => "brown_sheep",
    "eager" => array("quality" => "jpegmini", "crop" => "fill",
      "width" => 200, "height" => 150)));
Python:
cloudinary.uploader.upload("local_file.jpg",
  public_id = "brown_sheep",  
  eager = { 'quality': 'jpegmini', 'crop': "fill", 
    'width': 200, 'height': 150 })
Node.js:
cloudinary.v2.uploader.upload("local_file.jpg", 
  { public_id: "brown_sheep", 
    eager: { quality: "jpegmini", crop: "fill", 
      width: 200, height: 150 }},
  function(error, result){console.log(result);});
Java:
cloudinary.uploader().upload("local_file.jpg", 
  ObjectUtils.asMap(
    "public_id", "brown_sheep", 
    "eager", Arrays.asList(
      new Transformation().quality("jpegmini").crop("fill")
        .width(200).height(150))));
.Net:
var uploadParams = new ImageUploadParams(){
  File = new FileDescription(@"local_file.jpg"),
  PublicId = "brown_sheep",
  EagerTransforms = new List<Transformation>(){
   new Transformation().Quality("jpegmini").Crop("fill")
     Width(200).Height(150)}};
var uploadResult = cloudinary.Upload(uploadParams);

Tip
You can use upload presets to centrally define a set of upload options including add-on operations to apply, instead of specifying them in each upload call. You can define multiple upload presets, and apply different presets in different upload scenarios. You can create new upload presets in the Upload page of the Management Console settings or using the upload_presets Admin API method. From the Upload page of the console settings, you can also select default upload presets to use for image, video, and raw API uploads (respectively) as well as default presets for image, video, and raw uploads performed via the Media Library UI.

The resized and optimized image is available for delivery immediately when the upload request completes. Therefore, the optimized version can be accessed using an unsigned URL as in the example below:

Ruby:
cl_image_tag("brown_sheep.jpg", :height=>150, :quality=>"jpegmini", :width=>200, :crop=>"fill")
PHP:
cl_image_tag("brown_sheep.jpg", array("height"=>150, "quality"=>"jpegmini", "width"=>200, "crop"=>"fill"))
Python:
CloudinaryImage("brown_sheep.jpg").image(height=150, quality="jpegmini", width=200, crop="fill")
Node.js:
cloudinary.image("brown_sheep.jpg", {height: 150, quality: "jpegmini", width: 200, crop: "fill"})
Java:
cloudinary.url().transformation(new Transformation().height(150).quality("jpegmini").width(200).crop("fill")).imageTag("brown_sheep.jpg");
JS:
cloudinary.imageTag('brown_sheep.jpg', {height: 150, quality: "jpegmini", width: 200, crop: "fill"}).toHtml();
jQuery:
$.cloudinary.image("brown_sheep.jpg", {height: 150, quality: "jpegmini", width: 200, crop: "fill"})
React:
<Image publicId="brown_sheep.jpg" >
  <Transformation height="150" quality="jpegmini" width="200" crop="fill" />
</Image>
Vue.js:
<cld-image publicId="brown_sheep.jpg" >
  <cld-transformation height="150" quality="jpegmini" width="200" crop="fill" />
</cld-image>
Angular:
<cl-image public-id="brown_sheep.jpg" >
  <cl-transformation height="150" quality="jpegmini" width="200" crop="fill">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Height(150).Quality("jpegmini").Width(200).Crop("fill")).BuildImageTag("brown_sheep.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().height(150).quality("jpegmini").width(200).crop("fill")).generate("brown_sheep.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setHeight(150).setQuality("jpegmini").setWidth(200).setCrop("fill")).generate("brown_sheep.jpg")!, cloudinary: cloudinary)

Optimize JPG images

Optimizing JPG images using the JPEGmini add-on is done by setting the quality transformation parameter to jpegmini. Smart image conversion can be applied on the resulting image following any image scaling. The following resized and optimized image is generated on-the-fly by Cloudinary and delivered cached via a fast CDN. The size of the optimized thumbnail is 24.9KB, which is 27% less than the 34KB of the non JPEGmini optimized image.

Ruby:
cl_image_tag("horses.jpg", :quality=>"jpegmini", :width=>400, :crop=>"scale", :sign_url=>true)
PHP:
cl_image_tag("horses.jpg", array("quality"=>"jpegmini", "width"=>400, "crop"=>"scale", "sign_url"=>true))
Python:
CloudinaryImage("horses.jpg").image(quality="jpegmini", width=400, crop="scale", sign_url=True)
Node.js:
cloudinary.image("horses.jpg", {quality: "jpegmini", width: 400, crop: "scale", sign_url: true})
Java:
cloudinary.url().transformation(new Transformation().quality("jpegmini").width(400).crop("scale")).signed(true).imageTag("horses.jpg");
JS:
cloudinary.imageTag('horses.jpg', {quality: "jpegmini", width: 400, crop: "scale", signUrl: true}).toHtml();
jQuery:
$.cloudinary.image("horses.jpg", {quality: "jpegmini", width: 400, crop: "scale"})
React:
<Image publicId="horses.jpg" signUrl="true">
  <Transformation quality="jpegmini" width="400" crop="scale" />
</Image>
Vue.js:
<cld-image publicId="horses.jpg" signUrl="true">
  <cld-transformation quality="jpegmini" width="400" crop="scale" />
</cld-image>
Angular:
<cl-image public-id="horses.jpg" sign-url="true">
  <cl-transformation quality="jpegmini" width="400" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("jpegmini").Width(400).Crop("scale")).Signed(true).BuildImageTag("horses.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().quality("jpegmini").width(400).crop("scale")).signed(true).generate("horses.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality("jpegmini").setWidth(400).setCrop("scale")).generate("horses.jpg", signUrl: true)!, cloudinary: cloudinary)
JPEGmini default (best) quality

The default jpegmini quality gives you the best possible quality while still providing a significantly smaller file size than the original. If optimizing file size is more important than visual quality, you can request high (1) or medium (2) level quality instead of best (0), by adding the quality level value to the parameter, using the syntax: jpegmini:level.

For example, to request high quality (23.2 KB):

Ruby:
cl_image_tag("horses.jpg", :quality=>"jpegmini:1", :width=>400, :crop=>"scale", :sign_url=>true)
PHP:
cl_image_tag("horses.jpg", array("quality"=>"jpegmini:1", "width"=>400, "crop"=>"scale", "sign_url"=>true))
Python:
CloudinaryImage("horses.jpg").image(quality="jpegmini:1", width=400, crop="scale", sign_url=True)
Node.js:
cloudinary.image("horses.jpg", {quality: "jpegmini:1", width: 400, crop: "scale", sign_url: true})
Java:
cloudinary.url().transformation(new Transformation().quality("jpegmini:1").width(400).crop("scale")).signed(true).imageTag("horses.jpg");
JS:
cloudinary.imageTag('horses.jpg', {quality: "jpegmini:1", width: 400, crop: "scale", signUrl: true}).toHtml();
jQuery:
$.cloudinary.image("horses.jpg", {quality: "jpegmini:1", width: 400, crop: "scale"})
React:
<Image publicId="horses.jpg" signUrl="true">
  <Transformation quality="jpegmini:1" width="400" crop="scale" />
</Image>
Vue.js:
<cld-image publicId="horses.jpg" signUrl="true">
  <cld-transformation quality="jpegmini:1" width="400" crop="scale" />
</cld-image>
Angular:
<cl-image public-id="horses.jpg" sign-url="true">
  <cl-transformation quality="jpegmini:1" width="400" crop="scale">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation().Quality("jpegmini:1").Width(400).Crop("scale")).Signed(true).BuildImageTag("horses.jpg")
Android:
MediaManager.get().url().transformation(new Transformation().quality("jpegmini:1").width(400).crop("scale")).signed(true).generate("horses.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setQuality("jpegmini:1").setWidth(400).setCrop("scale")).generate("horses.jpg", signUrl: true)!, cloudinary: cloudinary)
JPEGmini high quality

Further image manipulations

Smart image optimization using the JPEGmini Cloudinary add-on can be mixed with any of Cloudinary's rich set of image manipulation capabilities.

For example, the following code first scales the 'horses' image to a width of 400 pixels while rounding its corners and increasing color saturation by 50%. Then another uploaded image named 'logo_jpegmini' is added as an overlay. The overlay is resized to a width of 100 pixels, positioned 10 pixels from the bottom right corner of the containing image and is made 80% semi-transparent. Finally, the automatic JPEGmini quality conversion is applied on the resulting image:

Ruby:
cl_image_tag("horses.jpg", :sign_url=>true, :transformation=>[
  {:effect=>"saturation:50", :radius=>20, :width=>400, :crop=>"scale"},
  {:gravity=>"south_east", :overlay=>"logo_jpegmini", :opacity=>80, :width=>100, :x=>10, :y=>10},
  {:quality=>"jpegmini"}
  ])
PHP:
cl_image_tag("horses.jpg", array("sign_url"=>true, "transformation"=>array(
  array("effect"=>"saturation:50", "radius"=>20, "width"=>400, "crop"=>"scale"),
  array("gravity"=>"south_east", "overlay"=>"logo_jpegmini", "opacity"=>80, "width"=>100, "x"=>10, "y"=>10),
  array("quality"=>"jpegmini")
  )))
Python:
CloudinaryImage("horses.jpg").image(sign_url=True, transformation=[
  {'effect': "saturation:50", 'radius': 20, 'width': 400, 'crop': "scale"},
  {'gravity': "south_east", 'overlay': "logo_jpegmini", 'opacity': 80, 'width': 100, 'x': 10, 'y': 10},
  {'quality': "jpegmini"}
  ])
Node.js:
cloudinary.image("horses.jpg", {sign_url: true, transformation: [
  {effect: "saturation:50", radius: 20, width: 400, crop: "scale"},
  {gravity: "south_east", overlay: "logo_jpegmini", opacity: 80, width: 100, x: 10, y: 10},
  {quality: "jpegmini"}
  ]})
Java:
cloudinary.url().transformation(new Transformation()
  .effect("saturation:50").radius(20).width(400).crop("scale").chain()
  .gravity("south_east").overlay(new Layer().publicId("logo_jpegmini")).opacity(80).width(100).x(10).y(10).chain()
  .quality("jpegmini")).signed(true).imageTag("horses.jpg");
JS:
cloudinary.imageTag('horses.jpg', {signUrl: true, transformation: [
  {effect: "saturation:50", radius: 20, width: 400, crop: "scale"},
  {gravity: "south_east", overlay: new cloudinary.Layer().publicId("logo_jpegmini"), opacity: 80, width: 100, x: 10, y: 10},
  {quality: "jpegmini"}
  ]}).toHtml();
jQuery:
$.cloudinary.image("horses.jpg", {transformation: [
  {effect: "saturation:50", radius: 20, width: 400, crop: "scale"},
  {gravity: "south_east", overlay: new cloudinary.Layer().publicId("logo_jpegmini"), opacity: 80, width: 100, x: 10, y: 10},
  {quality: "jpegmini"}
  ]})
React:
<Image publicId="horses.jpg" signUrl="true">
  <Transformation effect="saturation:50" radius="20" width="400" crop="scale" />
  <Transformation gravity="south_east" overlay="logo_jpegmini" opacity="80" width="100" x="10" y="10" />
  <Transformation quality="jpegmini" />
</Image>
Vue.js:
<cld-image publicId="horses.jpg" signUrl="true">
  <cld-transformation effect="saturation:50" radius="20" width="400" crop="scale" />
  <cld-transformation gravity="south_east" overlay="logo_jpegmini" opacity="80" width="100" x="10" y="10" />
  <cld-transformation quality="jpegmini" />
</cld-image>
Angular:
<cl-image public-id="horses.jpg" sign-url="true">
  <cl-transformation effect="saturation:50" radius="20" width="400" crop="scale">
  </cl-transformation>
  <cl-transformation gravity="south_east" overlay="logo_jpegmini" opacity="80" width="100" x="10" y="10">
  </cl-transformation>
  <cl-transformation quality="jpegmini">
  </cl-transformation>
</cl-image>
.Net:
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Effect("saturation:50").Radius(20).Width(400).Crop("scale").Chain()
  .Gravity("south_east").Overlay(new Layer().PublicId("logo_jpegmini")).Opacity(80).Width(100).X(10).Y(10).Chain()
  .Quality("jpegmini")).Signed(true).BuildImageTag("horses.jpg")
Android:
MediaManager.get().url().transformation(new Transformation()
  .effect("saturation:50").radius(20).width(400).crop("scale").chain()
  .gravity("south_east").overlay(new Layer().publicId("logo_jpegmini")).opacity(80).width(100).x(10).y(10).chain()
  .quality("jpegmini")).signed(true).generate("horses.jpg");
iOS:
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setEffect("saturation:50").setRadius(20).setWidth(400).setCrop("scale").chain()
  .setGravity("south_east").setOverlay("logo_jpegmini").setOpacity(80).setWidth(100).setX(10).setY(10).chain()
  .setQuality("jpegmini")).generate("horses.jpg", signUrl: true)!, cloudinary: cloudinary)