From e406c05bd0c4ae9b0d6cc5aef5771740db0db240 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 24 Oct 2011 11:00:18 -0400 Subject: [PATCH 1/2] Make "set_alpha()" work on images. Now, alpha blending is handled in the backends. Tested and works on Agg, Pdf and Svg. (Ps does not support alpha). --- lib/matplotlib/backends/backend_svg.py | 4 ++++ lib/matplotlib/image.py | 14 +++++++++----- src/_backend_agg.cpp | 6 +++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index b6542eecba63..25891630841a 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -757,6 +757,10 @@ def draw_image(self, gc, x, y, im, dx=None, dy=None, transform=None): im.flipud_out() attrib['xlink:href'] = filename + alpha = gc.get_alpha() + if alpha != 1.0: + attrib['opacity'] = str(alpha) + if transform is None: self.writer.element( 'image', diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 12711ec55370..9b7076795e72 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -199,7 +199,7 @@ def _get_unsampled_image(self, A, image_extents, viewlim): im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self._rgbacache = x else: x = self._rgbacache @@ -345,6 +345,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.axes.bbox.frozen()) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) if self._check_unsampled_image(renderer): self._draw_unsampled_image(renderer, gc) @@ -722,7 +723,7 @@ def set_data(self, x, y, A): A.shape = A.shape[0:2] if len(A.shape) == 2: if A.dtype != np.uint8: - A = self.to_rgba(A, alpha=self._alpha, bytes=True) + A = self.to_rgba(A, bytes=True) self.is_grayscale = self.cmap.is_gray() else: A = np.repeat(A[:,:,np.newaxis], 4, 2) @@ -824,7 +825,7 @@ def make_image(self, magnification=1.0): width = width * magnification height = height * magnification if self._rgbacache is None: - A = self.to_rgba(self._A, alpha=self._alpha, bytes=True) + A = self.to_rgba(self._A, bytes=True) self._rgbacache = A if self._A.ndim == 2: self.is_grayscale = self.cmap.is_gray() @@ -851,6 +852,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.axes.bbox.frozen()) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) renderer.draw_image(gc, round(self.axes.bbox.xmin), round(self.axes.bbox.ymin), @@ -974,7 +976,7 @@ def make_image(self, magnification=1.0): if self._A is None: raise RuntimeError('You must first set the image array') - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self.magnification = magnification # if magnification is not one, we need to resize ismag = magnification!=1 @@ -1008,6 +1010,7 @@ def draw(self, renderer, *args, **kwargs): gc = renderer.new_gc() gc.set_clip_rectangle(self.figure.bbox) gc.set_clip_path(self.get_clip_path()) + gc.set_alpha(self.get_alpha()) renderer.draw_image(gc, round(self.ox), round(self.oy), im) gc.restore() @@ -1096,7 +1099,7 @@ def make_image(self, renderer, magnification=1.0): im.is_grayscale = False else: if self._rgbacache is None: - x = self.to_rgba(self._A, self._alpha, bytes=True) + x = self.to_rgba(self._A, bytes=True) self._rgbacache = x else: x = self._rgbacache @@ -1148,6 +1151,7 @@ def draw(self, renderer, *args, **kwargs): l, b, r, t = self.get_window_extent(renderer).extents gc = renderer.new_gc() self._set_gc_clip(gc) + gc.set_alpha(self.get_alpha()) #gc.set_clip_path(self.get_clip_path()) renderer.draw_image(gc, round(l), round(b), im) gc.restore() diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 200fad33461a..f7a986fc2f95 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -988,6 +988,7 @@ RendererAgg::draw_image(const Py::Tuple& args) agg::trans_affine affine_trans; bool has_affine = false; double x, y, w, h; + double alpha; if (args.size() == 7) { @@ -1006,6 +1007,8 @@ RendererAgg::draw_image(const Py::Tuple& args) warnings from the compiler */ } + alpha = gc.alpha; + theRasterizer.reset_clipping(); rendererBase.reset_clipping(true); set_clipbox(gc.cliprect, theRasterizer); @@ -1097,7 +1100,8 @@ RendererAgg::draw_image(const Py::Tuple& args) else { set_clipbox(gc.cliprect, rendererBase); - rendererBase.blend_from(pixf, 0, (int)x, (int)(height - (y + image->rowsOut))); + rendererBase.blend_from( + pixf, 0, (int)x, (int)(height - (y + image->rowsOut)), alpha * 255); } rendererBase.reset_clipping(true); From 1dac36d829a8737741e1b223049042a4bc096070 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 21 Oct 2011 09:34:11 -0400 Subject: [PATCH 2/2] Tell Agg that we're giving it pre-multiplied image data --- src/_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_image.cpp b/src/_image.cpp index 3278b6c382b0..6bb202a8b320 100644 --- a/src/_image.cpp +++ b/src/_image.cpp @@ -33,7 +33,7 @@ #include "mplutils.h" -typedef agg::pixfmt_rgba32 pixfmt; +typedef agg::pixfmt_rgba32_pre pixfmt; typedef agg::renderer_base renderer_base; typedef agg::span_interpolator_linear<> interpolator_type; typedef agg::rasterizer_scanline_aa rasterizer;