Cloudinary Blog

Programmatically Convert Raster Images to Vector Graphics

Programmatically Convert Raster Images to Vector Graphics

SVG format has been around forever, but until recently usage has been relatively low. However, following improved browser support, developers are rediscovering SVG, and taking advantage of its merits including:

  • Extremely lightweight, especially for large image dimensions.
  • Pixel-perfect scalability making it ideal for responsive designs.
  • Code-only editing. SVG is code.
  • Searchable by search engines and accessibility screen readers.

For many web designers, SVG is a go-to method for creating and delivering logos, icons, fonts, graphics, infographics and other simple images in their websites. But generally, SVG creation requires a certain skill level and experience with SVG creation tools.

Cloudinary has long supported transforming and serving SVG assets but now Cloudinary has gone a step further by providing a simple vectorize effect . that enables web developers and designers to take advantage of SVG even when the images they have to work with are simple raster graphics, PNGs or even photographic data, and without requiring deep knowledge or special tools for generating vector graphics.

The newe_vectorizetransformation option accepts a raster image and returns an SVG on-the-fly and ready for delivery.. It achieves this 'magic' by tracing and detecting paths and areas in the source image and converting them to SVG vector form. It provides a variety of options that enable you to generate SVGs with more or less detail, depending on your goals.

Let’s take a closer look at some usage options that these new capabilities open up.

Vectorize Logos and Icons

Suppose you have access to logos, icons, or other graphics in raster form, (probably PNG) , but would like to scale them or deliver them in a more compact form. For this use-case, we want the SVG version to match the original as closely as possible.

Let's assume we only have access to a 256px version of the following drawing:

Original racoon PNG - 256px

This is a relatively small PNG at 28 KB.

But what if we want to display the image at a larger size? Unfortunately, the blurriness and file size of raster graphics both continually increase with resolution. So for example, if we wanted to display this image at 4x the original size, the file size would grow to a much less friendly 337 KB, while the quality would drop significantly, and it would also be highly pixelated.

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

But what if we turn it into an SVG?

With the new Cloudinary vectorize effect, we can do raster image to vector conversion on-the-fly.

As mentioned earlier, the vectorize feature works by tracing and detecting paths and areas in the source image and then converting them to SVG vector form. To do this, it must perform some approximations, so the result is usually not a completely “lossless” copy of the source, but depending on the source information, it can come very close.

There are several options that can be specified for the vectorize effect that you can use to control the resulting output, depending on your goals.

For this case, we'll request an SVG at the maximum detail (1.0) with 3 colors (like the original). We don't want corners to be too rough, but also not too soft, so we'll use an intermediate value of 40 for the corners option. This yields an extremely compact, 8 KB file that will provide pixel-perfect scaling to any size.

Ruby:
Copy to clipboard
cl_image_tag("docs/racoon.png", :effect=>"vectorize:detail:1.0:corners:40:colors:3")
PHP v1:
Copy to clipboard
cl_image_tag("docs/racoon.png", array("effect"=>"vectorize:detail:1.0:corners:40:colors:3"))
PHP v2:
Copy to clipboard
(new ImageTag('docs/racoon.png'))
  ->effect(Effect::vectorize()->numOfColors(3)->detailsLevel(1.0)
    ->cornersLevel(40));
Python:
Copy to clipboard
CloudinaryImage("docs/racoon.png").image(effect="vectorize:detail:1.0:corners:40:colors:3")
Node.js:
Copy to clipboard
cloudinary.image("docs/racoon.png", {effect: "vectorize:detail:1.0:corners:40:colors:3"})
Java:
Copy to clipboard
cloudinary.url().transformation(new Transformation().effect("vectorize:detail:1.0:corners:40:colors:3")).imageTag("docs/racoon.png");
JS:
Copy to clipboard
cloudinary.imageTag('docs/racoon.png', {effect: "vectorize:detail:1.0:corners:40:colors:3"}).toHtml();
jQuery:
Copy to clipboard
$.cloudinary.image("docs/racoon.png", {effect: "vectorize:detail:1.0:corners:40:colors:3"})
React:
Copy to clipboard
<Image publicId="docs/racoon.png" >
  <Transformation effect="vectorize:detail:1.0:corners:40:colors:3" />
</Image>
Vue.js:
Copy to clipboard
<cld-image publicId="docs/racoon.png" >
  <cld-transformation effect="vectorize:detail:1.0:corners:40:colors:3" />
</cld-image>
Angular:
Copy to clipboard
<cl-image public-id="docs/racoon.png" >
  <cl-transformation effect="vectorize:detail:1.0:corners:40:colors:3">
  </cl-transformation>
