Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 71eca02

Browse files
committed
Allow passing arguments to PIL.Image.save().
1 parent 354a430 commit 71eca02

File tree

4 files changed

+53
-16
lines changed

4 files changed

+53
-16
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*pil_kwargs* argument to savefig
2+
````````````````````````````````
3+
4+
Matplotlib uses Pillow to handle saving to the JPEG and TIFF formats. The
5+
`~Figure.savefig()` function gained a *pil_kwargs* keyword argument, which can
6+
be used to forward arguments to Pillow's ``Image.save()``.

lib/matplotlib/backends/backend_agg.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ def print_raw(self, filename_or_obj, *args, **kwargs):
450450
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
451451
cbook.open_file_cm(filename_or_obj, "wb") as fh:
452452
fh.write(renderer._renderer.buffer_rgba())
453+
453454
print_rgba = print_raw
454455

455456
def print_png(self, filename_or_obj, *args, **kwargs):
@@ -507,7 +508,7 @@ def print_png(self, filename_or_obj, *args, **kwargs):
507508
with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
508509
cbook.open_file_cm(filename_or_obj, "wb") as fh:
509510
_png.write_png(renderer._renderer, fh,
510-
self.figure.dpi, metadata=metadata)
511+
self.figure.dpi, metadata=metadata)
511512

512513
def print_to_buffer(self):
513514
FigureCanvasAgg.draw(self)
@@ -517,8 +518,13 @@ def print_to_buffer(self):
517518
(int(renderer.width), int(renderer.height)))
518519

519520
if _has_pil:
520-
# add JPEG support
521-
def print_jpg(self, filename_or_obj, *args, dryrun=False, **kwargs):
521+
522+
# Note that these methods should typically be called via savefig() and
523+
# print_figure(), and the latter ensures that `self.figure.dpi` already
524+
# matches the dpi kwarg (if any).
525+
526+
def print_jpg(self, filename_or_obj, *args, dryrun=False,
527+
pil_kwargs=None, **kwargs):
522528
"""
523529
Write the figure to a JPEG file.
524530
@@ -543,6 +549,11 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, **kwargs):
543549
progressive : bool
544550
If present, indicates that this image
545551
should be stored as a progressive JPEG file.
552+
553+
pil_kwargs : dict, optional
554+
Additional keyword arguments that are passed to Pillow when
555+
saving the figure. These take precedence over *quality*,
556+
*optimize* and *progressive*.
546557
"""
547558
buf, size = self.print_to_buffer()
548559
if dryrun:
@@ -554,25 +565,29 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, **kwargs):
554565
color = tuple([int(x * 255) for x in rgba[:3]])
555566
background = Image.new('RGB', size, color)
556567
background.paste(image, image)
557-
options = {k: kwargs[k]
558-
for k in ['quality', 'optimize', 'progressive', 'dpi']
559-
if k in kwargs}
560-
options.setdefault('quality', rcParams['savefig.jpeg_quality'])
561-
if 'dpi' in options:
562-
# Set the same dpi in both x and y directions
563-
options['dpi'] = (options['dpi'], options['dpi'])
564-
565-
return background.save(filename_or_obj, format='jpeg', **options)
568+
if pil_kwargs is None:
569+
pil_kwargs = {}
570+
for k in ["quality", "optimize", "progressive"]:
571+
if k in kwargs:
572+
pil_kwargs.setdefault(k, kwargs[k])
573+
pil_kwargs.setdefault("quality", rcParams["savefig.jpeg_quality"])
574+
pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi))
575+
return background.save(
576+
filename_or_obj, format='jpeg', **pil_kwargs)
577+
566578
print_jpeg = print_jpg
567579

568-
# add TIFF support
569-
def print_tif(self, filename_or_obj, *args, dryrun=False, **kwargs):
580+
def print_tif(self, filename_or_obj, *args, dryrun=False,
581+
pil_kwargs=None, **kwargs):
570582
buf, size = self.print_to_buffer()
571583
if dryrun:
572584
return
573585
image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1)
574-
dpi = (self.figure.dpi, self.figure.dpi)
575-
return image.save(filename_or_obj, format='tiff', dpi=dpi)
586+
if pil_kwargs is None:
587+
pil_kwargs = {}
588+
pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi))
589+
return image.save(filename_or_obj, format='tiff', **pil_kwargs)
590+
576591
print_tiff = print_tif
577592

578593

lib/matplotlib/figure.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,12 @@ def savefig(self, fname, *, frameon=None, transparent=None, **kwargs):
21032103
`~.backend_pdf.PdfPages`.
21042104
- 'eps' and 'ps' with PS backend: Only 'Creator' is supported.
21052105
2106+
pil_kwargs : dict, optional
2107+
Additional keyword arguments that are passed to Pillow when saving
2108+
the figure. Only applicable for formats that are saved using
2109+
Pillow, i.e. JPEG and TIFF.
21062110
"""
2111+
21072112
kwargs.setdefault('dpi', rcParams['savefig.dpi'])
21082113
if frameon is None:
21092114
frameon = rcParams['savefig.frameon']

lib/matplotlib/tests/test_agg.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,14 @@ def test_jpeg_dpi():
239239
plt.savefig(buf, format="jpg", dpi=200)
240240
im = Image.open(buf)
241241
assert im.info['dpi'] == (200, 200)
242+
243+
244+
def test_pil_kwargs():
245+
Image = pytest.importorskip("PIL.Image")
246+
from PIL.TiffTags import TAGS_V2 as TAGS
247+
buf = io.BytesIO()
248+
pil_kwargs = {"description": "test image"}
249+
plt.figure().savefig(buf, format="tiff", pil_kwargs=pil_kwargs)
250+
im = Image.open(buf)
251+
tags = {TAGS[k].name: v for k, v in im.tag_v2.items()}
252+
assert tags["ImageDescription"] == "test image"

0 commit comments

Comments
 (0)