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

Low resolution PNG output #207

Open
fourjr opened this issue Jul 13, 2019 · 19 comments
Open

Low resolution PNG output #207

fourjr opened this issue Jul 13, 2019 · 19 comments

Comments

@fourjr
Copy link

fourjr commented Jul 13, 2019

This is the SVG file that I am trying to convert.

Is there a way to make the output png a higher resolution? The rendered SVG on Github has a way higher resolution than the one outputted by the lib.

72 DPI (default)
image

1024 DPI
image

Python code:

drawing = svg2rlg('dump/emoji.svg')
with open('dump/emoji.png', 'wb') as f:
    renderPM.drawToFile(drawing, f, fmt="PNG", dpi=1024)
@claudep
Copy link
Collaborator

claudep commented Jul 13, 2019

Good question. This is more a ReportLab question than a svglib one, but by reading RL code, looks like you should be able to play with the drawing.renderScale attribute which looks like a scale factor. Would be nice if you can report your experiment results, maybe we can add a line or two in our README.

@fourjr
Copy link
Author

fourjr commented Jul 14, 2019

I managed to successfully resize properly with this answer. However, upon resizing, I realised that the edges were extremely jagged.
emoji

@tonioluna
Copy link

This is the SVG file that I am trying to convert.

Is there a way to make the output png a higher resolution? The rendered SVG on Github has a way higher resolution than the one outputted by the lib.

72 DPI (default)
image

1024 DPI
image

Python code:

drawing = svg2rlg('dump/emoji.svg')
with open('dump/emoji.png', 'wb') as f:
    renderPM.drawToFile(drawing, f, fmt="PNG", dpi=1024)

Having the same issue with a different svg image. drawToFile's dpi argument does not work, it just modifies the size of the output file but not its resolution. Adding this comment just in case a solution or follow up is added.

@deeplook
Copy link
Owner

deeplook commented Jul 14, 2020

I would also first scale it like you did. If the result looks jagged that could be because of its path definition, but I see it does contain cubic Bézier curves like in this pretty similar example here: https://www.sitepoint.com/closer-look-svg-path-data/ Maybe you want to compare with that? The test suite perfectly runs most flags from Wikipedia and they should be full of such curves.

Else I hope @replabrobin can shere any insight about any renderPM limitations?

@replabrobin
Copy link
Contributor

without the actual svg it's hard to answer any question like this. If I squash the large image the flats disappear, so are the curves bezier? I think the assertion in renderPM is 1pixel == 1pt for PDF compatibility. The dpi value is not used internally in the drawing code, but is passed to PIL via im.save.

@fourjr
Copy link
Author

fourjr commented Jul 14, 2020

@replabrobin The SVG file I used is liked above in a gist.

@replabrobin
Copy link
Contributor

It's not working for me; I just see the loading gif for a few seconds and then "Sorry, something went wrong. Reload?"

@fourjr
Copy link
Author

fourjr commented Jul 14, 2020

@replabrobin
Copy link
Contributor

I'm afraid not, as before just the placeholder circling and then something went wrong. I am using chromium 83 on arch linux latest

@deeplook
Copy link
Owner

