Skip to content

Commit

Permalink
Merge pull request #21 from hhoppe:pixelated
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 499277582
  • Loading branch information
The mediapy Authors committed Jan 3, 2023
2 parents 8f073aa + 056b42d commit 01fdedc
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 8 deletions.
22 changes: 17 additions & 5 deletions mediapy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"""

__docformat__ = 'google'
__version__ = '1.1.2'
__version__ = '1.1.3'
__version_info__ = tuple(int(num) for num in __version__.split('.'))

import base64
Expand All @@ -123,6 +123,7 @@
import urllib.request

import IPython.display
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import numpy.typing as npt
Expand Down Expand Up @@ -755,7 +756,7 @@ def to_rgb(
vmax = np.amax(np.where(np.isfinite(a), a, -np.inf)) if vmax is None else vmax
a = (a.astype('float') - vmin) / (vmax - vmin + np.finfo(float).eps)
if isinstance(cmap, str):
rgb_from_scalar = plt.cm.get_cmap(cmap)
rgb_from_scalar = matplotlib.colormaps[cmap]
else:
rgb_from_scalar = cmap
a = rgb_from_scalar(a)
Expand Down Expand Up @@ -811,6 +812,7 @@ def html_from_compressed_image(data: bytes,
*,
title: Optional[str] = None,
border: Union[bool, str] = False,
pixelated: bool = True,
fmt: str = 'png') -> str:
"""Returns an HTML string with an image tag containing encoded data.
Expand All @@ -821,13 +823,15 @@ def html_from_compressed_image(data: bytes,
title: Optional text shown centered above image.
border: If `bool`, whether to place a black boundary around the image, or if
`str`, the boundary CSS style.
pixelated: If True, sets the CSS style to 'image-rendering: pixelated;'.
fmt: Compression encoding.
"""
b64 = base64.b64encode(data).decode('utf-8')
border = (f'{border}; ' if isinstance(border, str) else
'border:1px solid black; ' if border else '')
s_pixelated = 'pixelated' if pixelated else 'auto'
s = (f'<img width="{width}" height="{height}"'
f' style="{border}image-rendering:pixelated; object-fit:cover;"'
f' style="{border}image-rendering:{s_pixelated}; object-fit:cover;"'
f' src="data:image/{fmt};base64,{b64}"/>')
if title:
s = f"""<div style="display:flex; align-items:left;">
Expand Down Expand Up @@ -889,6 +893,7 @@ def show_images(
border: Union[bool, str] = False,
ylabel: str = '',
html_class: str = 'show_images',
pixelated: Optional[bool] = None,
return_html: bool = False,
) -> Optional[str]:
"""Displays a row of images in the IPython/Jupyter notebook.
Expand Down Expand Up @@ -919,6 +924,9 @@ def show_images(
`str`, the boundary CSS style.
ylabel: Text (rotated by 90 degrees) shown on the left of each row.
html_class: CSS class name used in definition of HTML element.
pixelated: If True, sets the CSS style to 'image-rendering: pixelated;'; if
False, sets 'image-rendering: auto'; if None, uses pixelated rendering
only on images for which `width` or `height` introduces magnification.
return_html: If `True` return the raw HTML `str` instead of displaying.
Returns:
Expand Down Expand Up @@ -970,9 +978,11 @@ def html_from_compressed_images() -> str:
html_strings = []
for image, title, png_data in zip(list_images, list_titles, png_datas):
w, h = _get_width_height(width, height, image.shape[:2])
magnified = h > image.shape[0] or w > image.shape[1]
pixelated2 = pixelated if pixelated is not None else magnified
html_strings.append(
html_from_compressed_image(
png_data, w, h, title=title, border=border))
png_data, w, h, title=title, border=border, pixelated=pixelated2))
# Create single-row tables each with no more than 'columns' elements.
table_strings = []
for row_html_strings in _chunked(html_strings, columns):
Expand Down Expand Up @@ -1691,6 +1701,7 @@ def show_videos(videos: Union[Iterable[Iterable[_NDArray]],
if downsample and (w < first_image.shape[1] or h < first_image.shape[0]):
# Not resize_video() because each image may have different depth and type.
video = [resize_image(image, (h, w)) for image in video]
first_image = video[0]
data = compress_video(
video, metadata=metadata, fps=fps, bps=bps, qp=qp, codec=codec)
if title and _config.show_save_dir:
Expand All @@ -1699,8 +1710,9 @@ def show_videos(videos: Union[Iterable[Iterable[_NDArray]],
with _open(path, mode='wb') as f:
f.write(data)
if codec == 'gif':
pixelated = h > first_image.shape[0] or w > first_image.shape[1]
html_string = html_from_compressed_image(
data, w, h, title=title, fmt='gif', **kwargs)
data, w, h, title=title, fmt='gif', pixelated=pixelated, **kwargs)
else:
html_string = html_from_compressed_video(
data, w, h, title=title, **kwargs)
Expand Down
27 changes: 24 additions & 3 deletions mediapy_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
import pathlib
import re
import tempfile
import unittest.mock as mock
from unittest import mock

from absl.testing import absltest
from absl.testing import parameterized
import IPython
import matplotlib.pyplot as plt
import matplotlib
import mediapy as media
import numpy as np

Expand Down Expand Up @@ -394,7 +394,7 @@ def test_uint8_to_rgb(self):
a = np.array([100, 120, 140], dtype=np.uint8)

def gray(x):
return plt.cm.get_cmap('gray')(x)[..., :3]
return matplotlib.colormaps['gray'](x)[..., :3]

self.assert_all_close(media.to_rgb(a), gray([0.0, 0.5, 1.0]))
self.assert_all_close(
Expand Down Expand Up @@ -456,6 +456,27 @@ def test_show_image_downsampled(self):
size_min_max = (10_000, 20_000) if downsample else (200_000, 300_000)
self.assertBetween(len(htmls[0].data), *size_min_max)

def test_show_image_default_no_pixelated(self):
htmls = []
with mock.patch('IPython.display.display', htmls.append):
media.show_image(media.color_ramp((10, 10)))
self.assertLen(htmls, 1)
self.assertIsInstance(htmls[0], IPython.display.HTML)
self.assertLen(re.findall('(?s)<img', htmls[0].data), 1)
self.assertLen(re.findall('(?s)image-rendering:auto', htmls[0].data), 1)
self.assertEmpty(re.findall('(?s)image-rendering:pixelated', htmls[0].data))

def test_show_image_magnified_pixelated(self):
htmls = []
with mock.patch('IPython.display.display', htmls.append):
media.show_image(media.color_ramp((10, 10)), width=20)
self.assertLen(htmls, 1)
self.assertIsInstance(htmls[0], IPython.display.HTML)
self.assertLen(re.findall('(?s)<img', htmls[0].data), 1)
self.assertLen(
re.findall('(?s)image-rendering:pixelated', htmls[0].data), 1)
self.assertEmpty(re.findall('(?s)image-rendering:auto', htmls[0].data))

def test_show_images_list(self):
htmls = []
with mock.patch('IPython.display.display', htmls.append):
Expand Down

0 comments on commit 01fdedc

Please sign in to comment.