Sending SVG Images by SMS and WhatsApp with Python and CairoSVG
Time to read: 5 minutes
Twilio Programmable Messaging makes it easy to embed images in text messages, but a notable omission in the list of supported formats is Scalable Vector Graphics (SVG). While SVG is not one of the most popular image formats, it is the preferred choice for generating diagrams and charts, because this format renders without quality degradation at any resolution.
So what do you do if you have an SVG image and need to send it via SMS or WhatsApp? In this article I will show you how I use the CairoSVG package for Python to convert SVG images to the PNG format, which the messaging APIs support.
Tutorial requirements
The only requirement that you need for this tutorial is Python 3.6 or newer. If your operating system does not provide a Python interpreter, you can go to python.org to download an installer.
Installing CairoSVG
Let’s begin by creating a directory where we can implement this project:
Following best practices, we are now going to create a virtual environment where we will install our Python dependencies.
If you are using a Unix or MacOS system, open a terminal and enter the following commands to do the tasks described above:
For those of you following the tutorial on Windows, enter the following commands in a command prompt window:
The Python package that we have installed are:
- The cairosvg package, to render SVG files to PNG images that we can send through WhatsApp and SMS.
- The Flask framework, to create the web application that can convert SVG images to PNG on the fly.
The CairoSVG package requires the cairo library installed in your system. The installation procedure for this library is different depending on the operating system, so follow the instructions that apply to your system below.
Installing Cairo on Linux
Under Linux your package manager will likely provide a packaged version of the Cairo graphics library, either under the name libcairo2
, libcairo
or maybe cairo
.
If you are using Ubuntu Linux, you can install the libcairo2
package as follows:
Installing Cairo on Mac OS
The easiest way to install the Cairo library on a Mac computer is to use Homebrew. Assuming you have installed this package manager on your system, the command to install Cairo is:
Installing Cairo on Windows
On Windows I had no luck finding an installer for the Cairo library, so I had to get creative. I knew that GIMP, a popular open-source photo editor, uses this library, so I installed this application and then searched for the Cairo DLL and all of its dependencies in the installation directory.
I’ve created two zip files with the ready to be used Cairo DLLs for you to download. Please choose the appropriate version of these libraries depending on the version of Python you are using:
- Download libcairo-x64.zip for the 64-bit version of Python
- Download libcairo-x86.zip for the 32-bit version of Python
Once you have the zip file downloaded, extract its contents on the project directory, or in any directory that is in the system path.
Converting SVG images with CairoSVG
If you don’t have an example SVG file that you can use in the examples in this section, feel free to download the one I’m using, which is a diagram of a chess board.
If you open this file in your web browser, you’ll notice that the file scales automatically as you resize the window.
Let’s convert this file to the PNG format in a Python shell using the cairosvg.svg2png()
function:
Here we are passing the contents of the SVG file in the bytestring
argument and the name of the output PNG file in the write_to
argument. Open the board.png file in your browser and you will notice that unlike the SVG original this image has a fixed size.
The size of the generated PNG image will depend on the size hints included in the SVG file itself. The chess board SVG file that I’m using indicates a default size of 390 x 390 pixels, so that is the size of the resulting PNG. But as you saw before, SVG files can be rendered at any resolution without degradation, so we can tell CairoSVG to render it at any size by adding the parent_width
and parent_height
arguments:
Implementing an image conversion endpoint
To send an image through the Twilio messaging APIs we don’t provide the image data as a file, instead we specify a URL from where Twilio downloads the image on its own.
We can implement an endpoint that converts and returns the PNG image on the fly by changing the write_to
argument from a filename to a byte stream:
When you run the conversion in this way you end up with the PNG data stored in memory. The actual PNG data stored in the png
variable can be obtained with the expression png.getvalue()
. This data can then be returned as the response of the endpoint.
To help you understand how such an endpoint can be implemented, below you can see a simple, yet complete, Flask application that uses the techniques shown in this article to perform on-the-fly conversion of an SVG image to PNG. If you want to test this application out, create a file in the root directory of your project named app.py and copy the code below to it:
The application takes optional width
and height
arguments, obtained from the query string of the request URL (you will see in a moment how to provide these arguments). It then converts the SVG image to PNG, writing the resulting output to a bytes stream. It finally returns the image data with a 200 status code and the Content-Type
header set to image/png
, which is the correct setting to tell the client (be it Twilio or a web browser) that this endpoint is returning data that should be interpreted as a PNG image.
Start the application as follows:
Then enter http://localhost:5000/svg2png in the address bar of your web browser to check that you are getting the converted image displayed in your browser.
Since we haven’t specified a width or height the image in this case will render with the default size indicated in the SVG file.
Let’s now ask for the image to be generated in a specific size. In the address bar of your browser, enter http://localhost:5000/svg2png?width=200&height=200 to request that the image be resized to 200 x 200 pixels.
So that’s it. Now we have a web endpoint that converts an SVG image on the fly to PNG and returns it in the proper way to be used by the Twilio messaging APIs!
Feel free to experiment with different SVG files, or if you prefer, use the file upload capabilities of the Flask framework to upload and convert your images in a single step. I have written a detailed tutorial on uploading images with Flask that will be useful if you want to implement this feature.
Conclusion
I hope that you learned some helpful techniques in this article. Would you like to see how these are applied to a real Twilio-based application? Check out my Play Chess with a Friend on WhatsApp tutorial on this blog!
Miguel Grinberg is a Python Developer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool Python project you’d like to share on this blog!
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.