<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 47.5 47.5" style="enable-background:new 0 0 47.5 47.5;" xml:space="preserve" version="1.1" id="svg2"><metadata id="metadata8"><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/></cc:Work></rdf:RDF></metadata><defs id="defs6"><clipPath id="clipPath16" clipPathUnits="userSpaceOnUse"><path id="path18" d="M 0,38 38,38 38,0 0,0 0,38 Z"/></clipPath></defs><g transform="matrix(1.25,0,0,-1.25,0,47.5)" id="g10"><g id="g12"><g clip-path="url(#clipPath16)" id="g14"><g transform="translate(23.8555,36.2422)" id="g20"><path id="path22" style="fill:#5dadec;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -14.98,-6.266 12.537,-9.733 c 2.632,-2.224 6.377,-2.937 9.769,-1.518 4.826,2.018 7.096,7.577 5.072,12.413 C 10.377,-0.266 4.824,2.019 0,0"/></g><g transform="translate(13.8931,18.3184)" id="g24"><path id="path26" style="fill:#5dadec;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -10.843,8.398 -1.913,-13.246 c -0.534,-2.855 0.502,-5.902 2.958,-7.802 3.493,-2.705 8.518,-2.067 11.224,1.425 C 4.131,-7.732 3.493,-2.707 0,0"/></g><g transform="translate(29.2324,11.3027)" id="g28"><path id="path30" style="fill:#5dadec;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 0,0 -8.156,4.689 -0.033,-9.222 c -0.088,-2 0.904,-3.981 2.75,-5.041 2.63,-1.512 5.976,-0.594 7.478,2.051 C 3.539,-4.879 2.629,-1.51 0,0"/></g></g></g></g></svg>

@replabrobin
Copy link
Contributor

Thanks I'll take a look later

@replabrobin
Copy link
Contributor

Hi I had a look at this problem and it seems to me that the internal libart code is scaling after discretization instead of scaling before. I'll see if there's a better way to do curves in _renderPM.

@replabrobin
Copy link
Contributor

OK I looked in the _renderPM code and it seems that our smoothness is dictated by the parameter 0.25 passed into

vpath = art_bez_path_to_vec(self->path, 0.25)

which converts beziers into vector paths. Everywhere that is used it is followed eventually in _renderPM.c by a call to
art_vpath_affine_transform(vpath, self->ctm) to scale the vpath by the current transformation matrix.

I wonder if that is the source of the problem we are scaling after vectorizing; we should be able to scale all the control points before scaling. It seems to make sense for scales > 1, but perhaps not when scaling < 1.

@deeplook
Copy link
Owner

deeplook commented Jul 2, 2021

@replabrobin What is the state of this? I find the very same effect as shown below (recorded inside a Jupyter notebook).

import io

import requests
from ipywidgets import interact
from PIL import Image
from reportlab.graphics import renderPM, renderPDF
from svglib.svglib import svg2rlg

svg = requests.get("https://simpleicons.org/icons/apple.svg").text
svg_file = io.StringIO(svg)

@interact(scale=(1, 20, 1))
def render(scale=1):
    drawing = svg2rlg(svg_file)
    drawing.scale(scale, scale)
    drawing.width *= scale
    drawing.height *= scale

    f = io.BytesIO()
    renderPM.drawToFile(drawing, f, fmt="PNG")
    f.seek(0)
    im = Image.open(f)
    return im

im = render()

apple_renderpm

import base64
import io

import requests
from IPython.display import Markdown
from ipywidgets import interact
from reportlab.graphics import renderPDF
from svglib.svglib import svg2rlg

svg = requests.get("https://simpleicons.org/icons/apple.svg").text
svg_file = io.StringIO(svg)

@interact(scale=(1, 20, 1))
def render(scale=1):
    drawing = svg2rlg(svg_file)
    drawing.scale(scale, scale)
    drawing.width *= scale
    drawing.height *= scale
    pdf_content = renderPDF.drawToString(drawing)
    base64_pdf = base64.b64encode(pdf_content).decode("utf-8")
    pdf_display = (
        f'<embed src="data:application/pdf;base64,{base64_pdf}" '
        'width="400" height="400" type="application/pdf">'
    )
    return Markdown(pdf_display)

md = render()

apple_renderpdf

@justingolden21
Copy link

The fix above doesn't seem to apply to stroke

drawing.scale(scale, scale)

@justingolden21
Copy link

@justingolden21
Copy link

GOT IT FIGURED OUT

You can just convert from SVG to PDF then from PDF to PNG:

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
from pdf2image import convert_from_path

drawing = svg2rlg('card.svg')
renderPDF.drawToFile(drawing, 'card.pdf')

pages = convert_from_path('card.pdf', 600)
pages[0].save('card.png', 'PNG')

All other implementations online either require Pillow (which is a massive pain, struggled with that for several hours during several days a while ago) or CairoSVG (which is near impossible to get working on Windows)

@M4a1x
Copy link

M4a1x commented Oct 22, 2022

I found this issue when trying to convert SVG inputs to PNG/PIL, without relying on cairosvg, pyvips or pdf2image as those need python-external dependencies like cairo, poppler or libvips that can be a pain to install in windows. I found pymupdf that at least comes with prebuild wheels for windows/linux/mac so nothing more than

pip install pymupdf svglib

is needed to get this running

import fitz
from svglib import svglib
from reportlab.graphics import renderPDF

# Convert svg to pdf in memory with svglib+reportlab
# directly rendering to png does not support transparency nor scaling
drawing = svglib.svg2rlg(path="input.svg")
pdf = renderPDF.drawToString(drawing)

# Open pdf with fitz (pyMuPdf) to convert to PNG
doc = fitz.Document(stream=pdf)
pix = doc.load_page(0).get_pixmap(alpha=True, dpi=300)
pix.save("output.png")

This supports transparent backgrounds without corners and does not have the issue pointed out above.
I hope this helps someone who stumbles by.

Cheers!

@Nav31
Copy link

Nav31 commented Feb 23, 2023

To add a bit to the response by @M4a1x, if you don't want to save to a file, you can just do:

import fitz
from svglib import svglib
from reportlab.graphics import renderPDF

# Convert svg to pdf in memory with svglib+reportlab
# directly rendering to png does not support transparency nor scaling
drawing = svglib.svg2rlg(path="input.svg")
pdf = renderPDF.drawToString(drawing)

# Open pdf with fitz (pyMuPdf) to convert to PNG
doc = fitz.Document(stream=pdf)
pix = doc.load_page(0).get_pixmap(alpha=True, dpi=300)
png_bytes = pix.tobytes() # defaults to PNG <======= return bytes that you can do something with like upload to external object storage

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

8 participants