diff --git a/CHANGELOG b/CHANGELOG index c4155dd34267..4e4782c14671 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index a6fce09ef9ff..126a776746c5 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -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 + \ No newline at end of file diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 0b9b7ab51701..ddddcbd1299b 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -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']: @@ -733,6 +734,9 @@ def draw_gouraud_triangles(self, gc, triangles_array, colors_array, def option_scale_image(self): return True + 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): attrib = {} clipid = self._get_clip(gc) @@ -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: @@ -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) 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) diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf new file mode 100644 index 000000000000..3904df03ad42 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg new file mode 100644 index 000000000000..38027d48922d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 4556013bc4cb..7c0d7fd19e19 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -160,6 +160,32 @@ def test_no_interpolation_origin(): ax = fig.add_subplot(212) ax.imshow(np.arange(100).reshape((2, 50)), interpolation='none') +@image_comparison(baseline_images=['rasterize_10dpi'], extensions=['pdf','svg'], tol=1.5e-3, remove_text=True) +def test_rasterize_dpi(): + # This test should check rasterized rendering with high output resolution. + # It plots a rasterized line and a normal image with implot. So it will catch + # when images end up in the wrong place in case of non-standard dpi setting. + # Instead of high-res rasterization i use low-res. Therefore the fact that the + # resolution is non-standard is is easily checked by image_comparison. + import numpy as np + import matplotlib.pyplot as plt + + img = np.asarray([[1, 2], [3, 4]]) + + fig, axes = plt.subplots(1, 3, figsize = (3, 1)) + + axes[0].imshow(img) + + axes[1].plot([0,1],[0,1], linewidth=20., rasterized=True) + axes[1].set(xlim = (0,1), ylim = (-1, 2)) + + axes[2].plot([0,1],[0,1], linewidth=20.) + axes[2].set(xlim = (0,1), ylim = (-1, 2)) + + rcParams['savefig.dpi'] = 10 + + + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False)