Skip to content

Commit 3a87bb7

Browse files
committed
Factor common parts of saving to different formats using pillow.
We don't need to drop the alpha channel for jpeg anymore as imsave handles that. In imsave, also clarify that `sm` is not going to be used in the already-usable-rgba case.
1 parent a9bba75 commit 3a87bb7

File tree

2 files changed

+18
-26
lines changed

2 files changed

+18
-26
lines changed

lib/matplotlib/backends/backend_agg.py

+14-22
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,16 @@ def print_raw(self, filename_or_obj, *args):
487487

488488
print_rgba = print_raw
489489

490+
def _print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata=None):
491+
"""
492+
Draw the canvas, then save it using `.image.imsave` (to which
493+
*pil_kwargs* and *metadata* are forwarded).
494+
"""
495+
FigureCanvasAgg.draw(self)
496+
mpl.image.imsave(
497+
filename_or_obj, self.buffer_rgba(), format=fmt, origin="upper",
498+
dpi=self.figure.dpi, metadata=metadata, pil_kwargs=pil_kwargs)
499+
490500
@_check_savefig_extra_args
491501
@_api.delete_parameter("3.5", "args")
492502
def print_png(self, filename_or_obj, *args,
@@ -537,10 +547,7 @@ def print_png(self, filename_or_obj, *args,
537547
If the 'pnginfo' key is present, it completely overrides
538548
*metadata*, including the default 'Software' key.
539549
"""
540-
FigureCanvasAgg.draw(self)
541-
mpl.image.imsave(
542-
filename_or_obj, self.buffer_rgba(), format="png", origin="upper",
543-
dpi=self.figure.dpi, metadata=metadata, pil_kwargs=pil_kwargs)
550+
self._print_pil(filename_or_obj, "png", pil_kwargs, metadata)
544551

545552
def print_to_buffer(self):
546553
FigureCanvasAgg.draw(self)
@@ -573,26 +580,15 @@ def print_jpg(self, filename_or_obj, *args, pil_kwargs=None, **kwargs):
573580
r, g, b, a = mcolors.to_rgba(self.figure.get_facecolor())
574581
try:
575582
self.figure.set_facecolor(a * np.array([r, g, b]) + 1 - a)
576-
FigureCanvasAgg.draw(self)
583+
self._print_pil(filename_or_obj, "jpeg", pil_kwargs)
577584
finally:
578585
self.figure.set_facecolor((r, g, b, a))
579-
if pil_kwargs is None:
580-
pil_kwargs = {}
581-
pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi))
582-
# Drop alpha channel now.
583-
return (Image.fromarray(np.asarray(self.buffer_rgba())[..., :3])
584-
.save(filename_or_obj, format='jpeg', **pil_kwargs))
585586

586587
print_jpeg = print_jpg
587588

588589
@_check_savefig_extra_args
589590
def print_tif(self, filename_or_obj, *, pil_kwargs=None):
590-
FigureCanvasAgg.draw(self)
591-
if pil_kwargs is None:
592-
pil_kwargs = {}
593-
pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi))
594-
return (Image.fromarray(np.asarray(self.buffer_rgba()))
595-
.save(filename_or_obj, format='tiff', **pil_kwargs))
591+
self._print_pil(filename_or_obj, "tiff", pil_kwargs)
596592

597593
print_tiff = print_tif
598594

@@ -612,11 +608,7 @@ def print_webp(self, filename_or_obj, *, pil_kwargs=None):
612608
Additional keyword arguments that are passed to
613609
`PIL.Image.Image.save` when saving the figure.
614610
"""
615-
FigureCanvasAgg.draw(self)
616-
if pil_kwargs is None:
617-
pil_kwargs = {}
618-
return (Image.fromarray(np.asarray(self.buffer_rgba()))
619-
.save(filename_or_obj, format='webp', **pil_kwargs))
611+
self._print_pil(filename_or_obj, "webp", pil_kwargs)
620612

621613

622614
@_Backend.export

lib/matplotlib/image.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1601,20 +1601,20 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
16011601
else:
16021602
# Don't bother creating an image; this avoids rounding errors on the
16031603
# size when dividing and then multiplying by dpi.
1604-
sm = cm.ScalarMappable(cmap=cmap)
1605-
sm.set_clim(vmin, vmax)
16061604
if origin is None:
16071605
origin = mpl.rcParams["image.origin"]
16081606
if origin == "lower":
16091607
arr = arr[::-1]
16101608
if (isinstance(arr, memoryview) and arr.format == "B"
16111609
and arr.ndim == 3 and arr.shape[-1] == 4):
1612-
# Such an ``arr`` would also be handled fine by sm.to_rgba (after
1613-
# casting with asarray), but it is useful to special-case it
1610+
# Such an ``arr`` would also be handled fine by sm.to_rgba below
1611+
# (after casting with asarray), but it is useful to special-case it
16141612
# because that's what backend_agg passes, and can be in fact used
16151613
# as is, saving a few operations.
16161614
rgba = arr
16171615
else:
1616+
sm = cm.ScalarMappable(cmap=cmap)
1617+
sm.set_clim(vmin, vmax)
16181618
rgba = sm.to_rgba(arr, bytes=True)
16191619
if pil_kwargs is None:
16201620
pil_kwargs = {}

0 commit comments

Comments
 (0)