Cloudinary Blog

Animated WebP - how to convert animated GIF to WebP and save up to 90% bandwidth

Animated WebP: convert animated GIF to WebP on-the-fly

Fashion isn't something you'd expect to repeat itself in the technology world - technology advances quickly and hardly ever circles back. But where animated GIFs are involved, it seems like the 90s are here again. Animated GIFs are everywhere, and not only on strange, cheesy web sites - they've become mainstream. You now see short videos shared and played as animated GIFs in reputed sites such as Gawker and TechCrunch.

The GIF format is far from optimal for this purpose. While it's a simple image format supported by all web browsers and smartphones, converting videos to animated GIFs creates very large files. Downloading them takes time. Playing them uses a lot of memory and CPU resources. Pages on photo sharing sites, blogs, or even news sites, can become very slow when the page includes even a few animated GIFs that often weigh more than all the images in the page combined.

The GIF format was not meant to be used for full color video. It uses only 256 colors (with no semi-transparent alpha channel) and is better suited for drawings rather than photos or video frames. For a single photo frame, JPEG is a much better format both in quality and file size, but JPEG does not support animation.

A strong contender to replace the animated GIF is Google’s WebP format - with its new WebP animation support. In this blog post we show how you can use Cloudinary’s cloud-based media management service to convert animated GIFs on-the-fly to a WebP Animation. In addition, we detail how we automatically deliver Animated WebP files only on supported browsers with graceful degradation to Animated GIFs otherwise. The end result is a full-color, high-quality animated images that weigh much less and are almost visually identical to the original animated GIF files.

Conversion from animated GIF to animated WebP

The following animated GIF of a bored person was uploaded to Cloudinary from Wikimedia. Although it is a relatively small image of 279x193, this short video weighs as much as 1.5MB. If you have 30 such images on your site, that's a total of 45MB, which takes time to load. And if you have 1000 daily visitors to your site, your monthly bandwidth for these images alone will be 1.3TB!

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

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

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

</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.BuildImageTag("bored_animation.gif")
Android:
Copy to clipboard
MediaManager.get().url().generate("bored_animation.gif");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().generate("bored_animation.gif")!, cloudinary: cloudinary)
Original animated GIF279x193  GIF  (1.53 MB)

Cloudinary's media management service has support for uploading, transforming and managing all kinds of media files, including images, videos and audio to emerging media types. The code samples below, in all popular frameworks, construct a dynamic URL that converts the animated GIF above to an animated WebP. This URL enables the awebp flag (or fl_awebp if you’re providing the URL directly), and refers to the same image, bored_animation, changing its file extension to .webp (this tells Cloudinary you want to convert the image to this file format).

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.webp", :flags=>"awebp")
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.webp", array("flags"=>"awebp"))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.webp'))
  ->transcode(Transcode::toAnimated());
