Cloudinary Blog

Optimizing Images in Ruby

By Prosper Otemuyiwa
Optimizing Images in Ruby

Through various techniques and algorithms, you can optimize images, that is, reduce their file size yet still maintain a high visual quality. This article shows you how to optimally reduce image sizes in Ruby and Cloudinary.


How to Optimize for Page-Load Speed


The Importance of Image Optimization

Effective management of images involves taking into account four criteria: quality, size, format, and metadata, with quality and size a balancing act for optimization. Here are three major reasons why optimization counts:

  • Bandwidth. Bandwidth costs money both on your part as the site’s host and on your audience’s part. Optimizing images saves bandwidth.
  • Download time. Loading unoptimized images takes longer, and viewers who must wait for quite a while for a page to load might never return.
  • Storage space. Smaller images need less storage space. Consider this typical scenario: 100 user-uploaded images that weigh 5 MB each—and that you optimize to 2 MB each with no quality loss—require only 200 MB of storage instead of the original 500 MB.

Optimization of Images in Ruby

You can downsize images in Ruby with one of three gems: piet, image_optim, and mini_magick.

piet

To install **piet**, which optimizes images with the **optiPNG ** and **jpegoptim** utilities, type:

Copy to clipboard
gem install piet

For example, to optimize an image called dog.jpg in Ruby, type:

Copy to clipboard
Piet.optimize(‘/images/dog.jpg’)

To generate and display the related output, add the option :verbose => true:

Copy to clipboard
Piet.optimize('/images/dog.png', :verbose => true)

Here’s an output example:

Copy to clipboard
Processing: dog.png
340x340 pixels, 4x8 bits/pixel, RGB+alpha
Input IDAT size = 157369 bytes
Input file size = 157426 bytes

Trying:
  zc = 9  zm = 9  zs = 0  f = 1   IDAT size = 156966
  zc = 9  zm = 8  zs = 0  f = 1   IDAT size = 156932

Selecting parameters:
  zc = 9  zm = 8  zs = 0  f = 1   IDAT size = 156932

Output IDAT size = 156932 bytes (437 bytes decrease)
Output file size = 156989 bytes (437 bytes = 0.28% decrease)

Furthermore, you can convert 24- or 32-bit PNGs to paletted (8-bit) PNGs with piet, significantly reducing their sizes and preserving full-alpha transparency:

Copy to clipboard
Piet.pngquant('/a/path/where/you/store/the/file/to/convert')

For more options, see the related documentation.

image_optim

**image_optim** is a comprehensive gem that takes advantage of numerous utilities, such as jhead, jpegoptim, jpeg-recompress, jpegtran, optipng, pngcrush, pngout, and pngquant.

To install image_optim, type:

Copy to clipboard
gem install image_optim

Afterwards, to invoke image_optim In your Ruby app, type:

Copy to clipboard
image_optim = ImageOptim.new

image_optim = ImageOptim.new(:pngout => false)

image_optim = ImageOptim.new(:nice => 20)

Then, to optimize an image called dog.jpg, type:

Copy to clipboard
image_optim.optimize_image('dog.png')

For more options, see the related documentation.

mini_magick