</cl-image>
.NET:
Copy to clipboard
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("vectorize:detail:1.0:corners:40:colors:3")).BuildImageTag("docs/racoon.png")
Android:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation().effect("vectorize:detail:1.0:corners:40:colors:3")).generate("docs/racoon.png");
iOS:
Copy to clipboard
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setEffect("vectorize:detail:1.0:corners:40:colors:3")).generate("docs/racoon.png")!, cloudinary: cloudinary)

deliver PNG as vectorized SVG

This was a relatively simple case. It only has a few colors, so it really brings out the value of having a vector version.

Do keep in mind that when you are going for very accurate detail in the resulting SVG, color gradients or a large number of colors in the original don't work as well. Optimal results are achieved with a limited number of solid colors.

Generating Cool, Compact Image Placeholders

When delivering high quality photos, it's good web design practice to first deliver Low Quality Image Placeholders (LQIPs) that are very compact in size, and load extremely quickly. Cloudinary supports a large variety of compressions that can potentially be used for generating placeholders. You can read some more about those here.

But there are several merits to using SVG placeholders:

  • They are quite compact.
  • They offer pleasant results that also convey the contents of the final image.
  • SVGs can be embedded directly within HTML and don't need to wait for JavaScript to load.

Let’s dive in with an example:

The 2 Megapixel version of this lion image by Capri23auto is 752 KB, but assuming we take advantage of Cloudinary’s f_auto and q_auto optimizations, we will be dealing with about 400 KB for the full resolution image, which is nearly 50% of the original, but still pretty large.

Optimized full resolution lion JPG is 397 KB

So it would be nice to have an SVG LQIP in place while lazy loading the full-sized image.

We want the placeholder to represent the subject matter of the original but also be very compact. Confining ourselves to 5 colors and a detail level of 10% produces a nice image, but still too large for a placeholder.

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

Deliver large JPG as LQIP vectorized SVG

Leaving just 2 colors, and going to a 5% detail level produces a result that is still easily identifiable, but much smaller (about 6 kb). Or you can make a few more adjustments, which still gives you an image resembling the original, but now you are counting your file size in bytes!

6 KB LQIP 6 KB LQIP ~1 KB LQIP ~1 KB LQIP

Vectorizing as an Artistic Effect

As can already be seen in the previous example, the product of vectorization allows us to capture the main shapes and objects composing a photo or drawing and produces a nice effect.. This might be something we want to offer to our users simply to apply as effects on their own uploaded images or for other purposes. In these cases, we don't necessarily want to deliver as an SVG. As with any other Cloudinary transformation, you can deliver vectorized images in any format, simply by specifying the relevant extension.

For example, suppose one of your users had uploaded this simple selfie image. You could provide a button that lets them convert their photo to a vectorized image:

Original Original Default vectorize effect Default vectorize effect

The default e_vectorize parameter will reduce it to a detail level of 300 pixels and 10 colors, which is quite sufficient for this image.

Let’s examine another image that may require more colors, but less detail. For this image, we might deliver using e_vectorize:colors:20:detail:0.1

Original Original Many colors, less detail Many colors, less detail

Customizing your Vector Effect

As previously mentioned, the vectorize effect can be controlled in several ways allowing different outcomes. The syntax is as follows:

vectorize:[detail]:[colors]:[despeckle]:[paths]:[corners]

  • Detail can be supplied either as a relative value (0 - 1.0), or an absolute number of pixels. Relative detail may be more intuitive, but if you want to apply the same transformation to multiple images that may have different source resolutions, the absolute pixel value will provide more consistent results across images.

  • Colors (not surprisingly) indicate how many colors will be used for the resulting image (up to 30), but obviously the number of colors you choose (if fewer than the original) will also impact the ultimate level of detail.

  • The remaining options allow you to further fine tune the result.
    For full details, see the vectorize effect in the Image Transformation Reference.

Below you can see a variety of potential outputs using these options. The top-left image is the original photo. Following it, you can see the vector graphics, output as JPG, with varying levels of detail, color, despeckling and more.

Original   Many colors, high detail   Many colors, high detail   Many colors, high detail   Many colors, high detail   Many colors, high detail  

While the potential combinations are endless, if you are using Cloudinary to deliver images, your goal is probably automation, so you'll be looking for a set of options that will produce great results for the types of images you expect, without having to adjust the transformation code for each one.

(Unless of-course you are passing these on as cool effects to your users, and then by all means, feel free to let them adjust these options to their heart's content.)

Summary

The new vectorize effect allows you to easily generate vector graphics from raster images. Whether you want to upscale or reduce the size of your logos and icons, create effective placeholders, just offer another fun effect for your users, or any other usage you might think of, Cloudinary brings these capabilities to you with a simple URL, or using any of our SDKs. There's no need for a creative team, or fancy software editors and deep knowledge of how to use them. Just sign up for your free Cloudinary account, and give it a try.


Want to Learn More About Responsive Images?

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