Python:
Copy to clipboard
CloudinaryImage("bored_animation.webp").image(flags="awebp")
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.webp", {flags: "awebp"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().flags("awebp")).imageTag("bored_animation.webp");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.webp', {flags: "awebp"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.webp", {flags: "awebp"})
React:
Copy to clipboard
<Image publicId="bored_animation.webp" >
  <Transformation flags="awebp" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.webp" >
  <cld-transformation flags="awebp" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.webp" >
  <cl-transformation flags="awebp">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Flags("awebp")).BuildImageTag("bored_animation.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().flags("awebp")).generate("bored_animation.webp");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setFlags("awebp")).generate("bored_animation.webp")!, cloudinary: cloudinary)
Animated WebP279x193  WebP  (419 KB)

Note: Animated WebP is currently supported only by the Chrome browser. If you see a broken image here, try opening this blog post in Chrome (v32 or higher).

The WebP animation above is generated on-the-fly by Cloudinary when the dynamic URL is accessed. It looks the same as the original image, but weighs only 419KB. This means we saved 72% of file size, bandwidth and load time, compared to the original 1.5MB animated GIF.

By default, Cloudinary generates animated WebP in lossy mode. The default quality level, used for the animated WebP above, is 80%, but you can select a different quality level.

Let’s try to generate the same animated WebP with a lower quality level. We’ll set the quality parameter to 40 (q_40 when providing the URL directly). You can see the dynamic transformation URL and the resulting WebP animation below.

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.webp", :flags=>"awebp", :quality=>40)
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.webp", array("flags"=>"awebp", "quality"=>40))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.webp'))
  ->transcode(Transcode::toAnimated())
  ->delivery(Delivery::quality(40));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.webp").image(flags="awebp", quality=40)
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.webp", {flags: "awebp", quality: 40})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().flags("awebp").quality(40)).imageTag("bored_animation.webp");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.webp', {flags: "awebp", quality: 40}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.webp", {flags: "awebp", quality: 40})
React:
Copy to clipboard
<Image publicId="bored_animation.webp" >
  <Transformation flags="awebp" quality="40" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.webp" >
  <cld-transformation flags="awebp" quality="40" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.webp" >
  <cl-transformation flags="awebp" quality="40">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Flags("awebp").Quality(40)).BuildImageTag("bored_animation.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().flags("awebp").quality(40)).generate("bored_animation.webp");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setFlags("awebp").setQuality(40)).generate("bored_animation.webp")!, cloudinary: cloudinary)
Animated WebP of 40% quality279x193  WebP  (195 KB)

With quality set to 40%, the visual difference is almost unnoticeable, but the generated file weighs only 195KB. This saves 53% of size and bandwidth compared to the 80% quality animated WebP, and represents a size reduction of 87% compared to the original GIF.

Resizing and cropping animated GIFs and converting to animated WebP

You can use Cloudinary's image transformation URLs to crop and resize animated GIFs. The following transformation URL and resulting image generates a 150x100 north-filled rectangle of the same animated GIF. The resulting image, in which Cloudinary has already applied certain animated GIF optimizations, weighs 429KB.

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.gif", :width=>150, :height=>100, :gravity=>"north", :crop=>"fill")
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.gif", array("width"=>150, "height"=>100, "gravity"=>"north", "crop"=>"fill"))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.gif'))
  ->resize(Resize::fill()->width(150)->height(100)
    ->gravity(Gravity::compass(Compass::north())));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.gif").image(width=150, height=100, gravity="north", crop="fill")
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.gif", {width: 150, height: 100, gravity: "north", crop: "fill"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(150).height(100).gravity("north").crop("fill")).imageTag("bored_animation.gif");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.gif', {width: 150, height: 100, gravity: "north", crop: "fill"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.gif", {width: 150, height: 100, gravity: "north", crop: "fill"})
React:
Copy to clipboard
<Image publicId="bored_animation.gif" >
  <Transformation width="150" height="100" gravity="north" crop="fill" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.gif" >
  <cld-transformation width="150" height="100" gravity="north" crop="fill" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.gif" >
  <cl-transformation width="150" height="100" gravity="north" crop="fill">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(150).Height(100).Gravity("north").Crop("fill")).BuildImageTag("bored_animation.gif")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(150).height(100).gravity("north").crop("fill")).generate("bored_animation.gif");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(150).setHeight(100).setGravity("north").setCrop("fill")).generate("bored_animation.gif")!, cloudinary: cloudinary)
Scaled down animated GIF150x100  GIF  (429 KB)

