Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 79c296c

Browse filesBrowse files
authored
Merge pull request #13902 from anntzer/imsavemetadatapilkwargs
Add support for metadata= and pil_kwargs= in imsave().
2 parents d4ce99a + 5e91c5a commit 79c296c
Copy full SHA for 79c296c

File tree

Expand file treeCollapse file tree

3 files changed

+62
-7
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+62
-7
lines changed
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
`~pyplot.imsave` gained support for the ``metadata`` and ``pil_kwargs`` parameters
2+
``````````````````````````````````````````````````````````````````````````````````
3+
4+
These parameters behave similarly as for the `Figure.savefig()` method.

‎lib/matplotlib/image.py

Copy file name to clipboardExpand all lines: lib/matplotlib/image.py
+35-7Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,7 +1434,7 @@ def read_png(*args, **kwargs):
14341434

14351435

14361436
def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
1437-
origin=None, dpi=100):
1437+
origin=None, dpi=100, *, metadata=None, pil_kwargs=None):
14381438
"""
14391439
Save an array as an image file.
14401440
@@ -1467,6 +1467,17 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
14671467
dpi : int
14681468
The DPI to store in the metadata of the file. This does not affect the
14691469
resolution of the output image.
1470+
metadata : dict, optional
1471+
Metadata in the image file. The supported keys depend on the output
1472+
format, see the documentation of the respective backends for more
1473+
information.
1474+
pil_kwargs : dict, optional
1475+
If set to a non-None value, always use Pillow to save the figure
1476+
(regardless of the output format), and pass these keyword arguments to
1477+
`PIL.Image.save`.
1478+
1479+
If the 'pnginfo' key is present, it completely overrides
1480+
*metadata*, including the default 'Software' key.
14701481
"""
14711482
from matplotlib.figure import Figure
14721483
from matplotlib import _png
@@ -1477,10 +1488,14 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
14771488
else rcParams["savefig.format"]).lower()
14781489
if format in ["pdf", "ps", "eps", "svg"]:
14791490
# Vector formats that are not handled by PIL.
1491+
if pil_kwargs is not None:
1492+
raise ValueError(
1493+
f"Cannot use 'pil_kwargs' when saving to {format}")
14801494
fig = Figure(dpi=dpi, frameon=False)
14811495
fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin,
14821496
resize=True)
1483-
fig.savefig(fname, dpi=dpi, format=format, transparent=True)
1497+
fig.savefig(fname, dpi=dpi, format=format, transparent=True,
1498+
metadata=metadata)
14841499
else:
14851500
# Don't bother creating an image; this avoids rounding errors on the
14861501
# size when dividing and then multiplying by dpi.
@@ -1491,17 +1506,28 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
14911506
if origin == "lower":
14921507
arr = arr[::-1]
14931508
rgba = sm.to_rgba(arr, bytes=True)
1494-
if format == "png":
1495-
_png.write_png(rgba, fname, dpi=dpi)
1509+
if format == "png" and pil_kwargs is None:
1510+
_png.write_png(rgba, fname, dpi=dpi, metadata=metadata)
14961511
else:
14971512
try:
14981513
from PIL import Image
1514+
from PIL.PngImagePlugin import PngInfo
14991515
except ImportError as exc:
1500-
raise ImportError(
1501-
f"Saving to {format} requires Pillow") from exc
1516+
if pil_kwargs is not None:
1517+
raise ImportError("Setting 'pil_kwargs' requires Pillow")
1518+
else:
1519+
raise ImportError(f"Saving to {format} requires Pillow")
1520+
if pil_kwargs is None:
1521+
pil_kwargs = {}
15021522
pil_shape = (rgba.shape[1], rgba.shape[0])
15031523
image = Image.frombuffer(
15041524
"RGBA", pil_shape, rgba, "raw", "RGBA", 0, 1)
1525+
if format == "png" and metadata is not None:
1526+
# cf. backend_agg's print_png.
1527+
pnginfo = PngInfo()
1528+
for k, v in metadata.items():
1529+
pnginfo.add_text(k, v)
1530+
pil_kwargs["pnginfo"] = pnginfo
15051531
if format in ["jpg", "jpeg"]:
15061532
format = "jpeg" # Pillow doesn't recognize "jpg".
15071533
color = tuple(
@@ -1510,7 +1536,9 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
15101536
background = Image.new("RGB", pil_shape, color)
15111537
background.paste(image, image)
15121538
image = background
1513-
image.save(fname, format=format, dpi=(dpi, dpi))
1539+
pil_kwargs.setdefault("format", format)
1540+
pil_kwargs.setdefault("dpi", (dpi, dpi))
1541+
image.save(fname, **pil_kwargs)
15141542

15151543

15161544
def pil_to_array(pilImage):

‎lib/matplotlib/tests/test_image.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_image.py
+23Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,29 @@ def test_imsave_color_alpha():
208208
assert_array_equal(data, arr_buf)
209209

210210

211+
def test_imsave_pil_kwargs_png():
212+
Image = pytest.importorskip("PIL.Image")
213+
from PIL.PngImagePlugin import PngInfo
214+
buf = io.BytesIO()
215+
pnginfo = PngInfo()
216+
pnginfo.add_text("Software", "test")
217+
plt.imsave(buf, [[0, 1], [2, 3]],
218+
format="png", pil_kwargs={"pnginfo": pnginfo})
219+
im = Image.open(buf)
220+
assert im.info["Software"] == "test"
221+
222+
223+
def test_imsave_pil_kwargs_tiff():
224+
Image = pytest.importorskip("PIL.Image")
225+
from PIL.TiffTags import TAGS_V2 as TAGS
226+
buf = io.BytesIO()
227+
pil_kwargs = {"description": "test image"}
228+
plt.imsave(buf, [[0, 1], [2, 3]], format="tiff", pil_kwargs=pil_kwargs)
229+
im = Image.open(buf)
230+
tags = {TAGS[k].name: v for k, v in im.tag_v2.items()}
231+
assert tags["ImageDescription"] == "test image"
232+
233+
211234
@image_comparison(baseline_images=['image_alpha'], remove_text=True)
212235
def test_image_alpha():
213236
plt.figure()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.