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 support for SVG #3509

Open
rominf opened this issue Dec 27, 2018 · 44 comments
Open

Add support for SVG #3509

rominf opened this issue Dec 27, 2018 · 44 comments

Comments

@rominf
Copy link
Contributor

rominf commented Dec 27, 2018

No description provided.

@radarhere
Copy link
Member

Hi. This looks like a duplicate of #1146

@rominf
Copy link
Contributor Author

rominf commented Dec 27, 2018

That issue was a question, my is a feature request.

@surgan12
Copy link

is this getting worked upon ?

@aclark4life
Copy link
Member

@surgan12 Maybe … are you working on it? 😄

@TheSandDoctor
Copy link

Hoping that it gets added. :)

@MbBrainz
Copy link

MbBrainz commented Dec 6, 2020

Maybe merge or use this library https://github.com/btel/svg_utils/

@aclark4life
Copy link
Member

@rominf @surgan12 @TheSandDoctor @MdBrainz Why do you want this? Just curious …

@rominf
Copy link
Contributor Author

rominf commented Dec 6, 2020

@aclark4life I made a feature request almost two years ago; I don't remember what the reason was already. :-)
But, since currently, we have 13 upvotes, I guess it's quite a supported feature request.

@MbBrainz
Copy link

MbBrainz commented Dec 7, 2020

ohh i dont want it haha, just saw a Stack overflow post of someone who needed a svg image editor in python and saw that this pillow library had lots of supported formats but not SVG and then i ran upon this svg_utils library, so I thought maybe its easy to add functionality to the pillow library by combining the work. thats all

@loune
Copy link

loune commented Jan 10, 2021

I've implemented some basic SVG read support here: https://github.com/loune/Pillow/blob/svg/src/PIL/SvgImagePlugin.py

Currently supports basic paths shapes and text

Might submit a PR once I clean it up a bit

@kdumontnu
Copy link

I've implemented some basic SVG read support here: https://github.com/loune/Pillow/blob/svg/src/PIL/SvgImagePlugin.py

Currently supports basic paths shapes and text

Might submit a PR once I clean it up a bit

Just want to bump this.

This looks great! I really hope you get around to submitting a PR 😀

Happy to help with it.

@nulano
Copy link
Contributor

nulano commented Apr 1, 2022

Adding support for SVG images may be related to supporting color fonts in SVG format: #6170

@dopry
Copy link

dopry commented Aug 7, 2022

@loune did you ever get a chance to submit a PR?

@wolfspyre
Copy link

@loune is it still your intention to submit this as a PR? :)

@loune
Copy link

loune commented Oct 26, 2022

@dopry @wolfspyre It's still on my TODO list. Hoping to pick it up in a few months when I have more spare time.

@masatake
Copy link

@loune, will you accept sponsors?
I guess many people want to be your sponsor to boost your development.
I'm one such person.

@Popolon
Copy link

Popolon commented Dec 7, 2022

There is a plugin that already support basic svg, if it can help:
https://github.com/gribbg/pillow_svg

@2bndy5
Copy link

2bndy5 commented May 10, 2023

Just to bump this thread (& keep from going too stale). I have a use case in which I'm generating social media cards from a Sphinx theme, and I want to use pillow without the platform-specific dependencies of cairosvg to handle SVG images. I don't need write support, rather only a way to read SVG and paste into a RGBA image.

@TheTripleV
Copy link

TheTripleV commented Jun 28, 2023

a way to read SVG and paste into a RGBA image.

For a different sphinx extension, I did write-up a svg -> png script that tries 8 different converters. It usually finds one that works: https://github.com/wpilibsuite/sphinxext-photofinish/blob/main/sphinxext/photofinish/svgtopng.py

The biggest issue I've found for dealing with svgs is that svgs can embed html and css. So the render behavior of an svg can be dependent on the behavior of your web browser. And loading up an automated browser just to convert an image is a bit much is lot of cases.

@2bndy5

This comment was marked as off-topic.

@sarnold
Copy link

sarnold commented Aug 23, 2023

Hmm, seems like rst2pdf thinks they have SVG support using svglib, but then it actually falls back to pillow to open the svg file, and then... boom