Now we can convert this image to animated WebP. The following URL generates the same 150x100 thumbnail, while converting to animated WebP with 80% quality. The result weighs only 154KB, which means we saved 64% of file size, without affecting quality.

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.webp", :width=>150, :height=>100, :gravity=>"north", :flags=>"awebp", :quality=>80, :crop=>"fill")
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.webp", array("width"=>150, "height"=>100, "gravity"=>"north", "flags"=>"awebp", "quality"=>80, "crop"=>"fill"))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.webp'))
  ->resize(Resize::fill()->width(150)->height(100)->gravity(Gravity::compass(Compass::north())))
  ->transcode(Transcode::toAnimated())
  ->delivery(Delivery::quality(80));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.webp").image(width=150, height=100, gravity="north", flags="awebp", quality=80, crop="fill")
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.webp", {width: 150, height: 100, gravity: "north", flags: "awebp", quality: 80, crop: "fill"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(150).height(100).gravity("north").flags("awebp").quality(80).crop("fill")).imageTag("bored_animation.webp");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.webp', {width: 150, height: 100, gravity: "north", flags: "awebp", quality: 80, crop: "fill"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.webp", {width: 150, height: 100, gravity: "north", flags: "awebp", quality: 80, crop: "fill"})
React:
Copy to clipboard
<Image publicId="bored_animation.webp" >
  <Transformation width="150" height="100" gravity="north" flags="awebp" quality="80" crop="fill" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.webp" >
  <cld-transformation width="150" height="100" gravity="north" flags="awebp" quality="80" crop="fill" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.webp" >
  <cl-transformation width="150" height="100" gravity="north" flags="awebp" quality="80" crop="fill">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(150).Height(100).Gravity("north").Flags("awebp").Quality(80).Crop("fill")).BuildImageTag("bored_animation.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(150).height(100).gravity("north").flags("awebp").quality(80).crop("fill")).generate("bored_animation.webp");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(150).setHeight(100).setGravity("north").setFlags("awebp").setQuality(80).setCrop("fill")).generate("bored_animation.webp")!, cloudinary: cloudinary)
Scaled down animated WebP150x100  WebP  (154 KB)

The animated WebP format is also very useful for animations of drawings, not only for video. The examples below show an animated drawing uploaded to Cloudinary from Wikimedia. The original animated GIF on the left weighs 790KB, while the WebP version on the right, at 80% quality, weighs only 375KB (a reduction of 52.5%).

Ruby:
Copy to clipboard
cl_image_tag("cell_animation.webp", :flags=>"awebp")
PHP v1:
Copy to clipboard
cl_image_tag("cell_animation.webp", array("flags"=>"awebp"))
PHP v2:
Copy to clipboard
(new ImageTag('cell_animation.webp'))
  ->transcode(Transcode::toAnimated());
Python:
Copy to clipboard
CloudinaryImage("cell_animation.webp").image(flags="awebp")
Node.js:
Copy to clipboard
cloudinary.image("cell_animation.webp", {flags: "awebp"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().flags("awebp")).imageTag("cell_animation.webp");
JS:
Copy to clipboard
cloudinary.imageTag('cell_animation.webp', {flags: "awebp"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("cell_animation.webp", {flags: "awebp"})
React:
Copy to clipboard
<Image publicId="cell_animation.webp" >
  <Transformation flags="awebp" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="cell_animation.webp" >
  <cld-transformation flags="awebp" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="cell_animation.webp" >
  <cl-transformation flags="awebp">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Flags("awebp")).BuildImageTag("cell_animation.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().flags("awebp")).generate("cell_animation.webp");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setFlags("awebp")).generate("cell_animation.webp")!, cloudinary: cloudinary)
Animated WebP drawing320x240  WebP  (375 KB) Animated GIF drawing320x240  GIF  (790 KB)

Automatically deliver animated WebP only on supported browsers

Hopefully, we’ve managed to show that animated WebP can be far superior to animated GIF. The problem is that only the Google Chrome browser, version 32 or higher, supports this format. Chrome is the leading browser in popularity and pushes upgrades strongly; for example, more than 60% of Cloudinary's website visitors use Chrome v32 or higher. It’s likely that on your website too, Chrome users are a sufficiently large audience to justify serving WebP images.

The challenge is to deliver WebP images to users of supported browsers, and deliver other formats (GIF, PNG, JPG, etc.) to users of other browsers. In our case, we need to deliver animated WebP to users of Chrome v32 or higher, and animated GIF to all other users.

Cloudinary can help by automatically delivering the appropriate image format to each user based on their browser (see our previous post which discusses this feature in more depth). To do this for an animated image like the one below, just set the fetch_format parameter to auto (or f_auto for URLs). Cloudinary automatically detects the user browser at the CDN level, and delivers cached and optimized converted animated WebP, or the original animated GIF, according to the user's browser.

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.gif", :width=>150, :height=>100, :gravity=>"north", :crop=>"fill", :fetch_format=>:auto)
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.gif", array("width"=>150, "height"=>100, "gravity"=>"north", "crop"=>"fill", "fetch_format"=>"auto"))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.gif'))
  ->resize(Resize::fill()->width(150)->height(100)->gravity(Gravity::compass(Compass::north())))
  ->delivery(Delivery::format(Format::auto()));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.gif").image(width=150, height=100, gravity="north", crop="fill", fetch_format="auto")
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.gif", {width: 150, height: 100, gravity: "north", crop: "fill", fetch_format: "auto"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().width(150).height(100).gravity("north").crop("fill").fetchFormat("auto")).imageTag("bored_animation.gif");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.gif', {width: 150, height: 100, gravity: "north", crop: "fill", fetchFormat: "auto"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.gif", {width: 150, height: 100, gravity: "north", crop: "fill", fetch_format: "auto"})
React:
Copy to clipboard
<Image publicId="bored_animation.gif" >
  <Transformation width="150" height="100" gravity="north" crop="fill" fetchFormat="auto" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.gif" >
  <cld-transformation width="150" height="100" gravity="north" crop="fill" fetchFormat="auto" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.gif" >
  <cl-transformation width="150" height="100" gravity="north" crop="fill" fetch-format="auto">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Width(150).Height(100).Gravity("north").Crop("fill").FetchFormat("auto")).BuildImageTag("bored_animation.gif")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().width(150).height(100).gravity("north").crop("fill").fetchFormat("auto")).generate("bored_animation.gif");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(150).setHeight(100).setGravity("north").setCrop("fill").setFetchFormat("auto")).generate("bored_animation.gif")!, cloudinary: cloudinary)
