|
22 | 22 |
|
23 | 23 |
|
24 | 24 | __all__ = ['display_pretty', 'display_html', 'display_markdown', |
25 | | - 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json', |
| 25 | + 'display_svg', 'display_png', 'display_jpeg', 'display_webp', |
| 26 | + 'display_latex', 'display_json', |
26 | 27 | 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject', |
27 | 28 | 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON', |
28 | 29 | 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats', |
@@ -200,6 +201,23 @@ def display_jpeg(*objs, **kwargs): |
200 | 201 | _display_mimetype('image/jpeg', objs, **kwargs) |
201 | 202 |
|
202 | 203 |
|
| 204 | +def display_webp(*objs, **kwargs): |
| 205 | + """Display the WEBP representation of an object. |
| 206 | +
|
| 207 | + Parameters |
| 208 | + ---------- |
| 209 | + *objs : object |
| 210 | + The Python objects to display, or if raw=True raw JPEG data to |
| 211 | + display. |
| 212 | + raw : bool |
| 213 | + Are the data objects raw data or Python objects that need to be |
| 214 | + formatted before display? [default: False] |
| 215 | + metadata : dict (optional) |
| 216 | + Metadata to be associated with the specific mimetype output. |
| 217 | + """ |
| 218 | + _display_mimetype('image/webp', objs, **kwargs) |
| 219 | + |
| 220 | + |
203 | 221 | def display_latex(*objs, **kwargs): |
204 | 222 | """Display the LaTeX representation of an object. |
205 | 223 |
|
@@ -776,9 +794,12 @@ def _repr_javascript_(self): |
776 | 794 | r += _lib_t2*len(self.lib) |
777 | 795 | return r |
778 | 796 |
|
779 | | -# constants for identifying png/jpeg data |
| 797 | +# constants for identifying png/jpeg/gif/webp data |
780 | 798 | _PNG = b'\x89PNG\r\n\x1a\n' |
781 | 799 | _JPEG = b'\xff\xd8' |
| 800 | +_GIF1 = b"GIF87a" |
| 801 | +_GIF2 = b"GIF89a" |
| 802 | +_WEBP = b'WEBP' |
782 | 803 |
|
783 | 804 | def _pngxy(data): |
784 | 805 | """read the (width, height) from a PNG header""" |
@@ -809,18 +830,37 @@ def _gifxy(data): |
809 | 830 | """read the (width, height) from a GIF header""" |
810 | 831 | return struct.unpack('<HH', data[6:10]) |
811 | 832 |
|
| 833 | +def _webpxy(data): |
| 834 | + """read the (width, height) from a WEBP header""" |
| 835 | + if data[12:16] == b"VP8 ": |
| 836 | + width, height = struct.unpack('<HH', data[24:30]) |
| 837 | + width = (width & 0x3fff) |
| 838 | + height = (height & 0x3fff) |
| 839 | + return (width, height) |
| 840 | + elif data[12:16] == b"VP8L": |
| 841 | + size_info = struct.unpack('<I', data[21:25])[0] |
| 842 | + width = 1 + ((size_info & 0x3F) << 8) | (size_info >> 24) |
| 843 | + height = 1 + ((((size_info >> 8) & 0xF) << 10) | |
| 844 | + (((size_info >> 14) & 0x3FC) << 2) | |
| 845 | + ((size_info >> 22) & 0x3)) |
| 846 | + return (width, height) |
| 847 | + else: |
| 848 | + raise ValueError("Not a valid WEBP header") |
| 849 | + |
812 | 850 |
|
813 | 851 | class Image(DisplayObject): |
814 | 852 |
|
815 | 853 | _read_flags = 'rb' |
816 | 854 | _FMT_JPEG = u'jpeg' |
817 | 855 | _FMT_PNG = u'png' |
818 | 856 | _FMT_GIF = u'gif' |
819 | | - _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF] |
| 857 | + _FMT_WEBP = u'webp' |
| 858 | + _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF, _FMT_WEBP] |
820 | 859 | _MIMETYPES = { |
821 | 860 | _FMT_PNG: 'image/png', |
822 | 861 | _FMT_JPEG: 'image/jpeg', |
823 | 862 | _FMT_GIF: 'image/gif', |
| 863 | + _FMT_WEBP: 'image/webp', |
824 | 864 | } |
825 | 865 |
|
826 | 866 | def __init__( |
@@ -858,7 +898,7 @@ def __init__( |
858 | 898 | Images from a file are always embedded. |
859 | 899 |
|
860 | 900 | format : unicode |
861 | | - The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given |
| 901 | + The format of the image data (png/jpeg/jpg/gif/webp). If a filename or URL is given |
862 | 902 | for format will be inferred from the filename extension. |
863 | 903 |
|
864 | 904 | embed : bool |
@@ -942,13 +982,21 @@ def __init__( |
942 | 982 | format = self._FMT_PNG |
943 | 983 | elif ext == u'gif': |
944 | 984 | format = self._FMT_GIF |
| 985 | + elif ext == u'webp': |
| 986 | + format = self._FMT_WEBP |
945 | 987 | else: |
946 | 988 | format = ext.lower() |
947 | 989 | elif isinstance(data, bytes): |
948 | 990 | # infer image type from image data header, |
949 | 991 | # only if format has not been specified. |
950 | 992 | if data[:2] == _JPEG: |
951 | 993 | format = self._FMT_JPEG |
| 994 | + elif data[:8] == _PNG: |
| 995 | + format = self._FMT_PNG |
| 996 | + elif data[8:12] == _WEBP: |
| 997 | + format = self._FMT_WEBP |
| 998 | + elif data[:6] == self._GIF1 or data[:6] == self._GIF2: |
| 999 | + format = self._FMT_GIF |
952 | 1000 |
|
953 | 1001 | # failed to detect format, default png |
954 | 1002 | if format is None: |
|
0 commit comments