I just wanted to convert SVG to PNG files with Python and the library CairoSVG. That was no problem on my Ubuntu system. But running the SVG converter script within a lightweight Alpine Docker container turned out to be problematic. Figuring out which libraries have to be installed up front took me some time. That’s why I like to share my findings here. Hopefully, it’ll save your time.
FROM python:3.6.4-alpine3.7 RUN apk add --no-cache \ build-base cairo-dev cairo cairo-tools \ # pillow dependencies jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev RUN pip install "flask==1.0.1" "CairoSVG==2.1.3" COPY circle.svg / COPY svg-converter-service.py / CMD python3 /svg-converter-service.py
import cairosvg from flask import Flask, Response app = Flask(__name__) @app.route('/image') def convert_image(): png_data = cairosvg.svg2png(url="circle.svg", parent_width=300, parent_height=300) return Response(png_data, mimetype='image/png') if __name__ == '__main__': app.run(debug=True, port=5000, host='0.0.0.0')
You can see the converted PNG by opening
http://localhost:5000/image in the browser.
The complete source code can be found on GitHub in the project cairosvg-on-alpine.
I started my journey with a quite plain Python & Alpine Docker Image without any
FROM python:3.6.4-alpine3.7 RUN pip install "flask==1.0.1" "CairoSVG==2.1.3" COPY circle.svg / COPY svg-converter-service.py / CMD python3 /svg-converter-service.py
That leaded me directly to the first error when pip tries to install
Collecting cairocffi (from CairoSVG==2.1.3) ... Running setup.py (path:/tmp/pip-build-7l3xzt_6/cairocffi/setup.py) egg_info for package cairocffi Running command python setup.py egg_info No working compiler found, or bogus compiler options passed to the compiler from Python's standard "distutils" module. See the error messages above. Likely, the problem is not related to CFFI but generic to the setup.py of any Python package that tries to compile C code. (Hints: on OS/X 10.8, for errors about -mno-fused-madd see http://stackoverflow.com/questions/22313407/ Otherwise, see https://wiki.python.org/moin/CompLangPython or the IRC channel #python on irc.freenode.net.) ... unable to execute 'gcc': No such file or directory
The GNU Compiler Collection aka
gcc is missing. We can fix that by installing
RUN apk add --no-cache build-base
Still, pip can’t install
Running setup.py (path:/tmp/pip-build-3ryf8sen/cairocffi/setup.py) egg_info for package cairocffi ... to the PKG_CONFIG_PATH environment variable Package 'libffi', required by 'virtual:world', not found c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory #include <ffi.h> ^ compilation terminated. Traceback (most recent call last): File "/usr/local/lib/python3.6/distutils/unixccompiler.py", line 118, in _compile extra_postargs) File "/usr/local/lib/python3.6/distutils/ccompiler.py", line 909, in spawn spawn(cmd, dry_run=self.dry_run) File "/usr/local/lib/python3.6/distutils/spawn.py", line 36, in spawn _spawn_posix(cmd, search_path, dry_run=dry_run) File "/usr/local/lib/python3.6/distutils/spawn.py", line 159, in _spawn_posix % (cmd, exit_status)) distutils.errors.DistutilsExecError: command 'gcc' failed with exit status 1
RUN apk add --no-cache build-base cairo-dev cairo cairo-tools
Now we get the following error:
Running setup.py bdist_wheel for pillow: started Running setup.py bdist_wheel for pillow: finished with status 'error' ... The headers or library files could not be found for jpeg, a required dependency when compiling Pillow from source. Please see the install instructions at: https://pillow.readthedocs.io/en/latest/installation.html Traceback (most recent call last): File "/tmp/pip-build-g2zllesg/pillow/setup.py", line 794, in <module> zip_safe=not (debug_build() or PLATFORM_MINGW), ) File "/usr/local/lib/python3.6/site-packages/setuptools/__init__.py", line 129, in setup return distutils.core.setup(**attrs) File "/usr/local/lib/python3.6/distutils/core.py", line 148, in setup dist.run_commands() File "/usr/local/lib/python3.6/distutils/dist.py", line 955, in run_commands self.run_command(cmd) File "/usr/local/lib/python3.6/distutils/dist.py", line 974, in run_command cmd_obj.run() File "/usr/local/lib/python3.6/site-packages/wheel/bdist_wheel.py", line 204, in run self.run_command('build') File "/usr/local/lib/python3.6/distutils/cmd.py", line 313, in run_command self.distribution.run_command(command) File "/usr/local/lib/python3.6/distutils/dist.py", line 974, in run_command cmd_obj.run() File "/usr/local/lib/python3.6/distutils/command/build.py", line 135, in run self.run_command(cmd_name) File "/usr/local/lib/python3.6/distutils/cmd.py", line 313, in run_command self.distribution.run_command(command) File "/usr/local/lib/python3.6/distutils/dist.py", line 974, in run_command cmd_obj.run() File "/usr/local/lib/python3.6/distutils/command/build_ext.py", line 339, in run self.build_extensions() File "/tmp/pip-build-g2zllesg/pillow/setup.py", line 582, in build_extensions raise RequiredDependencyException(f) __main__.RequiredDependencyException: jpeg
Pillow is a Python Imaging library and a dependency of CairoSVG. Pillow, in turn, requires that some libraries are installed on the system. This can be done by adding some dependencies to our
apk command (I looked them up in the Alpine Docker Image in the Pillow GitHub Repo):
RUN apk add --no-cache \ build-base cairo-dev cairo cairo-tools \ # pillow dependencies jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev
Yes! We finally made it! Our Alpine Docker container with CairoSVG and Cairo is up and running. Opening
http://localhost:5000/image in the browser will show the converted PNG.
Extra: Local Development (under Ubuntu)
During development, we don’t want to rebuild the Alpine Docker image after every change in the Python script. Fortunately, it’s easy to execute the script locally because, on Ubuntu, we don’t have to install all these native C libraries (tested with Ubuntu 17.04).
I like to use pipenv for local development. We only need a
Pipfile containing our dependencies flask and CairoSVG:
[[source]] url = "https://pypi.python.org/simple" verify_ssl = true name = "pypi" [packages] flask = "==0.12.2" CairoSVG = "==2.1.3" [dev-packages] [requires] python_version = "3.6"
Start the Python script:
# pip install pipenv pipenv install pipenv shell cd src python svg-converter-service.py
All files can be found on GitHub.
This worked for me the last time. However, I somehow used to get the error
ModuleNotFoundError: No module named 'PIL':
Traceback (most recent call last): File "svg-converter-service.py", line 3, in <module> import cairosvg File "/home/pha/.local/share/virtualenvs/cairosvg-on-alpine--SwTTCnJ/lib/python3.6/site-packages/cairosvg/__init__.py", line 29, in <module> from . import surface File "/home/pha/.local/share/virtualenvs/cairosvg-on-alpine--SwTTCnJ/lib/python3.6/site-packages/cairosvg/surface.py", line 34, in <module> from .image import image File "/home/pha/.local/share/virtualenvs/cairosvg-on-alpine--SwTTCnJ/lib/python3.6/site-packages/cairosvg/image.py", line 25, in <module> from PIL import Image ModuleNotFoundError: No module named 'PIL'
Most likely, this means that Pillow couldn’t be installed by pip because the mentioned native C libraries are missing. Try
sudo apt-get install python3-dev python3-setuptools libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.5-dev tk8.5-dev.