From 6333ea4d94c6a9bebce60ac55f7dab7dcd634701 Mon Sep 17 00:00:00 2001 From: Kinshuk Dua Date: Mon, 4 Oct 2021 13:24:29 +0530 Subject: [PATCH 1/4] Add support to save images in WebP format --- lib/matplotlib/backend_bases.py | 2 ++ lib/matplotlib/backends/backend_agg.py | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 9bb78cf0cdbc..38d408ba02c6 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -69,6 +69,7 @@ 'svgz': 'Scalable Vector Graphics', 'tif': 'Tagged Image File Format', 'tiff': 'Tagged Image File Format', + 'webp': 'WebP Image Format', } _default_backends = { 'eps': 'matplotlib.backends.backend_ps', @@ -84,6 +85,7 @@ 'svgz': 'matplotlib.backends.backend_svg', 'tif': 'matplotlib.backends.backend_agg', 'tiff': 'matplotlib.backends.backend_agg', + 'webp': 'matplotlib.backends.backend_agg', } diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 4a62f5a921cd..35cc25579c67 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -594,6 +594,29 @@ def print_tif(self, filename_or_obj, *, pil_kwargs=None): print_tiff = print_tif + @_check_savefig_extra_args + def print_webp(self, filename_or_obj, *, pil_kwargs=None): + """ + Write the figure to a WebP file. + + Parameters + ---------- + filename_or_obj : str or path-like or file-like + The file to write to. + + Other Parameters + ---------------- + pil_kwargs : dict, optional + Additional keyword arguments that are passed to + `PIL.Image.Image.save` when saving the figure. + """ + FigureCanvasAgg.draw(self) + if pil_kwargs is None: + pil_kwargs = {} + pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi)) + return (Image.fromarray(np.asarray(self.buffer_rgba())) + .save(filename_or_obj, format='webp', **pil_kwargs)) + @_Backend.export class _BackendAgg(_Backend): From 26f1e3fdb9b713e951633ec7c896ada56d4ac35f Mon Sep 17 00:00:00 2001 From: Kinshuk Dua Date: Tue, 5 Oct 2021 15:44:12 +0530 Subject: [PATCH 2/4] Add tests for WebP format --- lib/matplotlib/tests/test_agg.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/matplotlib/tests/test_agg.py b/lib/matplotlib/tests/test_agg.py index 0e4abf86fe02..2192f939a284 100644 --- a/lib/matplotlib/tests/test_agg.py +++ b/lib/matplotlib/tests/test_agg.py @@ -248,6 +248,24 @@ def test_pil_kwargs_tiff(): tags = {TiffTags.TAGS_V2[k].name: v for k, v in im.tag_v2.items()} assert tags["ImageDescription"] == "test image" +def test_pil_kwargs_webp(): + plt.plot([0, 1, 2], [0, 1, 0]) + buf_small = io.BytesIO() + pil_kwargs_low = {"quality": 1} + plt.savefig(buf_small, format="webp", pil_kwargs=pil_kwargs_low) + buf_large = io.BytesIO() + pil_kwargs_high = {"quality": 100} + plt.savefig(buf_large, format="webp", pil_kwargs=pil_kwargs_high) + assert buf_large.getbuffer().nbytes > buf_small.getbuffer().nbytes + +def test_webp_alpha(): + plt.plot([0, 1, 2], [0, 1, 0]) + buf = io.BytesIO() + plt.savefig(buf, format="webp", transparent=True) + im = Image.open(buf) + assert im.mode == "RGBA" + + def test_draw_path_collection_error_handling(): fig, ax = plt.subplots() From 42d2ee46a128020d77b6e7f113ca57191b21447d Mon Sep 17 00:00:00 2001 From: Kinshuk Dua Date: Mon, 11 Oct 2021 22:53:20 +0530 Subject: [PATCH 3/4] Fix linting errors in test_agg.py --- lib/matplotlib/tests/test_agg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_agg.py b/lib/matplotlib/tests/test_agg.py index 2192f939a284..32fea7cd4590 100644 --- a/lib/matplotlib/tests/test_agg.py +++ b/lib/matplotlib/tests/test_agg.py @@ -248,6 +248,7 @@ def test_pil_kwargs_tiff(): tags = {TiffTags.TAGS_V2[k].name: v for k, v in im.tag_v2.items()} assert tags["ImageDescription"] == "test image" + def test_pil_kwargs_webp(): plt.plot([0, 1, 2], [0, 1, 0]) buf_small = io.BytesIO() @@ -258,13 +259,13 @@ def test_pil_kwargs_webp(): plt.savefig(buf_large, format="webp", pil_kwargs=pil_kwargs_high) assert buf_large.getbuffer().nbytes > buf_small.getbuffer().nbytes + def test_webp_alpha(): plt.plot([0, 1, 2], [0, 1, 0]) buf = io.BytesIO() plt.savefig(buf, format="webp", transparent=True) im = Image.open(buf) assert im.mode == "RGBA" - def test_draw_path_collection_error_handling(): From 394632c79dfd35312529d7bce65332206ab63a82 Mon Sep 17 00:00:00 2001 From: Kinshuk Dua Date: Fri, 15 Oct 2021 10:10:43 +0530 Subject: [PATCH 4/4] remove dpi pil_kwarg from print_webp --- lib/matplotlib/backends/backend_agg.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 35cc25579c67..7dacc6356d12 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -613,7 +613,6 @@ def print_webp(self, filename_or_obj, *, pil_kwargs=None): FigureCanvasAgg.draw(self) if pil_kwargs is None: pil_kwargs = {} - pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi)) return (Image.fromarray(np.asarray(self.buffer_rgba())) .save(filename_or_obj, format='webp', **pil_kwargs))