Pillow icon indicating copy to clipboard operation
Pillow copied to clipboard

Add support for SVG

Open rominf opened this issue 6 years ago β€’ 44 comments

rominf avatar Dec 27 '18 10:12 rominf

Hi. This looks like a duplicate of https://github.com/python-pillow/Pillow/issues/1146

radarhere avatar Dec 27 '18 10:12 radarhere

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

rominf avatar Dec 27 '18 10:12 rominf

is this getting worked upon ?

surgan12 avatar Apr 26 '19 07:04 surgan12

@surgan12 Maybe … are you working on it? πŸ˜„

aclark4life avatar May 11 '19 13:05 aclark4life

Hoping that it gets added. :)

TheSandDoctor avatar Nov 10 '19 08:11 TheSandDoctor

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

MbBrainz avatar Dec 06 '20 17:12 MbBrainz

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

aclark4life avatar Dec 06 '20 18:12 aclark4life

@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.

rominf avatar Dec 06 '20 19:12 rominf

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

MbBrainz avatar Dec 07 '20 10:12 MbBrainz

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

loune avatar Jan 10 '21 00:01 loune

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.

kdumontnu avatar Dec 05 '21 18:12 kdumontnu

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

nulano avatar Apr 01 '22 00:04 nulano

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

dopry avatar Aug 07 '22 19:08 dopry

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

wolfspyre avatar Sep 29 '22 19:09 wolfspyre

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

loune avatar Oct 26 '22 11:10 loune

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

masatake avatar Nov 22 '22 10:11 masatake

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

Popolon avatar Dec 07 '22 19:12 Popolon

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.

2bndy5 avatar May 10 '23 21:05 2bndy5

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.

TheTripleV avatar Jun 28 '23 00:06 TheTripleV

@TheTripleV I'm currently only supporting ImageMagick CLI since it is available in all the github-hosted action runners (and simple to install on user machines). Seems like a over-correction to use a multitude of third-party options to implement a workaround for this issue. I've also heard about performance penalties when using InkScape CLI.

loading up an automated browser just to convert an image

Agreed. This is an approach suggested (multiple times) for creating social media cards. I hope to support it in the future...

The biggest issue I've found for dealing with svgs is that svgs can embed html and css

This can be handled during the SVG loading in pillow. Web browsers' behavior need not apply to this feature request.

I found that resizing SVGs via ImageMagick must use their --density option (not explicit dimensions) with a value based the SVG's original DPI.

My current algo w/ IM
def convert_svg(img_path: Path, cache: Union[str, Path], size: Size) -> Path:
    out_name = (
        img_path.name
        + f"_{size.width}x{size.height}_"
        + hashlib.sha256(img_path.read_bytes()).hexdigest()[:16]
        + ".png"
    )
    out_path = Path(cache, out_name)
    if out_path.exists():
        return out_path

    magick_path = "magick"
    if "MAGICK_HOME" in os.environ:
        magick_home = Path(os.environ["MAGICK_HOME"], magick_path)
        if platform.system().lower() == "windows":
            magick_home = magick_home.with_suffix(".exe")
        assert magick_home.exists()
        magick_path = str(magick_home)

    # get size of svg via ImageMagick
    svg_info = subprocess.run(
        [
            magick_path,
            "identify",
            "-format",
            "DPI: %[fx:resolution.x] SIZE: %[fx:w]x%[fx:h]",
            str(img_path),
        ],
        check=True,
        capture_output=True,
    )
    m = _IDENTIFY_INFO.search(svg_info.stdout.decode(encoding="utf-8"))
    assert m is not None and isinstance(m, re.Match) and len(m.groups()) == 3
    svg_dpi, w, h = [int(x) for x in m.groups()]
    svg_size = Size(width=w, height=h)
    out_path.parent.mkdir(parents=True, exist_ok=True)
    magick_cmd = [magick_path, "-background", "none", str(img_path), str(out_path)]

    if size.width > svg_size.width or size.height > svg_size.height:
        # resize svg using density of DPI based on original size
        if size.height < size.width:
            new_dpi = int(svg_dpi * (size.height / svg_size.height))
        else:
            new_dpi = int(svg_dpi * (size.width / svg_size.width))
        # LOGGER.info("new DPI: %s", new_dpi)
        magick_cmd.insert(1, "-density")
        magick_cmd.insert(2, str(new_dpi))

    subprocess.run(magick_cmd, check=True)
    return out_path

2bndy5 avatar Jun 28 '23 01:06 2bndy5

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 ?

sarnold avatar Aug 23 '23 01:08 sarnold

@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 …

aclark4life avatar Aug 23 '23 12:08 aclark4life

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...

sarnold avatar Aug 23 '23 17:08 sarnold

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

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

homm avatar Nov 02 '23 15:11 homm

@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. πŸ˜ƒ

rominf avatar Nov 02 '23 16:11 rominf

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.

kevinhendricks avatar Nov 30 '23 14:11 kevinhendricks

I think we'd consider contributions if that's what you mean? πŸ€·β€β™‚οΈ

aclark4life avatar Nov 30 '23 16:11 aclark4life

@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 https://github.com/python-pillow/Pillow/issues/3509#issuecomment-757392479 ?

masatake avatar Nov 30 '23 16:11 masatake

There are 75 πŸ‘ on this issue.

I suggest interested parties get involved in @loune and @gribbg's third-party plugin at https://github.com/python-pillow/Pillow/issues/3509#issuecomment-1341491190 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:

  • https://pypi.org/project/pillow-jxl-plugin/
  • https://pypi.org/project/pillow-jpls/
  • https://pypi.org/project/pillow-avif-plugin/
  • https://pypi.org/search/?q=pillow+plugin

And there's a PR to make pillow_svg installable at https://github.com/gribbg/pillow_svg/pull/3.

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

hugovk avatar Nov 30 '23 16:11 hugovk

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.

kevinhendricks avatar Nov 30 '23 17:11 kevinhendricks