Rasterization of SVG images

Bhagyashri Kelkar
GumGum Tech Blog
Published in
10 min readFeb 22, 2024

The Scalable Vector Graphics (SVG) stand out among other image formats due to its XML-based structure, offering unique features that are not found in raster images (such as JPEG, PNG) or other vector formats (like EPS, PDF). Nowadays, SVG images have become a standard in digital graphics, publication-ready image assets, branding elements, advertisements and web-animations. They are ubiquitous in modern 2D interfaces due to their ability to scale to different resolutions and are commonly used for representing logos, diagrams, charts, and visualizations in technical and educational contents. SVG images can also be used to create adversarial examples, which are specially crafted images designed to fool machine learning models. In these and other scenarios, classifying SVG images is essential for use cases like extracting useful information from graphical content, automated tagging in content management systems, enhancing user experiences and ensuring the integrity and security of systems that handle graphical data.

However, when it comes to classifying SVG images using deep learning methods like CNN, they present several challenges due to the inherent characteristics of vector graphics. The typical input format for CNNs in image classification tasks is a multi-dimensional array, often referred to as a tensor, which is then processed by deep learning frameworks like TensorFlow or PyTorch. An important step in this process is the conversion of pixels in the image to tensors. SVG images lack pixel-level information primarily due to their fundamentally different data representations. Hence unlike raster images, the SVG images require a different processing pipeline such as parsing the XML structure, interpreting geometric shapes, and converting them into pixel-based, also called as rasterized format. This blog explores typical challenges encountered during the rasterization of SVG images and simple solutions to address them.

The SVG image

In computing, an image refers to a digital depiction of visual content like photos, drawings, charts, and diagrams. There are two main types of images:

  • Raster Images: Also called bitmap images, these consist of a grid of pixels where each pixel holds color and brightness data. Common raster formats include JPEG, PNG, GIF, and BMP. They are resolution-dependent and can appear pixelated when enlarged.
  • Vector Images: Unlike raster images, vectors are composed of geometric shapes like lines, curves, and polygons. They are resolution-independent, allowing them to be scaled to any size without loss of quality. Common vector formats include SVG, EPS, and PDF.

Here’s an illustration of a basic SVG image in XML format, depicting a text inside a circle:

<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
<circle
id="svg_1"
cx="75" cy="75" r="70" fill="#58D3B7"/>
<text
id="svg_2"
stroke="#41aeb8"
font-family="Helvetica, Arial, sans-serif"
font-size="20" y="80.0" x="20.0"
style="fill:teal;font-weight:bold;stroke:red;stroke-width:1"
>Hello World</text>
</svg>

Explanation:

  • The <svg> element defines the SVG document and sets its namespace to “http://www.w3.org/2000/svg". The <svg> element defines the root of the SVG document.
  • The xmlns attribute specifies the XML namespace for SVG.
  • The width and height attributes define the dimensions of the SVG canvas.
  • Inside the <svg> element, the <circle> element is used to create a circle. The cx and cy attributes define the centre coordinates of the circle and the r attribute specifies the radius of the circle. The fill attribute sets the fill colour of the circle (Sky-Blue in this example).
  • Text can be embedded with style and colour.

The XML code then can be saved to a file with a .svg extension (e.g., circle.svg) and opened in any SVG viewer or web browser to see the rendered circle. It will look something like this:

Key characteristics of SVG images

  • Scalability: SVG images are resolution-independent, meaning they can be scaled to any size without losing quality. Their scalability stems from being defined mathematically rather than as fixed pixel grids.
  • Vector-based: SVG images are composed of scalable vector shapes such as lines, curves, and polygons that require crisp edges rather than pixels. This allows for precise rendering at any size and enables editing of individual components within the image.
  • Editable: SVG images are essentially text files written in XML format, which makes them human-readable and easily editable using text editors or specialized SVG editing software. Developers can manipulate SVG files directly by modifying the XML code, making it straightforward to create dynamic and interactive graphics for web applications.
  • Support for Animation and Interactivity: SVG supports animation and interactivity through declarative markup using CSS (Cascading Style Sheets) and JavaScript. This allows developers to create interactive user interfaces, data visualizations, and multimedia presentations directly within the SVG document. Animations in SVG can include transformations, transitions, and keyframe animations.
  • Accessibility: SVG images can be made accessible to users with disabilities by providing alternative text descriptions (using the title and desc elements) and semantic markup (such as <svg> and <a> elements) within the SVG file. This ensures that screen readers and assistive technologies can convey the content of the image to users who may have visual impairments.
  • Compact File Size: SVG files are typically smaller in size compared to equivalent raster images, especially for images with simple geometric shapes and limited colors. This makes SVG an efficient format for delivering graphics over the web, reducing bandwidth usage and improving loading times.

