deeplook / svglib Goto Github PK
View Code? Open in Web Editor NEWRead SVG files and convert them to other formats.
License: GNU Lesser General Public License v3.0
Read SVG files and convert them to other formats.
License: GNU Lesser General Public License v3.0
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>
There seem to be some stale forks of svglib
on GitHub which were made a long time ago and which don't reflect the many changes that were added with version 0.8.1. I'm getting some requests from people confused by those, and maybe this can be changed by contacting those who have made the forks...
Here's a very preliminary list:
To be continued...
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.
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
.
Need to explore SVG 2 which is pretty new and the potential impacts on svglib
.
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 ==========================================
I've created the following test SVG (I've simplified this ugly example immensely after discovering this issue):
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.
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?
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.
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".
<?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>
Is there any way to choose the dimensions of the image that is saved by calling renderPM.drawToFile
or by any other method?
Only rgb(...) colors are supported for now. Opacity should be set by the a value.
Here is the example svg input and pdf output (created with svglib):
silicon2018.zip
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
I think it would be nice to make a release on PyPI with the recent improvements of svglib. Is that in your plans?
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
?
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.
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()
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).
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)
And make https://pypi.python.org/pypi/argparse a dependancy for older Python versions of, both, 2 and 3.
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.
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)
easy_install
in favour of pip
On Python 2, io.StringIO needs a unicode string. @deeplook, do you want to support Python 3.2? We could add the u""
prefix before the string, but Python 3.2 doesn't support it (it was readded in 3.3).
i tried to convert this svg:
https://github.com/eyaler/blob2svg/blob/master/test.svg
to png, and got this:
https://ibb.co/k2ksbm
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.
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: "Open Sans", 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.
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.
src/test
directory one level up and rename to tests
unittest
to pytest
(done)tox.ini
and/or pytest.ini
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.
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>`
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>See https://www.quantifiedcode.com/app/project/gh:deeplook:svglib
It's not sure, though, if this service will continue to exist after 2016, see https://www.quantifiedcode.com/blog/quantifiedcode-future...
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")
There are some threads about svglib
there, see http://stackoverflow.com/search?q=svglib which could benefit from a brief update about the next release (after making the release).
<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>
If we want to support CSS style sheets, it seems that using cssselect is a must.
https://pythonhosted.org/cssselect/
But to take advantage of it, we need an XML library which supports Xpath expressions. So I suggest to replace minidom usage by lxml. Is that reasonable?
@deeplook Any hint on the utility of the convertText0
method?
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
Those official ones are using one gradient for blue and yellow each which means they will currently not be rendered: https://www.python.org/community/logos/ So one without gradients would be nice.
svglib doesn't support yet stylesheet-defined styles. Only styles directly applied to elements is taken into account.
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
@deeplook , my svg include chinese charset. after use renderPM.drawToFile(drawing, "/home/xxx.png"),
the messy code appears like:
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
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?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.