diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index f3b23ca95531..8a3c93c8fc6f 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -38,6 +38,7 @@ from matplotlib.mathtext import MathTextParser from matplotlib.path import Path from matplotlib.transforms import Bbox, BboxBase +from matplotlib import colors as mcolors from matplotlib.backends._backend_agg import RendererAgg as _RendererAgg from matplotlib import _png @@ -551,7 +552,6 @@ def print_to_buffer(self): return result if _has_pil: - # add JPEG support def print_jpg(self, filename_or_obj, *args, **kwargs): """ @@ -573,14 +573,21 @@ def print_jpg(self, filename_or_obj, *args, **kwargs): buf, size = self.print_to_buffer() if kwargs.pop("dryrun", False): return + # The image is "pasted" onto a white background image to safely + # handle any transparency image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1) + color = mcolors.colorConverter.to_rgb( + rcParams.get('savefig.facecolor', 'white')) + color = tuple([int(x * 255.0) for x in color]) + background = Image.new('RGB', size, color) + background.paste(image, image) options = restrict_dict(kwargs, ['quality', 'optimize', 'progressive']) if 'quality' not in options: options['quality'] = rcParams['savefig.jpeg_quality'] - return image.save(filename_or_obj, format='jpeg', **options) + return background.save(filename_or_obj, format='jpeg', **options) print_jpeg = print_jpg # add TIFF support diff --git a/lib/matplotlib/tests/test_image.py b/lib/matplotlib/tests/test_image.py index 6f69822b535d..ef5108c88457 100644 --- a/lib/matplotlib/tests/test_image.py +++ b/lib/matplotlib/tests/test_image.py @@ -8,7 +8,7 @@ from matplotlib.testing.decorators import image_comparison, knownfailureif, cleanup from matplotlib.image import BboxImage, imread, NonUniformImage from matplotlib.transforms import Bbox -from matplotlib import rcParams +from matplotlib import rcParams, rc_context import matplotlib.pyplot as plt from nose.tools import assert_raises from numpy.testing import assert_array_equal, assert_array_almost_equal @@ -453,6 +453,34 @@ def test_nonuniformimage_setnorm(): im = NonUniformImage(ax) im.set_norm(plt.Normalize()) +@knownfailureif(not HAS_PIL) +@cleanup +def test_jpeg_alpha(): + plt.figure(figsize=(1, 1), dpi=300) + # Create an image that is all black, with a gradient from 0-1 in + # the alpha channel from left to right. + im = np.zeros((300, 300, 4), dtype=np.float) + im[..., 3] = np.linspace(0.0, 1.0, 300) + + plt.figimage(im) + + buff = io.BytesIO() + with rc_context({'savefig.facecolor': 'red'}): + plt.savefig(buff, transparent=True, format='jpg', dpi=300) + + buff.seek(0) + image = Image.open(buff) + + # If this fails, there will be only one color (all black). If this + # is working, we should have all 256 shades of grey represented. + print("num colors: ", len(image.getcolors(256))) + assert len(image.getcolors(256)) >= 175 and len(image.getcolors(256)) <= 185 + # The fully transparent part should be red, not white or black + # or anything else + print("corner pixel: ", image.getpixel((0, 0))) + assert image.getpixel((0, 0)) == (254, 0, 0) + + if __name__=='__main__': import nose nose.runmodule(argv=['-s','--with-doctest'], exit=False)