##// END OF EJS Templates
ENH: add webp support to IPython.display.Image and complete identification of JPEG,PNG,GIF,WEBP image types by initial bytes (#14526)...
M Bussonnier -
r28924:d7d58a36 merge
parent child Browse files
Show More
@@ -21,13 +21,35 from IPython.testing.skipdoctest import skip_doctest
21 21 from . import display_functions
22 22
23 23
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
29 'set_matplotlib_close',
30 'Video']
24 __all__ = [
25 "display_pretty",
26 "display_html",
27 "display_markdown",
28 "display_svg",
29 "display_png",
30 "display_jpeg",
31 "display_webp",
32 "display_latex",
33 "display_json",
34 "display_javascript",
35 "display_pdf",
36 "DisplayObject",
37 "TextDisplayObject",
38 "Pretty",
39 "HTML",
40 "Markdown",
41 "Math",
42 "Latex",
43 "SVG",
44 "ProgressBar",
45 "JSON",
46 "GeoJSON",
47 "Javascript",
48 "Image",
49 "set_matplotlib_formats",
50 "set_matplotlib_close",
51 "Video",
52 ]
31 53
32 54 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
33 55
@@ -200,6 +222,23 def display_jpeg(*objs, **kwargs):
200 222 _display_mimetype('image/jpeg', objs, **kwargs)
201 223
202 224
225 def display_webp(*objs, **kwargs):
226 """Display the WEBP representation of an object.
227
228 Parameters
229 ----------
230 *objs : object
231 The Python objects to display, or if raw=True raw JPEG data to
232 display.
233 raw : bool
234 Are the data objects raw data or Python objects that need to be
235 formatted before display? [default: False]
236 metadata : dict (optional)
237 Metadata to be associated with the specific mimetype output.
238 """
239 _display_mimetype("image/webp", objs, **kwargs)
240
241
203 242 def display_latex(*objs, **kwargs):
204 243 """Display the LaTeX representation of an object.
205 244
@@ -776,9 +815,14 class Javascript(TextDisplayObject):
776 815 r += _lib_t2*len(self.lib)
777 816 return r
778 817
779 # constants for identifying png/jpeg data
780 _PNG = b'\x89PNG\r\n\x1a\n'
781 _JPEG = b'\xff\xd8'
818
819 # constants for identifying png/jpeg/gif/webp data
820 _PNG = b"\x89PNG\r\n\x1a\n"
821 _JPEG = b"\xff\xd8"
822 _GIF1 = b"GIF87a"
823 _GIF2 = b"GIF89a"
824 _WEBP = b"WEBP"
825
782 826
783 827 def _pngxy(data):
784 828 """read the (width, height) from a PNG header"""
@@ -786,6 +830,7 def _pngxy(data):
786 830 # next 8 bytes are width/height
787 831 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
788 832
833
789 834 def _jpegxy(data):
790 835 """read the (width, height) from a JPEG header"""
791 836 # adapted from http://www.64lines.com/jpeg-width-height
@@ -805,22 +850,45 def _jpegxy(data):
805 850 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
806 851 return w, h
807 852
853
808 854 def _gifxy(data):
809 855 """read the (width, height) from a GIF header"""
810 856 return struct.unpack('<HH', data[6:10])
811 857
812 858
859 def _webpxy(data):
860 """read the (width, height) from a WEBP header"""
861 if data[12:16] == b"VP8 ":
862 width, height = struct.unpack("<HH", data[24:30])
863 width = width & 0x3FFF
864 height = height & 0x3FFF
865 return (width, height)
866 elif data[12:16] == b"VP8L":
867 size_info = struct.unpack("<I", data[21:25])[0]
868 width = 1 + ((size_info & 0x3F) << 8) | (size_info >> 24)
869 height = 1 + (
870 (((size_info >> 8) & 0xF) << 10)
871 | (((size_info >> 14) & 0x3FC) << 2)
872 | ((size_info >> 22) & 0x3)
873 )
874 return (width, height)
875 else:
876 raise ValueError("Not a valid WEBP header")
877
878
813 879 class Image(DisplayObject):
814 880
815 _read_flags = 'rb'
816 _FMT_JPEG = u'jpeg'
817 _FMT_PNG = u'png'
818 _FMT_GIF = u'gif'
819 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
881 _read_flags = "rb"
882 _FMT_JPEG = "jpeg"
883 _FMT_PNG = "png"
884 _FMT_GIF = "gif"
885 _FMT_WEBP = "webp"
886 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF, _FMT_WEBP]
820 887 _MIMETYPES = {
821 _FMT_PNG: 'image/png',
822 _FMT_JPEG: 'image/jpeg',
823 _FMT_GIF: 'image/gif',
888 _FMT_PNG: "image/png",
889 _FMT_JPEG: "image/jpeg",
890 _FMT_GIF: "image/gif",
891 _FMT_WEBP: "image/webp",
824 892 }
825 893
826 894 def __init__(
@@ -837,7 +905,7 class Image(DisplayObject):
837 905 metadata=None,
838 906 alt=None,
839 907 ):
840 """Create a PNG/JPEG/GIF image object given raw data.
908 """Create a PNG/JPEG/GIF/WEBP image object given raw data.
841 909
842 910 When this object is returned by an input cell or passed to the
843 911 display function, it will result in the image being displayed
@@ -858,7 +926,7 class Image(DisplayObject):
858 926 Images from a file are always embedded.
859 927
860 928 format : unicode
861 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
929 The format of the image data (png/jpeg/jpg/gif/webp). If a filename or URL is given
862 930 for format will be inferred from the filename extension.
863 931
864 932 embed : bool
@@ -942,6 +1010,8 class Image(DisplayObject):
942 1010 format = self._FMT_PNG
943 1011 elif ext == u'gif':
944 1012 format = self._FMT_GIF
1013 elif ext == "webp":
1014 format = self._FMT_WEBP
945 1015 else:
946 1016 format = ext.lower()
947 1017 elif isinstance(data, bytes):
@@ -949,6 +1019,12 class Image(DisplayObject):
949 1019 # only if format has not been specified.
950 1020 if data[:2] == _JPEG:
951 1021 format = self._FMT_JPEG
1022 elif data[:8] == _PNG:
1023 format = self._FMT_PNG
1024 elif data[8:12] == _WEBP:
1025 format = self._FMT_WEBP
1026 elif data[:6] == _GIF1 or data[:6] == _GIF2:
1027 format = self._FMT_GIF
952 1028
953 1029 # failed to detect format, default png
954 1030 if format is None:
@@ -1,6 +1,15
1 1 ============
2 2 8.x Series
3 3 ============
4
5 .. _version 8.29:
6
7 IPython 8.29
8 ============
9
10
11 - Add support for WEBP to ``IPython.display.Image``. :ghpull:`14526`
12
4 13 .. _version 8.28:
5 14
6 15 IPython 8.28
General Comments 0
You need to be logged in to leave comments. Login now