Giter Site home page Giter Site logo

deeplook / svglib Goto Github PK

View Code? Open in Web Editor NEW
302.0 8.0 80.0 2.88 MB

Read SVG files and convert them to other formats.

License: GNU Lesser General Public License v3.0

Python 99.62% Roff 0.38%
svg python pdf pdf-generation rendering graphics documents vector-graphics

svglib's Introduction

Svglib

A pure-Python library for reading and converting SVG

image

pre-commit.ci status

image

image

image

image

image

image

image

image

image

image

About

Svglib is a pure-Python library for reading SVG files and converting them (to a reasonable degree) to other formats using the ReportLab Open Source toolkit.

Used as a package you can read existing SVG files and convert them into ReportLab Drawing objects that can be used in a variety of contexts, e.g. as ReportLab Platypus Flowable objects or in RML. As a command-line tool it converts SVG files into PDF ones (but adding other output formats like bitmap or EPS is really easy and will be better supported, soon).

Tests include a huge W3C SVG test suite plus ca. 200 flags from Wikipedia and some selected symbols from Wikipedia (with increasingly less pointing to missing features).

Features

  • convert SVG files into ReportLab Graphics Drawing objects
  • handle plain or compressed SVG files (.svg and .svgz)
  • allow patterns for output files on command-line
  • install a Python package named svglib
  • install a Python command-line script named svg2pdf
  • provide a PyTest test suite with over 90% code coverage
  • test entire W3C SVG test suite after pulling from the internet
  • test all SVG flags from Wikipedia after pulling from the internet
  • test selected SVG symbols from Wikipedia after pulling from the net
  • support Python 3.7+ and PyPy3

Known limitations

  • @import rules in stylesheets are ignored. CSS is supported, but the range of supported attributes is still limited
  • clipping is limited to single paths, no mask support
  • color gradients are not supported (limitation of reportlab)
  • SVG ForeignObject elements are not supported.

Examples

You can use svglib as a Python package e.g. like in the following interactive Python session:

>>> from svglib.svglib import svg2rlg
>>> from reportlab.graphics import renderPDF, renderPM
>>>
>>> drawing = svg2rlg("file.svg")
>>> renderPDF.drawToFile(drawing, "file.pdf")
>>> renderPM.drawToFile(drawing, "file.png", fmt="PNG")

Note that the second parameter of drawToFile can be any Python file object, like a BytesIO buffer if you don't want the result to be written on disk for example.

In addition a script named svg2pdf can be used more easily from the system command-line. Here is the output from svg2pdf -h:

usage: svg2pdf [-h] [-v] [-o PATH_PAT] [PATH [PATH ...]]

svg2pdf v. x.x.x
A converter from SVG to PDF (via ReportLab Graphics)

positional arguments:
  PATH                  Input SVG file path with extension .svg or .svgz.

optional arguments:
  -h, --help            show this help message and exit
  -v, --version         Print version number and exit.
  -o PATH_PAT, --output PATH_PAT
                        Set output path (incl. the placeholders: dirname,
                        basename,base, ext, now) in both, %(name)s and {name}
                        notations.

examples:
  # convert path/file.svg to path/file.pdf
  svg2pdf path/file.svg

  # convert file1.svg to file1.pdf and file2.svgz to file2.pdf
  svg2pdf file1.svg file2.svgz

  # convert file.svg to out.pdf
  svg2pdf -o out.pdf file.svg

  # convert all SVG files in path/ to PDF files with names like:
  # path/file1.svg -> file1.pdf
  svg2pdf -o "%(base)s.pdf" path/file*.svg

  # like before but with timestamp in the PDF files:
  # path/file1.svg -> path/out-12-58-36-file1.pdf
  svg2pdf -o {{dirname}}/out-{{now.hour}}-{{now.minute}}-{{now.second}}-%(base)s.pdf path/file*.svg

issues/pull requests:
    https://github.com/deeplook/svglib

Copyleft by Dinu Gherman, 2008-2021 (LGPL 3):
    http://www.gnu.org/copyleft/gpl.html

Dependencies

Svglib depends mainly on the reportlab package, which provides the abstractions for building complex Drawings which it can render into different fileformats, including PDF, EPS, SVG and various bitmaps ones. Other dependancies are lxml which is used in the context of SVG CSS stylesheets.

Installation

There are three ways to install svglib.

1. Using pip

With the pip command on your system and a working internet connection you can install the newest version of svglib with only one command in a terminal:

$ pip install svglib

You can also use pip to install the very latest version of the repository from GitHub, but then you won't be able to conveniently run the test suite:

$ pip install git+https://github.com/deeplook/svglib

2. Using conda

If you use Anaconda or Miniconda you are surely using its respective package manager, Conda, as well. In that case you should be able to install svglib using these simple commands:

$ conda config --add channels conda-forge
$ conda install svglib

Svglib was kindly packaged for conda by nicoddemus. See here more about svglib with conda.

3. Manual installation

Alternatively, you can install a tarball like svglib-<version>.tar.gz after downloading it from the svglib page on PyPI or the svglib releases page on GitHub and executing a sequence of commands like shown here:

$ tar xfz svglib-<version>.tar.gz
$ cd svglib-<version>
$ python setup.py install

This will install a Python package named svglib in the site-packages subfolder of your Python installation and a script tool named svg2pdf in your bin directory, e.g. in /usr/local/bin.

Testing

The svglib tarball distribution contains a PyTest test suite in the tests directory. There, in tests/README.rst, you can also read more about testing. You can run the testsuite e.g. like shown in the following lines on the command-line:

$ tar xfz svglib-<version>.tar.gz
$ cd svglib-<version>
$ PYTHONPATH=. py.test
======================== test session starts =========================
platform darwin -- Python 3.7.3, pytest-5.0.1, py-1.8.0, pluggy-0.12.0
rootdir: /Users/dinu/repos/github/deeplook/svglib, inifile:
plugins: cov-2.4.0
collected 36 items

tests/test_basic.py ............................
tests/test_samples.py .s.s.s.s

=============== 32 passed, 4 skipped in 49.18 seconds ================

Bug reports

Please report bugs on the svglib issue tracker on GitHub (pull requests are also appreciated)! If necessary, please include information about the operating system, as well as the versions of svglib, ReportLab and Python being used!

svglib's People

Contributors

ajbrock avatar chrisbennight avatar claudep avatar dbasedow avatar deeplook avatar deepsource-autofix[bot] avatar deepsourcebot avatar donkirkby avatar eumiro avatar felixfrog avatar gagath avatar grhawk avatar jdgwf avatar kiinami avatar lgtm-com[bot] avatar lordmauve avatar mgorny avatar mosc9575 avatar nicoddemus avatar pre-commit-ci[bot] avatar quantifiedcode-bot avatar replabrobin avatar rogalek avatar stefanw avatar stickerfiend avatar tadeu avatar tomturner avatar victorbnl avatar wgundamj44 avatar winglq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

svglib's Issues

Coloured markers get filled with black upon rendering as PDF

I've got a simple matplotlib graph with one red and one green marker. Saving the figure as svg it renders correctly (attached graph.svg). When I draw the same graph on a reportlab Canvas and save it the markers are now filled with black (attached document.pdf).

Any idea on what is causing this behaviour? This is on Python 2.7, Ubuntu 14.04 running with the latest versions of reportlab and svglib . Script and requirements.txt to reproduce are attached.

Thanks

Attachments are in the zip below
svgbug.zip

Slow to install

I installed svglib today with pip.

The install didn't finish before something timed out.

I disabled test cases, installs and works fine. It wasn't use CPU - maybe a download hung or something.

I couldn't work out why, I'll have a look later.

Fix test suite when reading image file

Looks like after moving the test suite one level up some images for the W3C SVG tests cannot be found anymore. Same on Py2 and 3.