WebP or GIF automatically generated and delivered

Further transformations on your animated WebP images

We showed above how to resize and crop an animated image in Cloudinary. But there are many more transformations you can apply to an animated GIF or WebP image. The following example uses Cloudinary's image transformation URLs to round the corners of the animated GIF, add a gray border and a semi-transparent watermark overlay of another uploaded image, and finally convert to animated WebP. Again - the WebP format generates a visually-identical result that weighs just 35% of the GIF version (saving 65% of size and bandwidth).

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.webp", :transformation=>[
  {:width=>150, :height=>100, :gravity=>"north", :radius=>20, :border=>"3px_solid_rgb:aaa", :crop=>"fill"},
  {:overlay=>"cloudinary_icon", :flags=>"relative", :width=>0.8, :opacity=>50},
  {:flags=>"awebp", :quality=>80}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.webp", array("transformation"=>array(
  array("width"=>150, "height"=>100, "gravity"=>"north", "radius"=>20, "border"=>"3px_solid_rgb:aaa", "crop"=>"fill"),
  array("overlay"=>"cloudinary_icon", "flags"=>"relative", "width"=>"0.8", "opacity"=>50),
  array("flags"=>"awebp", "quality"=>80)
  )))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.webp'))
  ->border(Border::solid(3, Color::rgb('aaa'))
    ->roundCorners(RoundCorners::byRadius(20)))
  ->resize(Resize::fill()->width(150)->height(100)->gravity(Gravity::compass(Compass::north())))
  ->overlay(
      Overlay::source(Source::image('cloudinary_icon')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(0.8)->relative())
          ->adjust(Adjust::opacity(50)))))
    ->transcode(Transcode::toAnimated())
    ->delivery(Delivery::quality(80));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.webp").image(transformation=[
  {'width': 150, 'height': 100, 'gravity': "north", 'radius': 20, 'border': "3px_solid_rgb:aaa", 'crop': "fill"},
  {'overlay': "cloudinary_icon", 'flags': "relative", 'width': "0.8", 'opacity': 50},
  {'flags': "awebp", 'quality': 80}
  ])
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.webp", {transformation: [
  {width: 150, height: 100, gravity: "north", radius: 20, border: "3px_solid_rgb:aaa", crop: "fill"},
  {overlay: "cloudinary_icon", flags: "relative", width: "0.8", opacity: 50},
  {flags: "awebp", quality: 80}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .width(150).height(100).gravity("north").radius(20).border("3px_solid_rgb:aaa").crop("fill").chain()
  .overlay(new Layer().publicId("cloudinary_icon")).flags("relative").width(0.8).opacity(50).chain()
  .flags("awebp").quality(80)).imageTag("bored_animation.webp");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.webp', {transformation: [
  {width: 150, height: 100, gravity: "north", radius: 20, border: "3px_solid_rgb:aaa", crop: "fill"},
  {overlay: new cloudinary.Layer().publicId("cloudinary_icon"), flags: "relative", width: "0.8", opacity: 50},
  {flags: "awebp", quality: 80}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.webp", {transformation: [
  {width: 150, height: 100, gravity: "north", radius: 20, border: "3px_solid_rgb:aaa", crop: "fill"},
  {overlay: new cloudinary.Layer().publicId("cloudinary_icon"), flags: "relative", width: "0.8", opacity: 50},
  {flags: "awebp", quality: 80}
  ]})