I would really like SVG support in my PDFs - is there any chance this might work someday ?

@aclark4life
Copy link
Member

@sarnold There's always a chance … but this issue is currently in the icebox so I would say no immediate chance. Any idea what's involved in adding SVG support to Pillow? That seems a round-a-bout way to fix the issue you describe above, which sounds like an issue with docutils or whatever package includes rst2pdf. But, I'll play along with the SVG support in Pillow part …

@sarnold
Copy link

sarnold commented Aug 23, 2023

After some serious poking at the image stuff, turns out the fallback to pillow occurs only with SVG image inside a table. I didn't even know that was a thing, but there ya go...

@homm
Copy link
Member

homm commented Nov 2, 2023

@rominf Could you clarify your request, do you mean reading?

@benyissa as I know, none, so you can start just right now.

@rominf
Copy link
Contributor Author

rominf commented Nov 2, 2023

@homm I've filled this issue about 5 years ago. I was wrong about not being explicit for sure — now I don't know whether it was just about reading or something else either (it's not relevant for me anymore)... If you have the ability to edit the description of the issue — please go ahead, edit it as you wish. 😃

@kevinhendricks
Copy link

This is a true hole in image support. Svg is being used more and more for icons, images, and artwork but no support to open an svg and rasterize it seems to be available or coming to pillow. Attempts to use the talked about pilow_svg image plugin (after fixing its missing and misplaced registration calls) results in infinite recursion since PIL ImageDraw class invokes Draw() in its own polygon routine which when the getdraw attribute fails on an image object invokes ImageDraw which creates an infinite recursion.

Why on earth does ImageDraw ever invoke Draw() that can cause a caught attribute error to invoke ImageDraw creating an infinite recursion?

Without svg support, pillow is imho not a full image library.

Please consider fixing the supplied pillow_svg plugin code and get it into pillow as soon as possible so that others can work on filling missing pieces.

@aclark4life
Copy link
Member

I think we'd consider contributions if that's what you mean? 🤷‍♂️

@masatake
Copy link

@aclark4life

Can we use "GitHub Sponsors" for solving this issue? I don't want to use one at "external link".

What do you think about the work #3509 (comment) ?

@hugovk
Copy link
Member

hugovk commented Nov 30, 2023

There are 75 👍 on this issue.

I suggest interested parties get involved in @loune and @gribbg's third-party plugin at #3509 (comment) and get it into shape, and consider contributing it.


Installing plugins is a valid option. Look at pytest and Flake8, and there also exists Pillow plugins, such as:

And there's a PR to make pillow_svg installable at gribbg/pillow_svg#3.

We could ask for a Trove classifier, like Flake8 and pytest have.

@kevinhendricks
Copy link

kevinhendricks commented Nov 30, 2023

The pillow_svg repo listed in #3509 is dead as no one responds to any PRs or bugs, no one has committed anything to it in two years.

It does not work as is. It is missing calls to register the plugin properly, the calls that exist are not at the end of the code and so you get undefined and missing errors. And the draw implementation uses your ImageDraw which as far as I can tell is broken (see comment about your own ImageDraw calling Draw and if image does not support attribute getdraw it causes an infinite recursion). That infinite recursion should simply not be possible and should be prevented.

Worse yet, there is no clear license provided in that repo. Without a clear open source license no one can use the code nor contribute to it.

@aclark4life
Copy link
Member

May have just messaged Glenn Gribble on LinkedIn 🤷

Screenshot 2023-11-30 at 12 27 07 PM

@masatake
Copy link

I opened an issue: gribbg/pillow_svg#6 .

@aclark4life
Copy link
Member

@masatake I don't know if GitHub Sponsors is a good fit for us, but I'm starting to consider:

  • Additional funding outside of Tidelift
  • Additional funding for this feature

Similar to back in the day I may be interested in doing some paid work to move things forward. But I'll definitely need folks to help, either the core team, additional paid developers (which could include core developers and payments on top of Tidelift) or additional volunteers.

@hugovk How big of a need is there right for us to formalize a framework to support plugins? If the need for an SVG plugin is "high" how would you rate "Pillow framework" ?

@loune
Copy link

loune commented Dec 6, 2023

Just adding my thoughts since I saw there are some recent discussions. I don't have any involvement with gribbg/pillow_svg. It looks like a repackaging of my original SVG code with some experimental enhancements using aggdraw. At least for my code, feel free to take it and enhance it further.

I'm still open to submitting a PR on this, but I don't feel that the SVG support will be anywhere close to standards-compliant. This means that your mileage may vary depending on the complexity of the SVG you want to render. If partial support is acceptable then I can work on the PR with the functionality as is. However, I can't guarantee any ongoing support.

The difficulty with implementing the full standard is limitations of the Pillow ImageDraw API. Some key functionality that are missing include:

  • Transform matrix - This is required to scale, translate, rotate, skew elements. My code gets around it for paths and shapes by reimplementing them using polygon with transformed points. However, this work around is not possible for other elements like text.
  • Line caps
  • Line styles (dotted dashed etc)
  • Clipping and masking
  • Gradients

Nice to haves:

  • Anti-aliasing
  • Bezier curves
  • Saving / loading state or a stack

@Yay295
Copy link
Contributor

Yay295 commented Dec 6, 2023

These sound like things that should probably be implemented in C to be performant.

@aclark4life
Copy link
Member

aclark4life commented Dec 6, 2023

Ah! Thanks @loune . So we have this small amount of code we don't own:

diff loune-pillow/src/PIL/SvgImagePlugin.py pillow_svg/pillow_svg/SvgImagePlugin.py 
2c2
< from typing import Type, Tuple, Dict, List, Union
---
> from typing import Type, Tuple, Dict, List, Union, cast
12a13
> 
16a18
> 
20a23
> 
45c48
<             
---
> 
64c67
<     
---
> 
125d127
<         
257c259
<         
---
> 
403c405
<         
---
> 
417c419
<         
---
> 
425,427c427,442
<             self.draw.polygon([x1, y1, x2, y2, x3, y3, x4, y4],
<                 outline = self.parse_color(self.get_attribute("stroke", "none", False), float(self.get_attribute("stroke-opacity", "1", False))),
<                 fill = self.parse_color(self.get_attribute("fill", "none", False), float(self.get_attribute("fill-opacity", "1", False))))
---
>             if not isinstance(self.draw, ImageDraw.ImageDraw):
>                 from aggdraw import Brush, Pen, Draw
>                 draw = cast(Draw, self.draw)
>                 draw.setantialias(False)
>                 self.draw.polygon([x1, y1, x2, y2, x3, y3, x4, y4], Brush('black'))
>                 # self.draw.polygon([20, 20, 21, 20, 21, 21, 20, 21], Brush('green'))
>                 # self.draw.polygon([20, 0, 21, 0, 21, 1, 20, 1], Brush('blue'))
>                 # self.draw.polygon([22, 0, 22, 1, 23, 1, 23, 0], Brush('red'))
>                 draw.flush()
>             else:
>                 self.draw.polygon([x1, y1, x2, y2, x3, y3, x4, y4],
>                     outline = self.parse_color(self.get_attribute("stroke", "none", True), float(self.get_attribute("stroke-opacity", "1", False))),
>                     fill = self.parse_color(self.get_attribute("fill", "none", True), float(self.get_attribute("fill-opacity", "1", False))))
>                 # self.draw.polygon([20, 20, 21, 20, 21, 21, 20, 21], fill='green')
>                 # self.draw.polygon([20, 0, 21, 0, 21, 1, 20, 1], fill='blue')
>                 # self.draw.polygon([22, 0, 22, 0, 22, 1, 22, 1], fill='red')
510a526
> 
533a550
> 
535a553
> 
542a561
> 
578d596
< Image.register_open(SvgImageFile.format, SvgImageFile, _accept)
580,584d597
< Image.register_extensions(SvgImageFile.format, [
<     ".svg"
< ])
< 
< Image.register_mime(SvgImageFile.format, "image/svg+xml")

And you are willing to submit a PR to add your code which would be great, thank you! We can then figure out what to do from there and yes, whatever additional code you are willing to add to that PR please do.

As for "do we want partial support", probably. At least it would be a start, and possible incentive to improve the ImageDraw API as you describe. Thanks again.

@hugovk
Copy link
Member

hugovk commented Dec 7, 2023

@hugovk How big of a need is there right for us to formalize a framework to support plugins?

I don't know, is there anything we need beyond this?

We can ask for a Trove classifier. It's more of a nice-to-have, there are already plugins without it, e.g. #3509 (comment).

If the need for an SVG plugin is "high" how would you rate "Pillow framework" ?

Do you mean asking for the classifier or something else?

@aclark4life
Copy link
Member

Do you mean asking for the classifier or something else?

Asking for the classifier would formalize the process of publishing and sharing a plugin. The question is more like "does anyone care" or "would a formal plugin framework be an improvement to the ecosystem".

As you say, folks upvoted SVG support here, but I'm not sure anyone cares about Pillow plugins or a PyPI full of them and if that's the case, we may not need to formalize the process, but rather just consider it a "nice to have".

@wiredfool
Copy link
Member

wiredfool commented Dec 8, 2023

My feelings on this are:

  1. SVG is a big spec. I'd say it's as big as anything else we're doing, and there are definitely parsing issues or places where we'd have to be rather careful to not introduce new classes of exploits to Pillow. It's not on par with PDF (partially because PDF can include SVG, TIFFs and just about anything else) or potentially TIFF, but we're doing not the parsing for either of those cases.

  2. I don't think it's worth half assed support of SVG. There are also a reasonable number of primitives that we don't support out of the box with ImageDraw, as noted above. If we have something that only supports 'basic' svg, everyone is going to find something where it doesn't work, and it's going to be a support/maintenance issue.

  3. I think the best way forward would be to integrate similarly to how we have ghostscript -- find an existing SVG rendering engine (mozilla and inkscape both have them, somewhere at least, looks like gnome uses librsvg (lgpl, so notpotentially compatible license)) and run it in a separate process/sandbox. Extra bonuses if it's in a memory safe language (but it looks like rust just packages librsvg). The drawback here is going to be in packaging, there may be enough other library dependencies that we can't package it in Pillow.

@aclark4life
Copy link
Member

@wiredfool Got it, thanks. So at this point in our @python-pillow/pillow-team careers, this is not something that really needs to happen and historically only things that need to happen actually happen.

Still wouldn't mind a PR from @loune for reference. Thanks all

@wiredfool
Copy link
Member

From my quick look at librsvg, I think basic read support would not be hard (on linux at least), but packaging... I'm not sure how many of these are runtime dependencies: https://gnome.pages.gitlab.gnome.org/librsvg/devel-docs/devel_environment.html#setting-up-dependencies-manually, but there's at least cairo and lxml, at the runtime. Freetype would need to be in sync with what we're using.

@kevinhendricks
Copy link

Using a full library like rsvg is for the birds. The Svg spec is a moving target with various ever changing implementations such as tiny svg 1.2, svg 1.1, svg 2.x. Nothing out there short of full browser implementations are even close to being complete. Even those do not support many of the newer dynamic svg crap. Even QtSvg supports only a subset of Svg on top of Tiny SVG.

That said, Pareto's rule applies and a lot can be done with just a little effort that will support static svg as used in most icons and artwork. There are smaller self-contained libraries to convert more advanced svg drawing features into things that can actually be drawn by most existing drawing libraries.

Pulling in the pillow_svg support, would be a good start for others to tackle some of the more important missing features while providing some rendering capability to the more common static svg cases. Mark it experimental in some way if needed.

My 2 cents.

@aclark4life
Copy link
Member

Can we use "GitHub Sponsors" for solving this issue? I don't want to use one at "external link".

@masatake A bit more on using GitHub Sponsors here: #7610.

@akx
Copy link
Contributor

akx commented Dec 31, 2023

For the record, the easy-thumbnails package for Django implements SVG support by way of their own "VIL" package, which uses ReportLab and svglib under the hood.

I also kind of think SVG support shouldn't necessarily be in core Pillow; if anything, an easily installable and pluggable secondary package that adds support (pillow-svg?)

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

No branches or pull requests