With **mini_magick**(https://github.com/minimagick/minimagick), a wrapper for ImageMagick, you can access all ImageMagick options.

To add mini_magick to your Gemfile, type:

Copy to clipboard
gem "mini_magick"

To have mini_magick resize an image called dog.jpg as a copy of the original, type:

Copy to clipboard
image = MiniMagick::Image.open("dog.jpg")
image.path #=> "/var/folders/k7/6zx6dx6x7ys3rv3srh0nyfj00000gn/T/magick20140921-75881-1yho3zc.jpg"
image.resize "300x300"
image.format "png"
image.write "output.png"

Omitting the write method above enables you to modify the original image. For more options, see the related documentation.

Cloudinary: An Ideal Optimization Alternative

With Cloudinary, you can quickly and intuitively optimize images regardless of the programming language. By default and through automation, Cloudinary optimizes all transformed images, efficiently delivering the final version through integrated content delivery networks (CDNs). Among the many Cloudinary capabilities are the following:

Automated quality compression and encoding. Through the **q_auto** parameter, Cloudinary selects the optimal quality-compression level and encoding settings according to the image content, format, and viewing browser. The result is a sharp yet downsized image. For example:

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

To adjust the visual quality of images, add the **q_auto:best**, **q_auto:low**, **q_auto:good**, or **q_auto:eco** parameter to the dynamic URL.

Automated transformation. The **f_auto** parameter enables Cloudinary to analyze the image content and then select the best format for delivery: for example, WebP for Chrome, JPEG-XR for Internet Explorer, and the original format for all other browsers.

A combination of f_auto and q_auto causes Cloudinary to still deliver WebP and JPEG-XR to the relevant browsers. However, if the quality algorithm determines that PNG-8 or PNG-24 is optimal for certain images, Cloudinary switches the delivery format to either of those two, as appropriate.

Image resizing and cropping with w and h parameters. By adding to URLs the width (w) and height (h) parameters along with the dimensions you desire, you instruct Cloudinary to resize the images accordingly but maintain the aspect ratio:

Ruby:
Copy to clipboard
cl_image_tag("sample.jpg", :width=>0.5, :crop=>"scale")
PHP v1:
Copy to clipboard
cl_image_tag("sample.jpg", array("width"=>"0.5", "crop"=>"scale"))
PHP v2:
Copy to clipboard
(new ImageTag('sample.jpg'))
  ->resize(Resize::scale()->width(0.5));
Python:
Copy to clipboard
CloudinaryImage("sample.jpg").image(width="0.5", crop="scale")
Node.js:
Copy to clipboard
cloudinary.image("sample.jpg", {width: "0.5", crop: "scale"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(0.5).crop("scale")).imageTag("sample.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('sample.jpg', {width: "0.5", crop: "scale"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("sample.jpg", {width: "0.5", crop: "scale"})
React:
Copy to clipboard
<Image publicId="sample.jpg" >
  <Transformation width="0.5" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="sample.jpg" >
  <cld-transformation width="0.5" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="sample.jpg" >
  <cl-transformation width="0.5" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(0.5).Crop("scale")).BuildImageTag("sample.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(0.5).crop("scale")).generate("sample.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(0.5).setCrop("scale")).generate("sample.jpg")!, cloudinary: cloudinary)
https://res.cloudinary.com/demo/image/upload/w_0.5/sample.jpg

Ruby:
Copy to clipboard
cl_image_tag("sample.jpg", :height=>200, :crop=>"scale")
PHP v1:
Copy to clipboard
cl_image_tag("sample.jpg", array("height"=>200, "crop"=>"scale"))
PHP v2:
Copy to clipboard
(new ImageTag('sample.jpg'))
  ->resize(Resize::scale()->height(200));
Python:
Copy to clipboard
CloudinaryImage("sample.jpg").image(height=200, crop="scale")
Node.js:
Copy to clipboard
cloudinary.image("sample.jpg", {height: 200, crop: "scale"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().height(200).crop("scale")).imageTag("sample.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('sample.jpg', {height: 200, crop: "scale"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("sample.jpg", {height: 200, crop: "scale"})
React:
Copy to clipboard
<Image publicId="sample.jpg" >
  <Transformation height="200" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="sample.jpg" >
  <cld-transformation height="200" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="sample.jpg" >
  <cl-transformation height="200" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Height(200).Crop("scale")).BuildImageTag("sample.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().height(200).crop("scale")).generate("sample.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setHeight(200).setCrop("scale")).generate("sample.jpg")!, cloudinary: cloudinary)
https://res.cloudinary.com/demo/image/upload/h_200/sample.jpg

Ruby:
Copy to clipboard
cl_image_tag("sample.jpg", :width=>200, :height=>100, :crop=>"scale")
PHP v1:
Copy to clipboard
cl_image_tag("sample.jpg", array("width"=>200, "height"=>100, "crop"=>"scale"))
PHP v2:
Copy to clipboard
(new ImageTag('sample.jpg'))
  ->resize(Resize::scale()->width(200)->height(100));
Python:
Copy to clipboard
CloudinaryImage("sample.jpg").image(width=200, height=100, crop="scale")
Node.js:
Copy to clipboard
cloudinary.image("sample.jpg", {width: 200, height: 100, crop: "scale"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(200).height(100).crop("scale")).imageTag("sample.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('sample.jpg', {width: 200, height: 100, crop: "scale"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("sample.jpg", {width: 200, height: 100, crop: "scale"})
React:
Copy to clipboard
<Image publicId="sample.jpg" >
  <Transformation width="200" height="100" crop="scale" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="sample.jpg" >
  <cld-transformation width="200" height="100" crop="scale" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="sample.jpg" >
  <cl-transformation width="200" height="100" crop="scale">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(200).Height(100).Crop("scale")).BuildImageTag("sample.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(200).height(100).crop("scale")).generate("sample.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(200).setHeight(100).setCrop("scale")).generate("sample.jpg")!, cloudinary: cloudinary)
https://res.cloudinary.com/demo/image/upload/w_200,h_100/sample.jpg

Cloudinary supports these image-cropping modes: scale, [fit](https://cloudinary.com/documentation/image_transformations#fit), mfit, fill, lfill, limit, pad, lpad, mpad, crop, thumb, imagga_crop, and imagga_scale.

Summary

Optimizing images is a priority task for enhancing page performance. The optimization procedures in Ruby and in Cloudinary, as described in this post, are just the tip of the iceberg. For more ideas, read this Cloudinary post and the related Cloudinary documentation.

Further Reading on Image Optimization

Recent Blog Posts

Our $2B Valuation

By
Blackstone Growth Invests in Cloudinary

When we started our journey in 2012, we were looking to improve our lives as developers by making it easier for us to handle the arduous tasks of handling images and videos in our code. That initial line of developer code has evolved into a full suite of media experience solutions driven by a mission that gradually revealed itself over the course of the past 10 years: help companies unleash the full potential of their media to create the most engaging visual experiences.

Read more
Direct-to-Consumer E-Commerce Requires Compelling Visual Experiences

When brands like you adopt a direct–to-consumer (DTC) e-commerce approach with no involvement of retailers or marketplaces, you gain direct and timely insight into evolving shopping behaviors. Accordingly, you can accommodate shoppers’ preferences by continually adjusting your product offering and interspersing the shopping journey with moments of excitement and intrigue. Opportunities abound for you to cultivate engaging customer relationships.

Read more
Automatically Translating Videos for an International Audience

No matter your business focus—public service, B2B integration, recruitment—multimedia, in particular video, is remarkably effective in communicating with the audience. Before, making video accessible to diverse viewers involved tasks galore, such as eliciting the service of production studios to manually dub, transcribe, and add subtitles. Those operations were costly and slow, especially for globally destined content.

Read more
Cloudinary Helps Minted Manage Its Image-Generation Pipeline at Scale

Shoppers return time and again to Minted’s global online community of independent artists and designers because they know they can count on unique, statement-making products of the highest quality there. Concurrently, the visual imagery on Minted.com must do justice to the designs into which the creators have poured their hearts and souls. For Minted’s VP of Engineering David Lien, “Because we are a premium brand, we need to ensure that every single one of our product images matches the selected configuration exactly. For example, if you pick an 18x24 art print on blue canvas, we will show that exact combination on the hero images in the PDF.”

Read more
Highlights on ImageCon 2021 and a Preview of ImageCon 2022

New year, same trend! Visual media will continue to play a monumental role in driving online conversions. To keep up with visual-experience trends and best practices, Cloudinary holds an annual conference called ImageCon, a one-of-a-kind event that helps attendees create the most engaging visual experiences possible.

Read more