Skip to content

Svg rasterize resolution fix #1185

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

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2013-05-18 Added support for arbitrary rasterization resolutions to the
SVG backend. Previously the resolution was hard coded to 72
dpi. Now the backend class takes a image_dpi argument for
its constructor, adjusts the image bounding box accordingly
and forwards a magnification factor to the image renderer.
The code and results now resemble those of the PDF backend.
- MW

2012-08-11 Fix path-closing bug in patches.Polygon, so that regardless
of whether the path is the initial one or was subsequently
set by set_xy(), get_xy() will return a closed path if and
Expand Down
4 changes: 4 additions & 0 deletions doc/users/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -841,3 +841,7 @@ Here are the 0.98.4 notes from the CHANGELOG::
off automatically when infs or NaNs are present. Also masked
arrays are now converted to arrays with NaNs for consistent
handling of masks and NaNs - MGD and EF

Added support for arbitrary rasterization resolutions to the SVG
backend. - MW

31 changes: 19 additions & 12 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,11 @@ class RendererSVG(RendererBase):
FONT_SCALE = 100.0
fontd = maxdict(50)

def __init__(self, width, height, svgwriter, basename=None):
def __init__(self, width, height, svgwriter, basename=None, image_dpi=72):
self.width = width
self.height = height
self.writer = XMLWriter(svgwriter)
self.image_dpi = image_dpi # the actual dpi we want to rasterize stuff with

self._groupd = {}
if not rcParams['svg.image_inline']:
Expand Down Expand Up @@ -733,6 +734,9 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array,
def option_scale_image(self):
return True

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Only need a single new line between methods.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

def get_image_magnification(self):
return self.image_dpi/72.0

def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwelter - I don't know how much you've invested in checking out the details of this signature but it is worth noting that all backends have it, except for the backend_bases.py superclass. Would you be willing to submit a PR which adds the necessary signature updates to backend_bases.py along with the necessary keyword documentation?

I promise that PR wont take 8 months to merge 😉

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah, sorry. I happly contribute what i have done. But at the moment i am not willing to look into more stuff.

attrib = {}
clipid = self._get_clip(gc)
Expand All @@ -755,6 +759,17 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None):
im.resize(numcols, numrows)

h,w = im.get_size_out()

if dx is None:
w = 72.0*w/self.image_dpi
else:
w = dx

if dy is None:
h = 72.0*h/self.image_dpi
else:
h = dy

oid = getattr(im, '_gid', None)
url = getattr(im, '_url', None)
if url is not None:
Expand Down Expand Up @@ -1113,25 +1128,17 @@ def print_svgz(self, filename, *args, **kwargs):

def _print_svg(self, filename, svgwriter, fh_to_close=None, **kwargs):
try:
image_dpi = kwargs.pop("dpi", 72)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the difference between this image_dpi and self.image_dpi?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is in a different class. From here image_dpi gets passed to the backends constructor.

self.figure.set_dpi(72.0)
width, height = self.figure.get_size_inches()
w, h = width*72, height*72

if rcParams['svg.image_noscale']:
renderer = RendererSVG(w, h, svgwriter, filename)
renderer = RendererSVG(w, h, svgwriter, filename, image_dpi)
else:
# setting mixed renderer dpi other than 72 results in
# incorrect size of the rasterized image. It seems that the
# svg internally uses fixed dpi of 72 and seems to cause
# the problem. I hope someone who knows the svg backends
# take a look at this problem. Meanwhile, the dpi
# parameter is ignored and image_dpi is fixed at 72. - JJL

#image_dpi = kwargs.pop("dpi", 72)
image_dpi = 72
_bbox_inches_restore = kwargs.pop("bbox_inches_restore", None)
renderer = MixedModeRenderer(self.figure,
width, height, image_dpi, RendererSVG(w, h, svgwriter, filename),
width, height, image_dpi, RendererSVG(w, h, svgwriter, filename, image_dpi),
bbox_inches_restore=_bbox_inches_restore)

self.figure.draw(renderer)
Expand Down
Binary file not shown.
Loading