Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add svg support from agg-svg #49

Open
dov opened this issue Jan 21, 2019 · 4 comments
Open

Add svg support from agg-svg #49

dov opened this issue Jan 21, 2019 · 4 comments

Comments

@dov
Copy link
Contributor

dov commented Jan 21, 2019

A few years back I extended the svg support of agg to be a bit more usable, see http://github/dov/agg-svg . It should be trivial to add a wrapper to aggdraw for this. Note that this adds one more dependency, expat. The question is whether this should be included in aggdraw, or perhaps in another module.

@djhoese
Copy link
Member

djhoese commented Jan 21, 2019

How would the cpp/h files need to be compiled? The installation section says it gets dropped in to the source tree. So this links against an existing agg build and provides a new SVG interface or adds/modifies the existing SVG interface? Without fully understanding the interface I see two options:

  1. Add these to aggdraw, compile them if expat can be found.
  2. Create a separate package (that could be added to conda-forge for easier installation: https://conda-forge.org/) and compile the relevant parts of aggdraw.cxx based on a MACRO set from setup.py (if the library can be found or not).

I think I prefer number 1, but would want to do it where it was clear that these files are not part of the base AGG project. This may be easier too if we turned aggdraw in to a "full" python package where the aggdraw.cxx is just one submodule/subpackage. Would be easier to include tests in the released distribution, but would increase the size of the project too. Would make it much more flexible for future changes though.

@dov
Copy link
Contributor Author

dov commented Jan 21, 2019

The svg parser returns an agg::path_renderer object that really simply is a path container. If you wrap this object into python it really has the same semantics as the current Symbol. So draw.symbol() could be overloaded to recognize path renderer objects. This makes it possible e.g. to create an object in inkscape and then load it and copy and paste it multiple times in the "canvas". We still need to figure out how to transform it though, but perhaps draw.symbol can simply take a transformation object...

expat is public domain if I'm mistaken and quite small, so just dropping it into the sources is really not a problem. It is probably an overkill to put it in a different module.

@a-hurst
Copy link
Contributor

a-hurst commented Mar 15, 2019

This would be a great addition. I’ve been looking for a good simple SVG-to-Pillow solution for a while now (I want to be able to load vector images at a given arbitrary size and then draw them to the screen with PyOpenGL), and having the functionality rolled into aggdraw would make everything very easy. Would this be able to correctly render most SVG files, or are there any common SVG features that aren’t supported yet?

@dov
Copy link
Contributor Author

dov commented Mar 16, 2019

Please see the https://github.com/dov/aggdraw/tree/svg for a first implementation of svg support.

Regarding the coverage of the SVG support, it is indeed quite limited, as dictated by the https://github.com/dov/agg-svg project. If there is some particular file that doesn't render, feel free to open a bug report about it in agg-svg. The major feature missing though is text. There is no text support whatsoever.

Here is an example of what you can do with it. (Note that I'm also making use of https://github.com/dov/pyeuclid for matrix calculations.)

import math
import euclid
import aggdraw
from aggdraw import Draw,Brush,Svg
from PIL import Image

def euclid2agg(t):
    '''Extract the euclid affine coordinates in the proper order for agg'''
    return (t[0],t[1],t[3],t[4],t[6],t[7])

im = Image.new("RGB", (1024, 1024))
draw = Draw(im)
brush = Brush('#44c')
draw.rectangle((0, 0, im.size[0], im.size[1]), brush)

svg = Svg(open('tux.svg').read())
br = svg.bounding_rect()
center = euclid.Point2(0.5*(br[0]+br[2]),0.5*(br[1]+br[3]))
brush = Brush('red')
draw.svg((500-center[0],500-center[1]),svg)
s = 0.3
for i in range(16):
    angle = math.radians(360./16*i)
    t = (euclid.Matrix3.new_identity()
        .scale(s,s)
        .rotate_around(angle, center[0], center[1])
        .translate(0, -1300)
        .pre_translate(-center[0]*s+500, -center[1]*s+500)
        )
    draw.svg(euclid2agg(t),svg)
draw.flush()
im.save('tuxes.png')

print('ok')

And here is the result:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants