|
from io import BytesIO |
|
import base64 |
|
from .png import Writer, from_array |
|
|
|
try: |
|
from PIL import Image |
|
|
|
pil_imported = True |
|
except ImportError: |
|
pil_imported = False |
|
|
|
|
|
def image_array_to_data_uri(img, backend="pil", compression=4, ext="png"): |
|
"""Converts a numpy array of uint8 into a base64 png or jpg string. |
|
|
|
Parameters |
|
---------- |
|
img: ndarray of uint8 |
|
array image |
|
backend: str |
|
'auto', 'pil' or 'pypng'. If 'auto', Pillow is used if installed, |
|
otherwise pypng. |
|
compression: int, between 0 and 9 |
|
compression level to be passed to the backend |
|
ext: str, 'png' or 'jpg' |
|
compression format used to generate b64 string |
|
""" |
|
|
|
if compression < 0 or compression > 9: |
|
raise ValueError("compression level must be between 0 and 9.") |
|
alpha = False |
|
if img.ndim == 2: |
|
mode = "L" |
|
elif img.ndim == 3 and img.shape[-1] == 3: |
|
mode = "RGB" |
|
elif img.ndim == 3 and img.shape[-1] == 4: |
|
mode = "RGBA" |
|
alpha = True |
|
else: |
|
raise ValueError("Invalid image shape") |
|
if backend == "auto": |
|
backend = "pil" if pil_imported else "pypng" |
|
if ext != "png" and backend != "pil": |
|
raise ValueError("jpg binary strings are only available with PIL backend") |
|
|
|
if backend == "pypng": |
|
ndim = img.ndim |
|
sh = img.shape |
|
if ndim == 3: |
|
img = img.reshape((sh[0], sh[1] * sh[2])) |
|
w = Writer( |
|
sh[1], sh[0], greyscale=(ndim == 2), alpha=alpha, compression=compression |
|
) |
|
img_png = from_array(img, mode=mode) |
|
prefix = "data:image/png;base64," |
|
with BytesIO() as stream: |
|
w.write(stream, img_png.rows) |
|
base64_string = prefix + base64.b64encode(stream.getvalue()).decode("utf-8") |
|
else: |
|
if not pil_imported: |
|
raise ImportError( |
|
"pillow needs to be installed to use `backend='pil'. Please" |
|
"install pillow or use `backend='pypng'." |
|
) |
|
pil_img = Image.fromarray(img) |
|
if ext == "jpg" or ext == "jpeg": |
|
prefix = "data:image/jpeg;base64," |
|
ext = "jpeg" |
|
else: |
|
prefix = "data:image/png;base64," |
|
ext = "png" |
|
with BytesIO() as stream: |
|
pil_img.save(stream, format=ext, compress_level=compression) |
|
base64_string = prefix + base64.b64encode(stream.getvalue()).decode("utf-8") |
|
return base64_string |
|
|