@@ -1434,7 +1434,7 @@ def read_png(*args, **kwargs):
1434
1434
1435
1435
1436
1436
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 ):
1438
1438
"""
1439
1439
Save an array as an image file.
1440
1440
@@ -1467,6 +1467,17 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
1467
1467
dpi : int
1468
1468
The DPI to store in the metadata of the file. This does not affect the
1469
1469
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.
1470
1481
"""
1471
1482
from matplotlib .figure import Figure
1472
1483
from matplotlib import _png
@@ -1477,10 +1488,14 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
1477
1488
else rcParams ["savefig.format" ]).lower ()
1478
1489
if format in ["pdf" , "ps" , "eps" , "svg" ]:
1479
1490
# 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 } " )
1480
1494
fig = Figure (dpi = dpi , frameon = False )
1481
1495
fig .figimage (arr , cmap = cmap , vmin = vmin , vmax = vmax , origin = origin ,
1482
1496
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 )
1484
1499
else :
1485
1500
# Don't bother creating an image; this avoids rounding errors on the
1486
1501
# size when dividing and then multiplying by dpi.
@@ -1491,17 +1506,28 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
1491
1506
if origin == "lower" :
1492
1507
arr = arr [::- 1 ]
1493
1508
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 )
1496
1511
else :
1497
1512
try :
1498
1513
from PIL import Image
1514
+ from PIL .PngImagePlugin import PngInfo
1499
1515
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 = {}
1502
1522
pil_shape = (rgba .shape [1 ], rgba .shape [0 ])
1503
1523
image = Image .frombuffer (
1504
1524
"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
1505
1531
if format in ["jpg" , "jpeg" ]:
1506
1532
format = "jpeg" # Pillow doesn't recognize "jpg".
1507
1533
color = tuple (
@@ -1510,7 +1536,9 @@ def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None,
1510
1536
background = Image .new ("RGB" , pil_shape , color )
1511
1537
background .paste (image , image )
1512
1538
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 )
1514
1542
1515
1543
1516
1544
def pil_to_array (pilImage ):
0 commit comments