One of the key advantages of using SVG over rasterized images is the potential to leverage large language models like GPT-4 for understanding and manipulating image content based on text prompts. Generative models for vector graphics serve as promising tools, allowing artists to generate, manipulate, and animate vector images, potentially enhancing their creativity and productivity. Overall, SVG offers a powerful solution for creating high-quality graphics that are scalable, editable, accessible, and compatible with modern web standards.

The challenges in processing SVG images

While SVG images offer numerous advantages over other image formats, they also present some challenges in processing compared to raster image formats (e.g., JPEG, PNG), which include:

  • Rendering Complexity: SVG images can contain complex vector shapes, gradients, filters, and effects. Rendering such complex SVG files may require more computational resources compared to raster images, especially for software or libraries that lack efficient SVG rendering engines.
  • Performance: Processing SVG images in real-time, especially in web browsers, can sometimes lead to performance issues, particularly when dealing with large or highly detailed SVG graphics. This can result in slower loading times, especially on devices with limited processing power or memory.
  • Browser Compatibility: While modern web browsers generally have good support for SVG, there can still be variations in how different browsers handle certain SVG features, rendering inconsistencies, or lack of support for newer SVG specifications. Developers may need to implement workarounds or fallbacks for browsers that do not fully support SVG features.
  • File Size: Although SVG files are typically smaller in size compared to equivalent raster images, complex SVG graphics with many shapes, gradients, or embedded fonts can still result in large file sizes. Transmitting or loading large SVG files over the internet may lead to longer loading times and increased bandwidth usage.
  • Security Concerns: SVG files can contain executable code in the form of scripts (e.g., JavaScript) embedded within the SVG document. This poses potential security risks, as malicious code within SVG files could be executed when rendered in a browser or other SVG rendering software. Proper validation and sanitisation of SVG input are necessary to mitigate these risks.
  • Compatibility with Legacy Systems: Some older software or systems may not fully support SVG or may have limited capabilities for processing or rendering SVG images. Compatibility issues may arise when integrating SVG graphics into legacy applications or environments that rely on older image formats.

The Python Imaging Library (PIL)

The Python Imaging Library (PIL) is widely used in various domains, including computer vision, image analysis, web development, and graphic design. It provides the python interpreter with image editing capabilities and a number of factory functions including functions for resizing, cropping, rotating, filtering, and converting between different image formats. However, it’s worth noting that the original PIL library has not been actively maintained since 2011. As a result, many users now use the Pillow library, which is a fork of PIL and is actively maintained and developed. Pillow provides a compatible API with PIL, along with additional features, bug fixes, and performance improvements.

To install Pillow, we can use pip:

pip install Pillow

Once installed, the library can be imported as:

from PIL import Image

The set of available formats supported by PIL can be found by running python3 -m PIL or using the PIL.features.pilinfo().

The PIL.Image module is a class which hosts various functions including functions to load images from files, and to create new images. The PIL.Image.open(fp, mode=’r’, formats=None) opens and identifies the given image file. The parameter fp is either a string representing the path to an image file on disk or a file-like object. A file-like object can be any object that supports the file protocol, such as a file object returned by the open function, an instance of the io.BytesIO class, or any custom object that implements the necessary methods (read, write, seek, etc.) for file-like behavior.

The file-like object used here can be created by using io.BytesIO class in the Python’s io module. The BytesIO is commonly used in the situations where we need to work with binary data in memory, such as when processing image data, handling file uploads in web applications, or interacting with binary data in unit tests. It provides a convenient and efficient way to read from or write to binary data that behaves like a file object without the need for temporary files on disk.

For example, we can open an image file from memory using a BytesIO object like this:

from PIL import Image
import io


# Open an image file from memory using a BytesIO object
with open('example.jpg', 'rb') as f:
image_data = io.BytesIO(f.read())
img = Image.open(image_data)

The io.BytesIO(f.read()) creates a BytesIO object containing the binary data read from the file example.jpg. This BytesIO object behaves like a file object and can be passed to PIL.Image.open as if it were a file on disk.

Working on SVG with Pillow

PIL works with rasterized images. SVGs are vector graphics — it’s not surprising that PIL can’t identify the SVG format. It’s sort of like trying to open a PDF document in Microsoft Word, and expecting to be able to edit the PDF because PDFs and Word files sort of fall into the same category of “documents” with text inside them.