React:
Copy to clipboard
<Image publicId="bored_animation.webp" >
  <Transformation width="150" height="100" gravity="north" radius="20" border="3px_solid_rgb:aaa" crop="fill" />
  <Transformation overlay="cloudinary_icon" flags="relative" width="0.8" opacity="50" />
  <Transformation flags="awebp" quality="80" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.webp" >
  <cld-transformation width="150" height="100" gravity="north" radius="20" border="3px_solid_rgb:aaa" crop="fill" />
  <cld-transformation :overlay="cloudinary_icon" flags="relative" width="0.8" opacity="50" />
  <cld-transformation flags="awebp" quality="80" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.webp" >
  <cl-transformation width="150" height="100" gravity="north" radius="20" border="3px_solid_rgb:aaa" crop="fill">
  </cl-transformation>
  <cl-transformation overlay="cloudinary_icon" flags="relative" width="0.8" opacity="50">
  </cl-transformation>
  <cl-transformation flags="awebp" quality="80">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(150).Height(100).Gravity("north").Radius(20).Border("3px_solid_rgb:aaa").Crop("fill").Chain()
  .Overlay(new Layer().PublicId("cloudinary_icon")).Flags("relative").Width(0.8).Opacity(50).Chain()
  .Flags("awebp").Quality(80)).BuildImageTag("bored_animation.webp")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .width(150).height(100).gravity("north").radius(20).border("3px_solid_rgb:aaa").crop("fill").chain()
  .overlay(new Layer().publicId("cloudinary_icon")).flags("relative").width(0.8).opacity(50).chain()
  .flags("awebp").quality(80)).generate("bored_animation.webp");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setWidth(150).setHeight(100).setGravity("north").setRadius(20).setBorder("3px_solid_rgb:aaa").setCrop("fill").chain()
  .setOverlay("cloudinary_icon").setFlags("relative").setWidth(0.8).setOpacity(50).chain()
  .setFlags("awebp").setQuality(80)).generate("bored_animation.webp")!, cloudinary: cloudinary)
Transformed animated WebP156x106  WebP  (233 KB) Transformed animated GIF156x106  GIF  (664 KB)

Summary

The results of switching from animated GIF to animated WebP are impressive - in the examples we showed above, image size and bandwidth were reduced by 65-90%, with the same visual result. Albeit, WebP is only used by a limited number of browsers, but the latest versions of Chrome are becoming more and more popular, and so the importance of WebP is on the rise.

With Cloudinary's automatic conversion and selective delivery of animation format based on the user's browser, there's definitely no reason not to use animated WebP for displaying your short videos. Furthermore, if you convert your original high quality videos to WebP (and not just convert from GIF to WebP like we did in the examples above), you’ll get a better visual result, due to the WebP format’s full-color support, compared to only 256 colors in an animated GIF.

By the way, in our humble opinion, those major sites that are now full of animated GIFs, all playing simultaneously, could achieve a more professional result by showing the first still frame of the animation, with a small play button. With Cloudinary you can easily convert an animated GIF or WebP animation to any single-frame image format. For example:

