Skip to content

Commit 2706b2c

Browse files
committed
add webp support to px.imshow
Signed-off-by: maximsmol <[email protected]>
1 parent 7181c4d commit 2706b2c

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

packages/python/plotly/_plotly_utils/data_utils.py

+29-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
pil_imported = False
1111

1212

13-
def image_array_to_data_uri(img, backend="pil", compression=4, ext="png"):
13+
def image_array_to_data_uri(
14+
img, backend="pil", compression=4, ext="webp", backend_kwargs=None
15+
):
1416
"""Converts a numpy array of uint8 into a base64 png or jpg string.
1517
1618
Parameters
@@ -22,8 +24,10 @@ def image_array_to_data_uri(img, backend="pil", compression=4, ext="png"):
2224
otherwise pypng.
2325
compression: int, between 0 and 9
2426
compression level to be passed to the backend
25-
ext: str, 'png' or 'jpg'
27+
ext: str, 'webp', 'png', or 'jpg'
2628
compression format used to generate b64 string
29+
backend_kwargs : dict or None
30+
keyword arguments to be passed to the backend
2731
"""
2832
# PIL and pypng error messages are quite obscure so we catch invalid compression values
2933
if compression < 0 or compression > 9:
@@ -41,15 +45,25 @@ def image_array_to_data_uri(img, backend="pil", compression=4, ext="png"):
4145
if backend == "auto":
4246
backend = "pil" if pil_imported else "pypng"
4347
if ext != "png" and backend != "pil":
44-
raise ValueError("jpg binary strings are only available with PIL backend")
48+
raise ValueError(
49+
"webp and jpg binary strings are only available with PIL backend"
50+
)
51+
52+
if backend_kwargs is None:
53+
backend_kwargs = {}
4554

4655
if backend == "pypng":
4756
ndim = img.ndim
4857
sh = img.shape
4958
if ndim == 3:
5059
img = img.reshape((sh[0], sh[1] * sh[2]))
5160
w = Writer(
52-
sh[1], sh[0], greyscale=(ndim == 2), alpha=alpha, compression=compression
61+
sh[1],
62+
sh[0],
63+
greyscale=(ndim == 2),
64+
alpha=alpha,
65+
compression=compression,
66+
**backend_kwargs
5367
)
5468
img_png = from_array(img, mode=mode)
5569
prefix = "data:image/png;base64,"
@@ -63,13 +77,22 @@ def image_array_to_data_uri(img, backend="pil", compression=4, ext="png"):
6377
"install pillow or use `backend='pypng'."
6478
)
6579
pil_img = Image.fromarray(img)
66-
if ext == "jpg" or ext == "jpeg":
80+
if ext == "webp":
81+
prefix = "data:image/webp;base64,"
82+
ext = "webp"
83+
elif ext == "jpg" or ext == "jpeg":
6784
prefix = "data:image/jpeg;base64,"
6885
ext = "jpeg"
6986
else:
7087
prefix = "data:image/png;base64,"
7188
ext = "png"
7289
with BytesIO() as stream:
73-
pil_img.save(stream, format=ext, compress_level=compression)
90+
pil_img.save(
91+
stream,
92+
format=ext,
93+
compress_level=compression,
94+
lossless=True,
95+
**backend_kwargs
96+
)
7497
base64_string = prefix + base64.b64encode(stream.getvalue()).decode("utf-8")
7598
return base64_string

packages/python/plotly/plotly/express/_imshow.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ def imshow(
7878
binary_string=None,
7979
binary_backend="auto",
8080
binary_compression_level=4,
81-
binary_format="png",
81+
binary_format="webp",
82+
binary_backend_kwargs=None,
8283
text_auto=False,
8384
) -> go.Figure:
8485
"""
@@ -204,10 +205,15 @@ def imshow(
204205
test `len(fig.data[0].source)` and to time the execution of `imshow` to
205206
tune the level of compression. 0 means no compression (not recommended).
206207
207-
binary_format: str, 'png' (default) or 'jpg'
208-
compression format used to generate b64 string. 'png' is recommended
209-
since it uses lossless compression, but 'jpg' (lossy) compression can
210-
result if smaller binary strings for natural images.
208+
binary_format: str, 'webp' (default), 'png', or 'jpg'
209+
compression format used to generate b64 string. 'webp' is recommended
210+
since it supports both lossless and lossy compression with better quality
211+
then 'png' or 'jpg' of similar sizes, but 'jpg' or 'png' can be used for
212+
environments that do not support 'webp'.
213+
214+
binary_backend_kwargs : dict or None
215+
keyword arguments for the image backend. For Pillow, these are passed to `Image.save`.
216+
For 'pypng', these are passed to `Writer.__init__`
211217
212218
text_auto: bool or str (default `False`)
213219
If `True` or a string, single-channel `img` values will be displayed as text.
@@ -502,6 +508,7 @@ def imshow(
502508
backend=binary_backend,
503509
compression=binary_compression_level,
504510
ext=binary_format,
511+
binary_backend_kwargs=binary_backend_kwargs,
505512
)
506513
for index_tup in itertools.product(*iterables)
507514
]

0 commit comments

Comments
 (0)