It is also observed that, the PIL.Image.open() throws UnidentifiedImageError Exception with the io.BytesIO object created out of a SVG file as input. This is because io.BytesIO needs a bytes-like object and the SVG is a textual format encoded in XML, not a binary format.

To solve this issue, we need to convert the SVG image into a raster graphic format. There are specialized SVG processing libraries, the most important being the CairoSVG module, that allows to convert SVG data or files into raster images.

CairoSVG

CairoSVG is a SVG converter based on Cairo and is designed to parse well-formed SVG files. Once parsed, the result is drawn to a Cairo surface that can be exported to various formats: PDF, PostScript, PNG and even SVG. It needs SVG files that are XML trees, and uses the ElementTree module in Python to break down the XML document in a tree structure that is easy to work with. It also provides options for customization of the images, such as setting output size, background color, or DPI (dots per inch) and is particularly useful when we need to embed the SVG content in web pages, generate thumbnails, or process SVG data in Python applications. However, it does not support animations, as the output formats are mainly static. More generally, no real DOM support is offered, highly limiting the possibility of implementing features such as JavaScript support.

CairoSVG is available on PyPI, and can be installed with pip:

pip install cairosvg

The following code snippet shows how to render a SVG image using cairosvg.svg2png() and PIL.Image.open().

import io
from PIL import Image
import cairosvg


# Example SVG data
svg_data = b'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="teal" /></svg>'


# Convert SVG data to PNG format using cairosvg
filelike_obj = io.BytesIO(cairosvg.svg2png(svg_data))


# Open the image using PIL
image = Image.open(filelike_obj)


# Perform operations with the image (e.g., display, save, or process it)
image.show()

CairoSVG is not fault tolerant when parsing an XML document. It’s not known to be good at handling erratic SVG files, with for example unknown syntaxes or unavailable external resources. In the following example, the fill-opactity attribute of the SVG somehow has a value represented by the string “null”. The cairosvg.svg2png() throws ValueError exception in this case.

import io
from PIL import Image
import cairosvg


# Example SVG data
svg_data = b'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="teal" fill-opacity="null" /></svg>'


# Convert SVG data to PNG format using cairosvg
filelike_obj = io.BytesIO(cairosvg.svg2png(svg_data))


# Open the image using PIL
image = Image.open(filelike_obj)


# Perform operations with the image (e.g., display, save, or process it)
image.show()
409 # Get stroke and fill opacity
410 stroke_opacity = float(node.get('stroke-opacity', 1))
--> 411 fill_opacity = float(node.get('fill-opacity', 1))
412 if opacity < 1 and not node.children:
413 stroke_opacity *= opacity

ValueError: could not convert string to float: 'null'

This issue can be mitigated by removing null attributes from the SVG file. The function cleanup_svg_content() given below scans the SVG file by using ElementTree and removes them from the file. The cleaned SVG image then can be converted to PNG and further processed by PIL.Image.open().

import io
from PIL import Image
import cairosvg
from xml.etree import ElementTree


def cleanup_svg_content(svg_content):
# Parse SVG file using ElementTree
root = ElementTree.fromstring(svg_content)
# Remove attributes with null values
for elem in root.iter():
attrs_to_remove = []
for k, v in elem.attrib.items():
if v == "null":
attrs_to_remove.append(k)
for attr in attrs_to_remove:
del elem.attrib[attr]
return root

# Example SVG data
svg_data = b'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="teal" fill-opacity="null" /></svg>'

# Remove null valued attributes if any
cleaned_svg = cleanup_svg_content(svg_data)

# Convert SVG data to PNG format using cairosvg
filelike_obj = io.BytesIO(cairosvg.svg2png(bytestring=ElementTree.tostring(cleaned_svg)))

# Open the image using PIL
image = Image.open(filelike_obj)

# Perform operations with the image (e.g., display, save, or process it)
image.show()

Conclusion

SVG remains a versatile and widely used image format, especially in web design, data visualisation, and interactive graphics. If the compatibility issues are handled correctly, SVG offers great potential to perform a variety of vision tasks, thus opening up unique opportunities and applications beyond the traditional domain of vision models.

Credits
I would like to express my heartfelt gratitude to the individuals who have played an instrumental role in the creation of this blog post. Their invaluable contributions have made this project a success, and I am truly grateful for their unwavering support.

We’re always looking for new talent! View jobs.

Follow us: Facebook | Twitter | LinkedIn | Instagram

--

--