Ruby:
Copy to clipboard
cl_image_tag("bored_animation.jpg", :transformation=>[
  {:width=>150, :height=>100, :gravity=>"north", :crop=>"fill"},
  {:overlay=>"play_button", :width=>0.4, :flags=>"relative", :opacity=>60}
  ])
PHP v1:
Copy to clipboard
cl_image_tag("bored_animation.jpg", array("transformation"=>array(
  array("width"=>150, "height"=>100, "gravity"=>"north", "crop"=>"fill"),
  array("overlay"=>"play_button", "width"=>"0.4", "flags"=>"relative", "opacity"=>60)
  )))
PHP v2:
Copy to clipboard
(new ImageTag('bored_animation.jpg'))
  ->resize(Resize::fill()->width(150)->height(100)->gravity(Gravity::compass(Compass::north())))
  ->overlay(
      Overlay::source(Source::image('play_button')
        ->transformation((new ImageTransformation())
          ->resize(Resize::scale()->width(0.4)->relative())
          ->adjust(Adjust::opacity(60))
  )));
Python:
Copy to clipboard
CloudinaryImage("bored_animation.jpg").image(transformation=[
  {'width': 150, 'height': 100, 'gravity': "north", 'crop': "fill"},
  {'overlay': "play_button", 'width': "0.4", 'flags': "relative", 'opacity': 60}
  ])
Node.js:
Copy to clipboard
cloudinary.image("bored_animation.jpg", {transformation: [
  {width: 150, height: 100, gravity: "north", crop: "fill"},
  {overlay: "play_button", width: "0.4", flags: "relative", opacity: 60}
  ]})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation()
  .width(150).height(100).gravity("north").crop("fill").chain()
  .overlay(new Layer().publicId("play_button")).width(0.4).flags("relative").opacity(60)).imageTag("bored_animation.jpg");
JS:
Copy to clipboard
cloudinary.imageTag('bored_animation.jpg', {transformation: [
  {width: 150, height: 100, gravity: "north", crop: "fill"},
  {overlay: new cloudinary.Layer().publicId("play_button"), width: "0.4", flags: "relative", opacity: 60}
  ]}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("bored_animation.jpg", {transformation: [
  {width: 150, height: 100, gravity: "north", crop: "fill"},
  {overlay: new cloudinary.Layer().publicId("play_button"), width: "0.4", flags: "relative", opacity: 60}
  ]})
React:
Copy to clipboard
<Image publicId="bored_animation.jpg" >
  <Transformation width="150" height="100" gravity="north" crop="fill" />
  <Transformation overlay="play_button" width="0.4" flags="relative" opacity="60" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="bored_animation.jpg" >
  <cld-transformation width="150" height="100" gravity="north" crop="fill" />
  <cld-transformation :overlay="play_button" width="0.4" flags="relative" opacity="60" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="bored_animation.jpg" >
  <cl-transformation width="150" height="100" gravity="north" crop="fill">
  </cl-transformation>
  <cl-transformation overlay="play_button" width="0.4" flags="relative" opacity="60">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Width(150).Height(100).Gravity("north").Crop("fill").Chain()
  .Overlay(new Layer().PublicId("play_button")).Width(0.4).Flags("relative").Opacity(60)).BuildImageTag("bored_animation.jpg")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .width(150).height(100).gravity("north").crop("fill").chain()
  .overlay(new Layer().publicId("play_button")).width(0.4).flags("relative").opacity(60)).generate("bored_animation.jpg");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setWidth(150).setHeight(100).setGravity("north").setCrop("fill").chain()
  .setOverlay("play_button").setWidth(0.4).setFlags("relative").setOpacity(60)).generate("bored_animation.jpg")!, cloudinary: cloudinary)
First animation frame with play buttonx    ()

Dynamic transformation of animated GIFs, on-the-fly conversion to Web and all other powerful image transformation and optimization features described in this post, are available for all Cloudinary's users, including those using the free plan. Set up a free Cloudinary account to try it out. And we’ll more than welcome your feedback on this feature via the comments below or your favorite social network.


Want to Learn More About Image Formats?

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