##// 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
Wes Turner -
Show More
@@ -22,7 +22,8 from . import display_functions
22
22
23
23
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
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 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
29 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
@@ -200,6 +201,23 def display_jpeg(*objs, **kwargs):
200 _display_mimetype('image/jpeg', objs, **kwargs)
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 def display_latex(*objs, **kwargs):
221 def display_latex(*objs, **kwargs):
204 """Display the LaTeX representation of an object.
222 """Display the LaTeX representation of an object.
205
223
@@ -776,9 +794,12 class Javascript(TextDisplayObject):
776 r += _lib_t2*len(self.lib)
794 r += _lib_t2*len(self.lib)
777 return r
795 return r
778
796
779 # constants for identifying png/jpeg data
797 # constants for identifying png/jpeg/gif/webp data
780 _PNG = b'\x89PNG\r\n\x1a\n'
798 _PNG = b'\x89PNG\r\n\x1a\n'
781 _JPEG = b'\xff\xd8'
799 _JPEG = b'\xff\xd8'
800 _GIF1 = b"GIF87a"
801 _GIF2 = b"GIF89a"
802 _WEBP = b'WEBP'
782
803
783 def _pngxy(data):
804 def _pngxy(data):
784 """read the (width, height) from a PNG header"""
805 """read the (width, height) from a PNG header"""
@@ -809,6 +830,23 def _gifxy(data):
809 """read the (width, height) from a GIF header"""
830 """read the (width, height) from a GIF header"""
810 return struct.unpack('<HH', data[6:10])
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 class Image(DisplayObject):
851 class Image(DisplayObject):
814
852
@@ -816,11 +854,13 class Image(DisplayObject):
816 _FMT_JPEG = u'jpeg'
854 _FMT_JPEG = u'jpeg'
817 _FMT_PNG = u'png'
855 _FMT_PNG = u'png'
818 _FMT_GIF = u'gif'
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 _MIMETYPES = {
859 _MIMETYPES = {
821 _FMT_PNG: 'image/png',
860 _FMT_PNG: 'image/png',
822 _FMT_JPEG: 'image/jpeg',
861 _FMT_JPEG: 'image/jpeg',
823 _FMT_GIF: 'image/gif',
862 _FMT_GIF: 'image/gif',
863 _FMT_WEBP: 'image/webp',
824 }
864 }
825
865
826 def __init__(
866 def __init__(
@@ -858,7 +898,7 class Image(DisplayObject):
858 Images from a file are always embedded.
898 Images from a file are always embedded.
859
899
860 format : unicode
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 for format will be inferred from the filename extension.
902 for format will be inferred from the filename extension.
863
903
864 embed : bool
904 embed : bool
@@ -942,6 +982,8 class Image(DisplayObject):
942 format = self._FMT_PNG
982 format = self._FMT_PNG
943 elif ext == u'gif':
983 elif ext == u'gif':
944 format = self._FMT_GIF
984 format = self._FMT_GIF
985 elif ext == u'webp':
986 format = self._FMT_WEBP
945 else:
987 else:
946 format = ext.lower()
988 format = ext.lower()
947 elif isinstance(data, bytes):
989 elif isinstance(data, bytes):
@@ -949,6 +991,12 class Image(DisplayObject):
949 # only if format has not been specified.
991 # only if format has not been specified.
950 if data[:2] == _JPEG:
992 if data[:2] == _JPEG:
951 format = self._FMT_JPEG
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 # failed to detect format, default png
1001 # failed to detect format, default png
954 if format is None:
1002 if format is None:
General Comments 0
You need to be logged in to leave comments. Login now