svglib $ py.test -v -s tests/test_samples.py
[...]
============================================================= FAILURES =============================================================
___________________________________________________ TestW3CSVG.test_convert_pdf ____________________________________________________

self = <test_samples.TestW3CSVG object at 0x108d41a10>

    def test_convert_pdf(self):
        "Test converting W3C SVG files to PDF using svglib."

        exclude_list = [
            "paint-stroke-06-t.svg",
            "coords-trans-09-t.svg",  # renderPDF issue (div by 0)
            # ExpatError while parsing due to the ev namespace
            "interact-order-04-t.svg",
            "interact-order-05-t.svg",
            "media-video-220-t.svg",
            "script-listener-201-t.svg",
            # Unsupported 'transform="ref(svg, ...)"' expression
            "coords-constr-201-t.svg",
            "coords-constr-202-t.svg",
            "coords-constr-203-t.svg",
            "coords-constr-204-t.svg",
            # Errors to be investigated
            "udom-event-207-t.svg",
        ]

        paths = glob.glob("%s/svg/*.svg" % self.folder_path)
        msg = "Destination folder '%s/svg' not found." % self.folder_path
        assert len(paths) > 0, msg

        for i, path in enumerate(paths):
            print("working on [%d] %s" % (i, path))

            if basename(path) in exclude_list:
                print("excluded (to be tested later)")
                continue

            # convert
            drawing = svglib.svg2rlg(path)

            # save as PDF
            base = splitext(path)[0] + '-svglib.pdf'
>           renderPDF.drawToFile(drawing, base, showBoundary=0)

tests/test_samples.py:428:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:288: in drawToFile
    draw(d, c, 0, 0, showBoundary=showBoundary)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:29: in draw
    R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:199: in draw
    self.drawNode(drawing)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:55: in drawNode
    self.drawNodeDispatcher(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:280: in drawNodeDispatcher
    self.drawGroup(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:309: in drawGroup
    self.drawNode(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:55: in drawNode
    self.drawNodeDispatcher(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:280: in drawNodeDispatcher
    self.drawGroup(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:309: in drawGroup
    self.drawNode(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:55: in drawNode
    self.drawNodeDispatcher(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:280: in drawNodeDispatcher
    self.drawGroup(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:309: in drawGroup
    self.drawNode(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:55: in drawNode
    self.drawNodeDispatcher(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderbase.py:264: in drawNodeDispatcher
    self.drawImage(node)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/graphics/renderPDF.py:87: in drawImage
    image.width, image.height
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfgen/canvas.py:852: in drawInlineImage
    img_obj = PDFImage(image, x,y, width, height)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfgen/pdfimages.py:40: in __init__
    self.getImageData()
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfgen/pdfimages.py:156: in getImageData
    imagedata, imgwidth, imgheight = self.non_jpg_imagedata(image)  #try for normal kind of image
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfgen/pdfimages.py:138: in non_jpg_imagedata
    imagedata = pdfutils.cacheImageFile(image,returnInMemory=1)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfbase/pdfutils.py:95: in cacheImageFile
    code = makeA85Image(filename,IMG)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/pdfbase/pdfutils.py:38: in makeA85Image
    raw = img.getRGBData()
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/lib/utils.py:883: in getRGBData
    annotateException('\nidentity=%s'%self.identity())
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/lib/utils.py:1387: in annotateException
    rl_reraise(t,v,b)
/Users/dinu/miniconda2/lib/python2.7/site-packages/reportlab/lib/utils.py:880: in getRGBData
    self._data = (im.tobytes if hasattr(im, 'tobytes') else im.tostring)()  #make pillow and PIL both happy, for now
/Users/dinu/miniconda2/lib/python2.7/site-packages/PIL/Image.py:678: in tobytes
    self.load()
/Users/dinu/miniconda2/lib/python2.7/site-packages/PIL/ImageFile.py:235: in load
    raise_ioerror(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

error = -2

    def raise_ioerror(error):
        try:
            message = Image.core.getcodecstatus(error)
        except AttributeError:
            message = ERRORS.get(error)
        if not message:
            message = "decoder error %d" % error
>       raise IOError(message + " when reading image file")
E       IOError: broken data stream when reading image file
E       identity=[ImageReader@0x1099eaad0 filename=u'/Users/dinu/repos/github/deeplook/svglib/tests/samples/W3C_SVG_12_TinyTestSuite/svg/../images/cloudqllo.jpg']

/Users/dinu/miniconda2/lib/python2.7/site-packages/PIL/ImageFile.py:59: IOError
========================================== 1 failed, 3 passed, 4 skipped in 40.64 seconds ==========================================

Paths are closed which shouldn't be

I think there might be an issue with closing paths which also shows in a series of flag examples, e.g. that of Bhutan. I've condensed the following minimal example from tests/samples/wikipedia/symbols/Flower-of-Life-small.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
	xmlns:svg="http://www.w3.org/2000/svg"
	xmlns="http://www.w3.org/2000/svg"
	width="304"
	height="304"
	id="svg2"
	version="1.0">
	<g
		id="idLayerDrawing"
		style="display:inline"
		transform="translate(-348,-348)">
		<path
			style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
			id="path4481"
			d="M 543.30127,375 A 50,50 0 0 1 500,400"
			transform="translate(-43.30127,-25)"
			/>
	</g>
</svg>

Clearly, there is no z in the path here, but for some reason this seems to be ok. Maybe it's the fill-rule:nonzero style... (well, apparently not).

TypeError: patchedRenderPath() got an unexpected keyword argument 'forceClose'

  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/platypus/flowables.py", line 111, in drawOn
    self._drawOn(canvas)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/platypus/flowables.py", line 92, in _drawOn
    self.draw()#this is the bit you overload
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/shapes.py", line 697, in draw
    renderPDF.draw(self, self.canv, 0, 0, showBoundary=showBoundary)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 29, in draw
    R.draw(renderScaledDrawing(drawing), canvas, x, y, showBoundary=showBoundary)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 201, in draw
    self.drawNode(drawing)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 282, in drawNodeDispatcher
    self.drawGroup(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 311, in drawGroup
    self.drawNode(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 282, in drawNodeDispatcher
    self.drawGroup(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 311, in drawGroup
    self.drawNode(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 282, in drawNodeDispatcher
    self.drawGroup(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 311, in drawGroup
    self.drawNode(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 282, in drawNodeDispatcher
    self.drawGroup(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 311, in drawGroup
    self.drawNode(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 282, in drawNodeDispatcher
    self.drawGroup(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 311, in drawGroup
    self.drawNode(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 54, in drawNode
    self.drawNodeDispatcher(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderbase.py", line 278, in drawNodeDispatcher
    self.drawPath(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/reportlab/graphics/renderPDF.py", line 184, in drawPath
    isClosed = _renderPath(path, drawFuncs, forceClose=fill and autoclose=='pdf')
TypeError: patchedRenderPath() got an unexpected keyword argument 'forceClose'

https://github.com/deeplook/svglib/blob/283aa1d/svglib/svglib.py#L1062

Missing arguments.

ZeroDivisionError: float division by zero

When calling svg2rlg with the SVG file below, I get a ZeroDivisionError

File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 1040, in svg2rlg
    drawing = svgRenderer.render(svg)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 373, in render
    main_group = self.renderNode(svg_node)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 394, in renderNode
    item = self.renderSvg(n)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 484, in renderSvg
    self.renderNode(child, group)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 403, in renderNode
    item = self.renderG(n, clipping=clipping)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 494, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 403, in renderNode
    item = self.renderG(n, clipping=clipping)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 494, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 403, in renderNode
    item = self.renderG(n, clipping=clipping)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 494, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 416, in renderNode
    item = self.shape_converter.convertShape(name, n, clipping)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 567, in convertShape
    shape = getattr(self, method_name)(node)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/svglib.py", line 865, in convertPath
    bp = bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2)
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/utils.py", line 238, in bezier_arc_from_end_points
    x1, y1, x2, y2, fA, fS, rx, ry
  File "/home/chartdev/venv/lib/python3.5/site-packages/svglib/utils.py", line 148, in end_point_to_center_parameters
    r = 1 / r - 1
ZeroDivisionError: float division by zero

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin" viewBox="0 0 800 400" width="800" height="400"><rect transform="translate(1, 1)" width="798" height="398" class="background" fill-opacity="0" style="shape-rendering: crispEdges"/><g class="chart-body" pointer-events="all" transform="translate(10, 20)"><rect width="780" height="370" fill-opacity="0" style="shape-rendering: crispEdges"/><g transform="translate(679, 0)" class="legends" id="hejbyxuxkg" style="font-size:11px;font-family:Open Sans;fill:#000000"><g class="legend"><desc>{"dataset_id": 0}</desc><circle fill="#6990AD" cx="3.5" cy="8.5" r="3.5"/><text x="11.5" y="12.25">0.0% First zero</text></g><g class="legend"><desc>{"dataset_id": 1}</desc><circle fill="#FAC069" cx="3.5" cy="25.5" r="3.5"/><text x="11.5" y="29.25">0.0% Second zero</text></g></g><g><g><path d="M334.500000 0.000000 A185.000000 185.000000 0 0 1 334.500000 0.000000 L334.500000 185.000000 A0.000000 0.000000 0 0 0 334.500000 185.000000 z" class="slice tooltip-trigger" data-tooltip-pt="334.5:92.5" fill="#6990AD"/></g><g><path d="M334.500000 0.000000 A185.000000 185.000000 0 0 1 334.500000 0.000000 L334.500000 185.000000 A0.000000 0.000000 0 0 0 334.500000 185.000000 z" class="slice tooltip-trigger" data-tooltip-pt="334.5:92.5" fill="#FAC069"/></g></g></g><desc class="metadata">{"hide_tooltip": false, "layers": [{"y_labels": ["0 (0.0%)"], "color": "#6990AD", "title": "First zero", "raw_y_value": 0, "points": [334.5, 185.0]}, {"y_labels": ["0 (0.0%)"], "color": "#FAC069", "title": "Second zero", "raw_y_value": 0, "points": [334.5, 185.0]}]}</desc><g transform="translate(1, 1)"><g transform="translate(374.0, -2.5)" opacity="1.0" display="none" class="drag-handle-icon hover" fill="rgb(179, 179, 179)"><svg width="30" height="15.0" viewBox="0 0 38 6" version="1.1" id="seormugiwy">
    <g stroke-width="1" fill-rule="evenodd">
        <rect x="0" y="0" width="2" height="2"/>
        <rect x="4" y="0" width="2" height="2"/>
        <rect x="0" y="4" width="2" height="2"/>
        <rect x="4" y="4" width="2" height="2"/>
        <rect x="8" y="0" width="2" height="2"/>
        <rect x="12" y="0" width="2" height="2"/>
        <rect x="8" y="4" width="2" height="2"/>
        <rect x="12" y="4" width="2" height="2"/>
        <rect x="16" y="0" width="2" height="2"/>
        <rect x="16" y="4" width="2" height="2"/>
        <rect x="20" y="0" width="2" height="2"/>
        <rect x="24" y="0" width="2" height="2"/>
        <rect x="20" y="4" width="2" height="2"/>
        <rect x="24" y="4" width="2" height="2"/>
        <rect x="28" y="0" width="2" height="2"/>
        <rect x="32" y="0" width="2" height="2"/>
        <rect x="28" y="4" width="2" height="2"/>
        <rect x="32" y="4" width="2" height="2"/>
        <rect x="36" y="0" width="2" height="2"/>
        <rect x="36" y="4" width="2" height="2"/>
    </g>
</svg></g><g class="title drag-handle" pointer-events="all"><rect width="778" height="10" class="title-background" fill-opacity="0" stroke-dasharray="0 788 778 10"/><g transform="translate(10, 0)"/></g></g><g transform="translate(779, 1)" class="settings-button" pointer-events="all" display="none"><rect width="20" height="30" fill-opacity="0.0" fill="#000000"/><circle cx="10.0" cy="10.0" r="1.6666666666666667" fill="#b3b3b3"/><circle cx="10.0" cy="15.0" r="1.6666666666666667" fill="#b3b3b3"/><circle cx="10.0" cy="20.0" r="1.6666666666666667" fill="#b3b3b3"/></g></svg>

Modernize test suite

  • move src/test directory one level up and rename to tests
  • convert unittest to pytest (done)
  • add tox.ini and/or pytest.ini

font-family not handled properly?

The example document uses the fonts "Dingbats", "Verdana", "serif", "Times-Roman" and "Helvetica". In the generated PDF I can only find "/Times-Roman" (may be a correct substitute for "serif") and "Helvetica".

  1. "serif" seems to be handle properly, see second line ("Zeile 3")
  2. "Times-Roman" and "Helvetica seem to be handled properly, see second text-block: Times (green) renders differently than Helvetica (black).
  3. "Dingbats" is ignored, see fist line (blue).
  4. "Verdana" is ignored, see last block: The text using Helvetica (black) is printed at the same position as the second one using Verdana (red). While Verdana is different from Helvetica, the text is rendering the same, as you can see.
<?xml version="1.0" standalone="no"?>
<svg width="210mm" height="297mm"
     xmlns="http://www.w3.org/2000/svg" version="2">
<text x="5cm" y="10cm" xml:space="preserve"
      font-family="Dingbats" font-size="32" fill="blue"><tspan/>
<tspan>Hello, out </tspan>
<tspan font-weight="bold" fill="red">not</tspan><tspan> there!</tspan>
<tspan font-family="serif" x="5cm" dy="32">Zeile 3 iIlL</tspan>
  </text>

<text x="5cm" y="13cm"
      font-family="Times-Roman" font-size="32" fill="lightgreen">
2. Hello, out not there!</text>
<text x="5cm" y="13cm"
      font-family="Helvetica" font-size="32">
3. Hello, out not there!</text>

<text x="5cm" y="14.5cm"
      font-family="Verdana" font-size="32" fill="red">
4. Hello, out not there!</text>
<text x="5cm" y="14.5cm"
      font-family="Helvetica" font-size="32">
5. Hello, out not there!</text>

</svg>

grafik

CI setup

Hi,

First for all thanks for all your work on this package!

I'm building a conda version of this package for conda-forge and it seems to work fine except for two failing tests:

pytest tests -k "not TestWikipediaFlags.test_convert_pdf"
============================= test session starts =============================
platform win32 -- Python 3.5.3, pytest-3.1.0, py-1.4.33, pluggy-0.4.0
rootdir: e:\Miniconda3\conda-bld\svglib_1495798629498\test_tmp, inifile:
collected 36 items

tests\test_basic.py ............................
tests\test_samples.py .s.sEsEs

=================================== ERRORS ====================================
____________ ERROR at setup of TestWikipediaFlags.test_convert_pdf ____________

self = <test_samples.TestWikipediaFlags object at 0x0000015977C3F588>

    def setup_method(self):
        "Check if files exists, else download."

        self.folder_path = "%s/samples/wikipedia/flags" % TEST_ROOT

        # create directory if not already present
        if not exists(self.folder_path):
            os.mkdir(self.folder_path)

        # fetch flags.html, if not already present
        path = join(self.folder_path, "flags.html")
        if not exists(path):
            u = "https://en.wikipedia.org/wiki/Gallery_of_sovereign_state_flags"
            data = self.fetch_file(u)
            if data:
>               open(path, "w").write(data)

tests\test_samples.py:253:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <encodings.cp1252.IncrementalEncoder object at 0x0000015977C3F438>
input = '<!DOCTYPE html>\r\n<html class="client-nojs" lang="en" dir="ltr">\r\n<head>\r\n<meta charset="UTF-8"/>\r\n<title>Gall...unction(){mw.config.set({"wgBackendResponseTime":2026,"wgHostname":"mw1216"});});</script>\r\n\t</body>\r\n</html>\r\n'
final = False

    def encode(self, input, final=False):
>       return codecs.charmap_encode(input,self.errors,encoding_table)[0]
E       UnicodeEncodeError: 'charmap' codec can't encode character '\u2010' in position 250325: character maps to <undefined>

..\_t_env\lib\encodings\cp1252.py:19: UnicodeEncodeError
______________ ERROR at setup of TestW3CSVG.test_convert_pdf_png ______________

self = <test_samples.TestW3CSVG object at 0x00000159753C7B00>

    def setup_method(self):
        "Check if testsuite archive exists, else download and unpack it."

        server = "http://www.w3.org"
        path = "/Graphics/SVG/Test/20070907/W3C_SVG_12_TinyTestSuite.tar.gz"
        url = server + path

        archive_path = basename(url)
        tar_path = splitext(archive_path)[0]
        self.folder_path = join(TEST_ROOT, "samples", splitext(tar_path)[0])
        if not exists(self.folder_path):
            if not exists(join(TEST_ROOT, "samples", tar_path)):
                if not exists(join(TEST_ROOT, "samples", archive_path)):
                    print("downloading %s" % url)
                    try:
                        data = urlopen(url).read()
                    except IOError as details:
                        print(details)
                        print("Check your internet connection and try again!")
                        return
                    archive_path = basename(url)
                    open(join(TEST_ROOT, "samples", archive_path), "wb").write(data)
                print("unpacking %s" % archive_path)
                tar_data = gzip.open(join(TEST_ROOT, "samples", archive_path), "rb").read()
                open(join(TEST_ROOT, "samples", tar_path), "wb").write(tar_data)
            print("extracting into %s" % self.folder_path)
            os.mkdir(self.folder_path)
            tar_file = tarfile.TarFile(join(TEST_ROOT, "samples", tar_path))
            tar_file.extractall(self.folder_path)
            if exists(join(TEST_ROOT, "samples", tar_path)):
>               os.remove(join(TEST_ROOT, "samples", tar_path))
E               PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'e:\\Miniconda3\\conda-bld\\svglib_1495798629498\\test_tmp\\tests\\samples\\W3C_SVG_12_TinyTestSuite.tar'

tests\test_samples.py:371: PermissionError
---------------------------- Captured stdout setup ----------------------------
downloading http://www.w3.org/Graphics/SVG/Test/20070907/W3C_SVG_12_TinyTestSuite.tar.gz
unpacking W3C_SVG_12_TinyTestSuite.tar.gz
extracting into e:\Miniconda3\conda-bld\svglib_1495798629498\test_tmp\tests\samples\W3C_SVG_12_TinyTestSuite
============================== warnings summary ===============================
tests/test_basic.py::TestTransformAttrConverter::()::test_0
  e:\Miniconda3\conda-bld\svglib_1495798629498\_t_env\lib\site-packages\svglib\svglib.py:191: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
    logger.warn("Unable to parse transform expression '%s'" % svgAttr)

tests/test_samples.py::TestSVGSamples::()::test_convert_pdf
  e:\Miniconda3\conda-bld\svglib_1495798629498\_t_env\lib\site-packages\svglib\svglib.py:294: DeprecationWarning: The 'warn' method is deprecated, use 'warning' instead
    logger.warn("Can't handle color: %s" % text)

tests/test_samples.py::TestWikipediaFlags::()::test_convert_pdf
  e:\Miniconda3\conda-bld\svglib_1495798629498\test_tmp\tests\test_samples.py:253: ResourceWarning: unclosed file <_io.TextIOWrapper name='e:\\Miniconda3\\conda-bld\\svglib_1495798629498\\test_tmp\\tests/samples/wikipedia/flags\\flags.html' mode='w' encoding='cp1252'>
    open(path, "w").write(data)

tests/test_samples.py::TestW3CSVG::()::test_convert_pdf_png
  e:\Miniconda3\conda-bld\svglib_1495798629498\test_tmp\tests\test_samples.py:362: ResourceWarning: unclosed file <_io.BufferedWriter name='e:\\Miniconda3\\conda-bld\\svglib_1495798629498\\test_tmp\\tests\\samples\\W3C_SVG_12_TinyTestSuite.tar.gz'>
    open(join(TEST_ROOT, "samples", archive_path), "wb").write(data)
  e:\Miniconda3\conda-bld\svglib_1495798629498\test_tmp\tests\test_samples.py:365: ResourceWarning: unclosed file <_io.BufferedWriter name='e:\\Miniconda3\\conda-bld\\svglib_1495798629498\\test_tmp\\tests\\samples\\W3C_SVG_12_TinyTestSuite.tar'>
    open(join(TEST_ROOT, "samples", tar_path), "wb").write(tar_data)

-- Docs: http://doc.pytest.org/en/latest/warnings.html
========= 30 passed, 4 skipped, 5 warnings, 2 error in 56.93 seconds ==========

This happens for both py27 and py35.

The tests seem simple to solve, but I notice there's no continuous integration for Windows and Travis actually on the repository. @deeplook is this something you would be interested to add to this project?

font-weight is not handled

<text> and <tspan> do not handle font-weight.

The following document renders the same text at almost the same position. The second one should be bold (with the "not" rendered normal). As you can see, both text have the same width.

<?xml version="1.0" standalone="no"?>
<svg width="210mm" height="297mm"
     xmlns="http://www.w3.org/2000/svg" version="2">
<text x="5cm" y="10cm" xml:space="preserve"
      font-family="Verdana" font-size="32" fill="blue"><tspan/>
<tspan>Hello, out </tspan>
<tspan font-weight="bold" fill="red">not</tspan><tspan> there!</tspan>
<tspan x="5cm" dy="32">Zeile 2b iIlL</tspan>
<tspan font-family="serif" x="5cm" dy="32">Zeile 3 iIlL</tspan>
  </text>

<text x="5cm" y="10.1cm" xml:space="preserve"
      font-family="Verdana" font-size="32" font-weight="bold" ><tspan/>
<tspan>Hello, out </tspan>
<tspan font-weight="normal" fill="lightgreen">not</tspan><tspan> there!</tspan>
<tspan x="5cm" dy="32">Zeile 2b iIlL</tspan>
<tspan font-family="serif" x="5cm" dy="32">Zeile 3 iIlL</tspan>
  </text>
</svg>

grafik

chinese chars rendering

@deeplook , my svg include chinese charset. after use renderPM.drawToFile(drawing, "/home/xxx.png"),
the messy code appears like:
image
How can I solve the messy code problem? Thanks for your apply.

my svg is:

Created with Highcharts 5.0.3ๆ—ถ้—ดbpsๆฏ”็‰น็Ž‡ - ๆ—ถ้—ดๅˆ†ๅธƒๆ€ป้‡14:4014:5015:0014:4514:5515:050200k400k

IndexError: list index out of range

  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 1029, in svg2rlg
    drawing = svgRenderer.render(svg)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 362, in render
    main_group = self.renderNode(svg_node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 383, in renderNode
    item = self.renderSvg(n)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 473, in renderSvg
    self.renderNode(child, group)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 386, in renderNode
    item = self.renderG(n)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 483, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 392, in renderNode
    item = self.renderG(n, clipping=clipping)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 483, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 396, in renderNode
    item = self.renderSymbol(n)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 493, in renderSymbol
    return self.renderG(node, display=0)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 483, in renderG
    item = self.renderNode(child, parent=gr)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 405, in renderNode
    item = self.shape_converter.convertShape(name, n, clipping)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 560, in convertShape
    shape = getattr(self, method_name)(node)
  File "/home/mygod/Programs/anaconda3/lib/python3.5/site-packages/svglib/svglib.py", line 870, in convertPath
    if path.operators[-1] != _CLOSEPATH:
IndexError: list index out of range

Generated PDF is all black

Hi,

I am using pygal to generate a SVG file which displays just fine in my browser. But when I convert it to any other format (PDF, jpg, png) using svglib, all I am getting is a picture completely black.

I am on OSX, do I need any additional package/library installed?

Thanks

SvgImage(Flowable) or SvgReader class that provides convenience functions to scale or wrap the image to a specified space using reportlab.platypus?

Something like this would be nice for a future release:

SvgImage(Flowable):
    def __init__(self,fname)
        pass
    def drawOn(self, canv, x, y, _sW=0):
        pass

Maybe it is sufficient to just provide a SvgReader() class, that gives the freedom to implement this in a flexible way...

The wrap() can be overloaded, whereas the wrapOn() method should not be touched.

I found an example somewhere that explains what it could look like, only that this shows how to embed a PDF file:

from reportlab.platypus import Flowable
from pdfrw import PdfReader,PdfDict
from pdfrw.buildxobj import pagexobj
from pdfrw.toreportlab import makerl

class PdfAsset(Flowable):
    def __init__(self,fname,width=None,height=None,kind='direct'):

        self.page = PdfReader(fname=fname, decompress=False).pages[0]
        self.xobj = pagexobj(self.page)

        self.imageWidth = width
        self.imageHeight = height
        x1, y1, x2, y2 = self.xobj.BBox

        self._w, self._h = x2 - x1, y2 - y1
        if not self.imageWidth:
            self.imageWidth = self._w
        if not self.imageHeight:
            self.imageHeight = self._h
        self.__ratio = float(self.imageWidth)/self.imageHeight
        if kind in ['direct','absolute'] or width==None or height==None:
            self.drawWidth = width or self.imageWidth
            self.drawHeight = height or self.imageHeight
        elif kind in ['bound','proportional']:
            factor = min(float(width)/self._w,float(height)/self._h)
            self.drawWidth = self._w*factor
            self.drawHeight = self._h*factor

    def wrap(self, width, height):
        return self.imageWidth, self.imageHeight

    def drawOn(self, canv, x, y, _sW=0):
        if _sW > 0 and hasattr(self, 'hAlign'):
            a = self.hAlign
            if a in ('CENTER', 'CENTRE', TA_CENTER):
                x += 0.5*_sW
            elif a in ('RIGHT', TA_RIGHT):
                x += _sW
            elif a not in ('LEFT', TA_LEFT):
                raise ValueError("Bad hAlign value " + str(a))
        canv.saveState()
        img = self.xobj
        if isinstance(img, PdfDict):
            xscale = self.imageWidth / img.BBox[2]
            yscale = self.imageHeight / img.BBox[3]
            canv.translate(x, y)
            canv.scale(xscale, yscale)
            canv.doForm(makerl(canv, img))
        else:
            #canv.drawInlineImage(img, x, y-self.imageHeight, self.imageWidth, self.imageHeight)
            canv.drawImage(img, x, y, self.imageWidth, self.imageHeight)
        canv.restoreState()

Running svg2rlg second time returns None.

I have to draw an image on every page of a PDF file. For that I have a function that does something like this:

def draw_logo(file_path):
      rlg = svg2rlg(file_path)
      # Draw on PDF. This part doesn't matter...

And for every page I call the function draw_logo. It draws the image on the first page, but when the function is called second time(for second page) svg2rlg returns None. Yet I have found a way to bypass this case, I still think things shouldn't work so.

Windows support

I noted the "pure python" and "no windows support" and wondered why.

On Windows, I did pip install svglib and it wasn't blocked, and also installed lxml.

Didn't find any tests after the install, which the readme had sort of hinted might be installed that way, but wouldn't be the second way...

Downloaded the whole shebang as a ZIP from github, which doesn't include the wikipedia samples, I guess, but there were some in "misc". Firefox complained about some of them having syntax errors, and some not having style, so just displayed the XML tree. GNU Emacs on Windows actually showed the graphic form of the .svg which surprised me, I hadn't discovered that feature of Emacs before, but it worked well enough, except didn't scale the images to fit the window, so had to maximize the window to see some of them in full.

Didn't find pyTest, so did a loop over *.svg to run svg2pdf.py (copy of svg2pdf so Windows Python launcher would be happy with it) and while there were some messages on the screen, it seems that .pdf files were generated, and they displayed fine (within the limits of my understanding of what "fine" should look like, based on what I could see in emacs, and cursory visual inspection) except for the airbus.pdf showed up with the fuselage all filled with black. The log of messages appears at the end.

It seems Firefox might not like the ones that don't start with <svg> with full DTD specified, which might be reasonable, but there were a couple, one of which was airbus, that gave a syntax error (pasted below). Not sure if the error is for the or the prior , or the combination.

So I never heard of svglib until the recent "revival" messages on reportlab-users mailing list, so I clearly don't know what I am doing, or how to interpret the errors, and I'm pretty much a novice with SVG, but trying to learn for a project, so I can't presently say much more about all this. But svg2pdf looks like it could be useful for my Windows-based project, if it goes in certain directions... and it seems that a fair bit of the code works fairly well on Windows...

So why isn't there Windows support? :)

==== syntax error from Firefox for airbus.svg ====
XML Parsing Error: undefined entity
Location: file:///D:/downloads/svglib/tests/samples/misc/airbus.svg
Line Number 889, Column 3: <g id="0" name="0" style="&st0;" onclick="displayAttributes(evt)">

==== messages from conversion loop ====
`
D:\downloads\svglib\tests\samples\misc>for %v in (*.svg) do py "C:\program files\Python36\Scripts\svg2pdf.py" %v

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" airbus.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" arcs01.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" arcs02.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" car.svg
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px
Ignoring unit: px

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" logo_a3.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" newlion.svg
Ignoring unit: px
Ignoring unit: px

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" python221imap.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" Python_logo_and_wordmark.svg
Can't handle color: url(#linearGradient1478)
Can't handle color: url(#linearGradient1475)
Ignoring unit: px
Can't handle color: url(#radialGradient1480)

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" rllogo.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" tiger.svg

D:\downloads\svglib\tests\samples\misc>py "C:\program files\Python36\Scripts\svg2pdf.py" timezones.svg

D:\downloads\svglib\tests\samples\misc>`

Embedded PNG images don't show up?

I get a "Adding box instead of image." warning for each embedded PNG image. The output PDF has no images. Any suggestions?

Here's the stanza for the embedded PNG images:

<image xlink:href="data:image/png;base64,iVBORw0KGgoAA.../>

And the code:

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF, renderPM

drawing = svg2rlg("input.svg")
renderPDF.drawToFile(drawing, "output.pdf")

Different PDF output between runs with hash randomization enabled

Hi!

We have regression tests that use svglib to embed SVG files into PDF reports. Those tests work by generating a PDF file and saving it as the "expected" output in a designated directory the first time they execute. The generated PDF files are manually examined and if they are correct, they are committed to Git so future runs now generate a new PDF file and compare it with the "expected" output: if they differ then the test fails.

Those tests fail in Python 3.5, because every execution of the test suite produces a different PDF file. The cause seems to be hash randomization which is enabled by default in Python 3: the same tests also fail on Python 2.7 if we set the PYTHONHASHSEED environment variable to random. Also, the same tests produce the same PDF file on Python 3.5 if PYTHONHASHSEED is set to the same value (1 for example).

It seems the conversion process is dependent on order of iterations over dicts/sets somehow.

I was wondering if this is a known issue (I couldn't find anything on the tracker) and if there might be a workaround.

Any advice would be greatly appreciated!


Reproducible example:

import os
from reportlab.graphics import renderPDF
from svglib import svglib

def test_svg_to_pdf():
    pdf_image = svglib.svg2rlg('image.svg')
    i = 1
    while True:
        filename = 'file{0}.pdf'.format(i)
        if not os.path.isfile(filename):
            break
        i += 1
    renderPDF.drawToFile(pdf_image, filename)

Running this test twice will generate file1.pdf and file2.pdf. Here's the diff with hash randomization turned on and off:

Hash optimization OFF

*** file1.pdf   Tue Dec  5 16:46:49 2017
--- file2.pdf   Tue Dec  5 16:46:51 2017
***************
*** 54,60 ****
  % 'R6': class PDFInfo
  6 0 obj
  << /Author (anonymous)
!  /CreationDate (D:20171205164649+03'00')
   /Creator (ReportLab PDF Library - www.reportlab.com)
   /Keywords ()
   /Producer (ReportLab PDF Library - www.reportlab.com)
--- 54,60 ----
  % 'R6': class PDFInfo
  6 0 obj
  << /Author (anonymous)
!  /CreationDate (D:20171205164651+03'00')
   /Creator (ReportLab PDF Library - www.reportlab.com)
   /Keywords ()
   /Producer (ReportLab PDF Library - www.reportlab.com)
***************
*** 97,103 ****
  trailer
  << /ID
   % ReportLab generated PDF document -- digest (http://www.reportlab.com)
!  [(\236!\035*7\326\241\244\317\031\313\250\215\241\375\324) (\236!\035*7\326\241\244\317\031\313\250\215\241\375\324)]

   /Info 6 0 R
   /Root 5 0 R
--- 97,103 ----
  trailer
  << /ID
   % ReportLab generated PDF document -- digest (http://www.reportlab.com)
!  [(\267{\227\035\202\242\247|9\326`\372\002\245\312\303) (\267{\227\035\202\242\247|9\326`\372\002\245\312\303)]

   /Info 6 0 R
   /Root 5 0 R

The files differ in those two lines every run because they are the time-stamp and the hash digest of the document. In our test suite we ignore differences in those two lines.

Hash optimization ON

*** file1.pdf   Tue Dec  5 16:49:18 2017
--- file2.pdf   Tue Dec  5 16:49:19 2017
***************
*** 54,60 ****
  % 'R6': class PDFInfo
  6 0 obj
  << /Author (anonymous)
!  /CreationDate (D:20171205164918+03'00')
   /Creator (ReportLab PDF Library - www.reportlab.com)
   /Keywords ()
   /Producer (ReportLab PDF Library - www.reportlab.com)
--- 54,60 ----
  % 'R6': class PDFInfo
  6 0 obj
  << /Author (anonymous)
!  /CreationDate (D:20171205164919+03'00')
   /Creator (ReportLab PDF Library - www.reportlab.com)
   /Keywords ()
   /Producer (ReportLab PDF Library - www.reportlab.com)
***************
*** 73,81 ****
  % page stream
  << /Filter [ /ASCII85Decode
   /FlateDecode ]
!  /Length 2420 >>
  stream
! Gb!#_95iTD&AB+QJ)IR`&=7<,f+r4SU6i7$"Z[9sP9>[@-:lP!hg&([?*76IDN0>lqgk43oSnSFP*4B6$U9[NO,q<YE,WJjfbrttrB''!>r;;jR@incDa*(83:lV+%2jEN//e5'fU@lrmoTFB5JR4rd$OL92fIOSp^7t*B0/]Yq:K_&HA*HG5A6Ss?U+".BLmf:%]$p(IpfCpa3o5'R[lPp?PtOH_F!J-o[/'Xl/Cn*f+7#gj4eLsrC:r/*I5=N^X)0$G!4EY_4&mN8rTs$QOfiRaOQ.0C4rcOTFF&<BMV&t&[a?J#T']\KCtRk_)dGsD2=mAg(K#K``N$U>W$lM(c)"9$Gi:X_a;km(gP:m(fGkB&H'<eS5$mfe&Dr67E8\U-tL6U^i)f[p7_CX_(-8UA!QaiY=i#I1(cRIlcl2UhMU6Tq-]e+mc$+Up9XaJ<$L"o,Rg*/&1Eb_ppV[9OtZp`-s?GV-qQ^l!,.UurEGN=6'qXcPcXg&Pk_t&-3OZ%#Q?;IZLg*Z)C92!(*t[B'*+#T[==)ICP<(F7`jB!6&Fp'1*KIB3UgraP,-,AcmW&o[jVP\R1O%rXSj*&^tOBri)?=ZjkZRR92Wj3R^Vd):_CkbWgeR+hG)P%'I-m8>BmV^Mb)km'$smC[=?AY(E>4Sd*-`Ms-ClRcV+U$\QSg=e.3@_$%\t&XSlB"M.Bc>7qUXM_8Y!S^b+A=WGM,hUMWY>asIS*h=T^Be11@Xj#q&8*=a0!fB+(A4MO'Brr)?Jc`d@rGqa/c4F*^^C]HQ#6FQQV"T:c5V_6t9gifT*Tk[43%T]V`'1M9M./^V(QEmrP&_p$5d1(.6na%hH[kE[GZgA.n.57.KaQMPblIn'Oi$uFifLU''rRo#ld'Y0[cG%pJn+%I=q>4hu@9Wft_b5t"D\iMoSK6oe@=(W:c7--<5)a8K!rJ>Ga8Xd]L@\HE)"#pQ@o04W9nmU!;Q-QKB[q@Z$Q#T:C2+/l27Y5BKG8/N$sGO)A`7+*?VQMGXX9s_77a,L_Ot5F]-ppC'\i$_K3CtZKo;$Z9nbm6-:,I[/k5`ge/6\ME[dfC'P]*+=uFuu9$1h^RMpfZbtnTIK!bR?^p1Y#<Z"I/,G`[a@o1e9Tk'[T6;<G*?2==Ph[rbbWA1>e9j_KL64,S-#5.3J9,AkL:fClNfAW]b!gDUZf9*go4N0(f&5m2@0rW,k/G5Np6;<G*4e?,^TS+"oC(0Ak'?^06OJ^W/(t@RpPV,KtTr,i&Sh3=oK7jqRC((om<LTg!n-#O.oJ=;eDO>=$#2d:<[&#sNjUFD(a:[5ld:\D_YFA"U!5:Dim^qLu[;8X-d'ojqh-&e,m./"tWO6a;6\'5'41k>4*S+CuC9Cmn0hnDq0+%8L^/V\(Bc;*tl;1B6ot$/t)KfI7[\Y0,oWBF-7U9,[D5kd+?,nd]]!+6M;Pj&tNbM\gkiG*HhY/R;"&HNaIP@8Q&ZoBm+]#^*IScNqOf_sC+]#^*IW1e<&[#Hn+jU>g=m6qYI;H`n>"%^^r6Pn'1=>UWMR`QGQh7N'o1O,6#Nf+*_N[[JM=M$G=PW[/*8D(QRkRfCn/1Q7FS@(f6Iu0WNB+)_P&.p^Zb=78QO(17i-R7jr4mXA+n3*3?o16`b8oD]L#t@!8)Y9kL&nCRC`EZ<!&2^Jf\Fa&h8E/tr1-U,ogQ*1i1<UM^7,S&N1se:O\ci-I>.cBK]@kX^k"mmHW\o*i>DeHZCC71`5=Ke5KS2/I@b\,k3&1#\Nlm>*GPRE7l[g.JNlLo==6pF,#s8.[FFU\p0Mu5_/)'bqh`@W:#YhehI<*(T"Tuli_\>BKeMm]M5KJB4%j5Zd!b-Ec=%S\<IdQSNn%%>>M)$r)$TbF2qcs"nCX=KKV-uY_EL^W3tlb]Tj/^;0WW&!b0^g`naE1Kct>i7i&DoW2-<mFm<2oVKkD+Dj+"L5'+`h3rZpYYp0lt6S#@hIV*.\,(Xj'=A*G$iWHoY+&VR1RMh/)Ei/*WN@IBZP$%#Rh=M!C#mj9+Bc835!o8<LBB6U)Q3Ksms$5T)7roE8K%l,q]*H8^22(BS9"KHbhfA,6/p4RdQNc<$RMga1l*^Jc0O6q$qZ(L[T:Xg,7d[mDYh]e`W(t2BHQC)c;I$6_Ofas/<77pTRmG5Xn':r'?,eM_n:-=YT$@e<3MZ'>`GG;6#PRA`DG'$]%*uTCX&O>fYm6nbg*?57`P5<BA"Dl<jj3/Jf6S"Xc@VlL.,n".iI)=!M-ldU*F+"Y-V^::R9eHnY#M,:E:SZ%kDAs'5'U/YpMU\(1`ec]FL)oS2f!,mKfT?=n;es-%mL.(\Zs7#B(J"otP3824dB3oODlMn3T(1)2*6kFZkL#0(EFBa,T8jlGmGW9&MJWq)5f]9Kd$\Lh:Ajiuj(a6SnEJcporkp>q%$VX>"\~>endstream
  endobj
  % 'R9': class PDFOutlines
  9 0 obj
--- 73,81 ----
  % page stream
  << /Filter [ /ASCII85Decode
   /FlateDecode ]
!  /Length 2427 >>
  stream
! Gb!#_95iTD&AB+QJ)IR@&=7<,f+r4SU6i7$"Z[9sP9>[@2Fu61hg&([?$]QjDN0>lqgk43oSnSFP*4B6$U9[NO,q;.IrE'uaVj9drHmSa>r;;jRNM!:DuRJaH2A)1rk,pa/"bQ8CHg]Ar;#aCgDcmV``]&*Kn'WHI!F5XR=EWL(HU1,3Mr\*p_!CUf%KQ;C%jt^,'7oL%IWk>[0@^Gj0RA(f`S9j;1sYMOm/Y:k4?L>LT_fEgW+NqReonCrY9^l.DMd&Dn@(VemM5;I3lnb^<;:/*b=Z+k%]RQ4.m$GKkR*:X<MCh$kY+"/I(Mo*J8JK6eW)=&[`nh+,mDs27RDpOtgMB9b`1@Rtl]rNA7r1CGDXa_BJ]*6TCQiKr0hQe;B9ukYT?Ta+<-2JF,`"7)<)-E%&+8bI5H;qd^mm<7dU0"2,GcBCjM5(%1'=QhV$h^K2W4W$De>R1Ld2*;Hukl&m_$cmW&o[jXg6QiLfaXSl@ffKkl)BU#Us)jL-3@jV<c,mXE$9!\(K"<&S%rtZn8$53E!P-odt&o31-J4@Z7^Hm_BUbX)i-opd8;3I`q+j_W?qmRs[;OJ)0PcXg&Pec")Lu;4*A*)O>,"keUWg^BeDGUqg'WRXRQekHeX:umb/R*J/>`2/558)=JNO=8ZN#*Hi+jeGXC]B^EGgB%h1q?cd\'tp)QjJ>@I]WKPqMA`ceOO6/8\rBse%dQk:oS:%5,2sfCW[t5[GCK7^sjk2k2SU;iuJUO@+XN\ml\?K4T>$Cjc?VFI!IDaIsCZVa4UH9?A34]2[T>=mS7'+^UWZ+a$S=B+<7I`?RCZ_bu+7W;(Q9q#pZsH$DSR&0]Lbi2Juk=&SBc6l;M(E`KAKcZ.-0qBY[VoWNhTJ3;Tt6A"d[2*1_M_1#D"PNq<"mQGU'5dYF/-+5SUSLc[]FQbrH\igj"]LOC#kOp(J3bE)V0M[\dN:bg\-V8f0/".K_X,,A%6@F2%EXqr][qpj15e7s#*\-OP5<#DuWK$2$MBYTuSK3CuEKo;$Z9nbmHE-G0h(b)oL'aD(7*"!K*Kpi@$<_\0tc!65$X/RhPe`9V!)(F'7(pn%`/!Z@HIPiteXdYpl#R"lAc%0ASorKj3r^TMQV8f12_aDO*+bc@'K=^XHA\KCb:fCk#f:'Ft0SC-TC(0CTh3T`b8>2p#TWc73&HsN#/Zp=Jolu@*Fs3[.;I`OaVc`4E+bc@'K6fZ!;F(U<eC5>bI3t3O,9]dbWA(9k;^bq5O?u[$5s8G,dK^(-eC5<fI&f)"-f>;%4m6O1$f!Gl)@c](LAG#<2u!@s7s+W%T/#?=DAn?5ptkN;=,5c"fq($o580j)Zc:nU':H1)CZFA@J@4_-m&`h(FnIPZYh%N+F7lPnBc;,>8YD^HV:'K[e#4cnLQX^"f6'd9W!b,\/JYgiG9,'flGB!+95W8G3i6W@L"4kB.]q<F9[fG#0+VN5oi]r@6lts,/)pl@=WYuUPo]G&/)plB=WZ8]Po]G&/)plD=WZPePo]F#TV%M+dF-&N*3)HGcG^=M!%8Ki^TNC)Dgk7gM`ea"LO3EX2(VG#`18<kOG(T4?c0_Y+MA(KFTmiRSkO?8i[&.6&(d2dW\2Btgc*tLHuk.;]*l>36cKY<G9-h#9*@^?`4OgP>ut^"ZZQtBO^K$Ab0S(9&.S^#9T@<QCu%f*[Dh%&`*?XP)tt[,dXpq"6RSY-(j@7T`C->,5TJ`BU(M>e&_nECp-Epm_27Mjq_[iI:#SlghI<*)St5\fk"m[l-t%fK^sNaSXENOJO:p+N<0^#)i)qY>qh;^"Sl%2rc1ZVGnRPSn]puRaVho&)U96J?p-dl_]254N3l91j=ZpjK3kKH8`_dJD&[5cQeF"+G:3]7E4kWR'[P'bO-QD$Bp:.>f'@4rl?#qD18/0:J0S=CfKR*KBkW\X,&N_t4#ZM8!<D^;5fN[;P"nVM]mF0"k2MFB;H&I*<GkNKLMF2)R<8b_P7E8NALJ4`)7pH1j.f<`uC]o!WUir+e-[W_%<&'^,2qbg"#J9TOn)V,j5O$jlW+un)!f;M_-EKEl3l6NnN*HTmDfLaD`t<m&T#W^tpTm$AStdOcZ.`[EFbL(I3:gWASQG/*4o5n8`M'Xd.e:%S-p#ATe>+B;SK6Tu%sU!#,CYc<eP^b'Yj[6X'HG54[Z;(t,b)Xmjh,%el.MW+CC]G-M1Q`ge_<TK??QIuHY>JQE.8+J!J$t0o*,5"o>3ICa2lWMAtrJ__I:PQQn=qL1*-eChY^Vc"RTnpGY=6Y"2TP2VSLYoZFJYD_[-LC^lotMVM0#!Nfdbj3fA.IKHkYN_9CE_09#eFYqmt5(r6C(JretQ-:"pgKDf$>H%]hCo)V?;Wp+f9@U!)>7e3J;#'YFh?*@]V`';UgjpZ@/fs2:k^"Kn6i>6lfpLaA>DK#LV<m"T=~>endstream
  endobj
  % 'R9': class PDFOutlines
  9 0 obj
***************
*** 93,107 ****
  0000000954 00000 n
  0000001228 00000 n
  0000001333 00000 n
! 0000003896 00000 n
  trailer
  << /ID
   % ReportLab generated PDF document -- digest (http://www.reportlab.com)
!  [(u\336\3320\243n?\313\324\016\022\260D\301\351x) (u\336\3320\243n?\313\324\016\022\260D\301\351x)]

   /Info 6 0 R
   /Root 5 0 R
   /Size 10 >>
  startxref
! 3947
  %%EOF
--- 93,107 ----
  0000000954 00000 n
  0000001228 00000 n
  0000001333 00000 n
! 0000003903 00000 n
  trailer
  << /ID
   % ReportLab generated PDF document -- digest (http://www.reportlab.com)
!  [(\247\203o\037\231^\037\245 \204\322\335\227\367\007\334) (\247\203o\037\231^\037\245 \204\322\335\227\367\007\334)]

   /Info 6 0 R
   /Root 5 0 R
   /Size 10 >>
  startxref
! 3954
  %%EOF

Now the contents of the document have changed between runs, in the line that describes the contents of the SVG file. We could start to ignore those lines like with did with the time-stamp and digest lines, but that would defeat the purpose of the tests.

The diffs above were obtained in Python 2.7 with PYTHONHASHSEED=1 and PYTHONHASHSEED=random, respectively.

Support *pathlike* objects.

What am I proposing is that svglib.svglib.svg2rlg() accept a path-object created by pathlib.Path() (added to the standard library in Python 3.5) rather than just strings.

I have pathlib is a wonderful addition to my Python programming, and it would be a touch simpler if I could use it directly with svglib.

"y" in "tspan" interpreted as relative coordinate?

I tried to convert an SVG that contains the following text node, which contains a y key both in the text tag and in the tspan code:

  <text
     id="text125"
     data-bb="18"
     style="font-family: &quot;Open Sans&quot;, verdana, arial, sans-serif; font-size: 12px; fill: rgb(68, 68, 68); fill-opacity: 1; visibility: inherit; white-space: pre;"
     transform="translate(24.66,0)"
     y="234"  // y is defined here...
     x="0"
     text-anchor="middle">
    <tspan
       id="tspan121"
       y="234"  // ... and here again
       x="0"
       dy="0em"
       class="line">Oct 6</tspan>
    <tspan
       id="tspan123"
       y="234"
       x="0"
       dy="1.3em"
       class="line">2013</tspan>
  </text>

This node disappears off the page when converting it using svg2pdf, presumably because in https://github.com/deeplook/svglib/blob/master/svglib/svglib.py#L720, the y coordinates are added. If I understand correctly, the inner y keyword should be interpreted as an absolute coordinate though, so the outer y should be ignored in this case.

plot.svg.txt

When using viewBox attribute, canvas size is not scaled to width and height of svg attribute

When trying to convert the following svg to png

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF, renderPM

svgtemplate="""
<svg   width="1250" height="1250"  viewBox="-40 -40 80 80">
<rect width="30" height="30" style="fill:red" />
</svg>
"""
def png(svg,pngfilename):
    text_file = open("template.svg", "w")
    text_file.write(svg)
    text_file.close()
    drawing = svg2rlg("template.svg")
    renderPM.drawToFile(drawing, pngfilename)

png(svgtemplate,'Test_viewBox.png')

I receive a png that is only 80px x 80px.
It should be 1250 x 1250 and the rect should be scaled accordingly.

(svglib 0.8.1 python 3.6.4 Windows 7)

Investigate implicit line operators in <path>

I've stumbled over a very simply logo that svglib does partly not render (the blueish triangle is missing): https://upload.wikimedia.org/wikipedia/commons/c/c7/HERE_logo.svg. It does appear though when adding l operators to the first path, turning it into:

<path d="m 26.95,66.453001 l -11,11 l -11,-11 l 22,0 z" style="fill:#65c1c2" />

So there seems to be some convention about implicit line operators that is not followed by svglib, yet. This is simply a ticket to investigate this further.

Extend svg2pdf to generate other formats

This should be easy given that there are other ReportLab renderers, like renderPM for bitmaps and renderPS for Postscript. And with renderSVG one could also do round-trip testing. The most difficult question then might be which name to choose for this extended tool instead of svg2pdf?

Remaining little flag artefacts

Three flags in samples/wikipedia/flags show minor but clearly visible artefacts with paths and/or clipping: Kyrgyzstan.svg, Slovenia.svg and The_republic_of_china.svg.

svg would not parse

Hello,
I have an svg produced by matplotlib and I would like to read it with svg2rlg.
I'm able to read different svgs, but this one eludes me.

When reading, I end up with error:
Traceback (most recent call last):
File "/usr/local/lib/python3.4/dist-packages/IPython/core/interactiveshell.py", line 2881, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "", line 1, in
d = svg2rlg(a)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 1029, in svg2rlg
drawing = svgRenderer.render(svg)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 362, in render
main_group = self.renderNode(svg_node)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 383, in renderNode
item = self.renderSvg(n)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 473, in renderSvg
self.renderNode(child, group)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 392, in renderNode
item = self.renderG(n, clipping=clipping)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 483, in renderG
item = self.renderNode(child, parent=gr)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 392, in renderNode
item = self.renderG(n, clipping=clipping)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 483, in renderG
item = self.renderNode(child, parent=gr)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 392, in renderNode
item = self.renderG(n, clipping=clipping)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 483, in renderG
item = self.renderNode(child, parent=gr)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 386, in renderNode
item = self.renderG(n)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 483, in renderG
item = self.renderNode(child, parent=gr)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 405, in renderNode
item = self.shape_converter.convertShape(name, n, clipping)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 560, in convertShape
shape = getattr(self, method_name)(node)
File "/usr/local/lib/python3.4/dist-packages/svglib/svglib.py", line 870, in convertPath
if path.operators[-1] != _CLOSEPATH:
IndexError: list index out of range

I've traced it to the line 233 (debugger:convertPath>node>sourceline which I believe to be the line when error happen) (line: " id="BitstreamVeraSans-Roman-6e"/>)
What I do not understand is, that it appears to successfully parsed very similar path before this line.
I've tried to search for unsupported statements, but I'm not such well familiar with svg, so i was unable to determine what style-list is.

Python is 3.4, svglib is 0.80 and reportlab is 3.3.0

Please ignore my issue, if the svg is not supported. Or if some preprocessing can be done, point me please to violating attribute.

Thanks
Best regards
Marek

I'm including the svg file as a text below:

<style type="text/css"> *{stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:100000;} </style>

PDF Export with Embedded SVG

I've created the following test SVG (I've simplified this ugly example immensely after discovering this issue):

SVG Preview Screenshot:
screenshot from 2018-04-03 10-09-15

PDF Render:
screenshot from 2018-04-03 10-09-37

Will paste my (again, ugly) test SVG code below.

What appears to be happening:
svglib is trying to use one of the embedded SVG dimensions as the parent document dimension.

Think about using this package to render GeoJSON files

Converting GeoJSON into something visual is still kind of an unnecessarily complicated issue. Using sites like geojson.io or GitHub gists makes this easier, but creating something quickly local seems to be overly complex, often involving some node.js tools. It might be interesting to come up with a simple solution using svglib to convert them into SVG and from there to PDF. Any practical help would be highly welcome.

Explore ShadedRect/ShadedPoly for color gradients

After looking at reportlab.graphics.widgets.grids it seems that ReportLab started at some point to provide ShadedRect and ShadedPoly classes to support color gradients. While these do not seem to render in PDF using its higher level abstractions it does certainly help to render them also in bitmaps, say. It would be very useful to evaluate their potential for filling one import missing functionality in svglib. And although the shading appears to be linear only, even that already would be very useful to have. Thoughts?

Test failures on Python 3.6+

Running the tests, I see following failures on OSX, Python 3.6, on current svglib master:

tests/test_samples.py::TestWikipediaFlags::test_convert_pdf ERROR
(while processing tests/test_samples.py::TestWikipediaFlags::test_convert_pdf)

Later the following simply hangs forever:

tests/test_samples.py::TestW3CSVG::test_convert_pdf_png
(while processing tests/samples/W3C_SVG_12_TinyTestSuite/svg/paint-stroke-207-t.svg)

Update README

  • deprecate easy_install in favour of pip
  • mention Python versions 2 and 3
  • add links to Wikipedia samples used
  • update testing section to py.test

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.