##// END OF EJS Templates
implement GIF support without registering a new formatter...
Min RK -
Show More
@@ -23,7 +23,7 b' from IPython.utils.py3compat import cast_unicode'
23 from IPython.testing.skipdoctest import skip_doctest
23 from IPython.testing.skipdoctest import skip_doctest
24
24
25 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
25 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
26 'display_svg', 'display_png', 'display_jpeg', 'display_gif', 'display_latex', 'display_json',
26 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
28 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'JSON', 'GeoJSON', 'Javascript',
29 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
29 'Image', 'clear_output', 'set_matplotlib_formats', 'set_matplotlib_close',
@@ -86,18 +86,7 b' def publish_display_data(data, metadata=None, source=None, *, transient=None, **'
86 See the ``display_data`` message in the messaging documentation for
86 See the ``display_data`` message in the messaging documentation for
87 more details about this message type.
87 more details about this message type.
88
88
89 The following MIME types are currently implemented:
89 Keys of data and metadata can be any mime-type.
90
91 * text/plain
92 * text/html
93 * text/markdown
94 * text/latex
95 * application/json
96 * application/javascript
97 * image/png
98 * image/jpeg
99 * image/gif
100 * image/svg+xml
101
90
102 Parameters
91 Parameters
103 ----------
92 ----------
@@ -257,11 +246,11 b' def display(*objs, include=None, exclude=None, metadata=None, transient=None, di'
257 - `_repr_json_`: return a JSONable dict
246 - `_repr_json_`: return a JSONable dict
258 - `_repr_jpeg_`: return raw JPEG data
247 - `_repr_jpeg_`: return raw JPEG data
259 - `_repr_png_`: return raw PNG data
248 - `_repr_png_`: return raw PNG data
260 - `_repr_gif_`: return raw GIF data
261 - `_repr_svg_`: return raw SVG data as a string
249 - `_repr_svg_`: return raw SVG data as a string
262 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$".
250 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$".
263 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
251 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
264 from all mimetypes to data
252 from all mimetypes to data.
253 Use this for any mime-type not listed above.
265
254
266 When you are directly writing your own classes, you can adapt them for
255 When you are directly writing your own classes, you can adapt them for
267 display in IPython by following the above approach. But in practice, you
256 display in IPython by following the above approach. But in practice, you
@@ -496,22 +485,6 b' def display_jpeg(*objs, **kwargs):'
496 Metadata to be associated with the specific mimetype output.
485 Metadata to be associated with the specific mimetype output.
497 """
486 """
498 _display_mimetype('image/jpeg', objs, **kwargs)
487 _display_mimetype('image/jpeg', objs, **kwargs)
499
500 def display_gif(*objs, **kwargs):
501 """Display the GIF representation of an object.
502
503 Parameters
504 ----------
505 objs : tuple of objects
506 The Python objects to display, or if raw=True raw gif data to
507 display.
508 raw : bool
509 Are the data objects raw data or Python objects that need to be
510 formatted before display? [default: False]
511 metadata : dict (optional)
512 Metadata to be associated with the specific mimetype output.
513 """
514 _display_mimetype('image/gif', objs, **kwargs)
515
488
516
489
517 def display_latex(*objs, **kwargs):
490 def display_latex(*objs, **kwargs):
@@ -984,11 +957,12 b' def _jpegxy(data):'
984 idx += 2
957 idx += 2
985
958
986 return struct.unpack('>HH', data[iSOF+5:iSOF+9])
959 return struct.unpack('>HH', data[iSOF+5:iSOF+9])
987
960
988 def _gifxy(data):
961 def _gifxy(data):
989 """read the (width, height) from a GIF header"""
962 """read the (width, height) from a GIF header"""
990 return struct.unpack('<HH', data[6:10])
963 return struct.unpack('<HH', data[6:10])
991
964
965
992 class Image(DisplayObject):
966 class Image(DisplayObject):
993
967
994 _read_flags = 'rb'
968 _read_flags = 'rb'
@@ -996,6 +970,11 b' class Image(DisplayObject):'
996 _FMT_PNG = u'png'
970 _FMT_PNG = u'png'
997 _FMT_GIF = u'gif'
971 _FMT_GIF = u'gif'
998 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
972 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
973 _MIMETYPES = {
974 _FMT_PNG: 'image/png',
975 _FMT_JPEG: 'image/jpeg',
976 _FMT_GIF: 'image/gif',
977 }
999
978
1000 def __init__(self, data=None, url=None, filename=None, format=None,
979 def __init__(self, data=None, url=None, filename=None, format=None,
1001 embed=None, width=None, height=None, retina=False,
980 embed=None, width=None, height=None, retina=False,
@@ -1097,12 +1076,15 b' class Image(DisplayObject):'
1097 if format.lower() == 'jpg':
1076 if format.lower() == 'jpg':
1098 # jpg->jpeg
1077 # jpg->jpeg
1099 format = self._FMT_JPEG
1078 format = self._FMT_JPEG
1100
1079
1101 self.format = format.lower()
1080 self.format = format.lower()
1102 self.embed = embed if embed is not None else (url is None)
1081 self.embed = embed if embed is not None else (url is None)
1103
1082
1104 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1083 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1105 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1084 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1085 if self.embed:
1086 self._mimetype = self._MIMETYPES.get(self.format)
1087
1106 self.width = width
1088 self.width = width
1107 self.height = height
1089 self.height = height
1108 self.retina = retina
1090 self.retina = retina
@@ -1119,6 +1101,7 b' class Image(DisplayObject):'
1119 if retina:
1101 if retina:
1120 self._retina_shape()
1102 self._retina_shape()
1121
1103
1104
1122 def _retina_shape(self):
1105 def _retina_shape(self):
1123 """load pixel-doubled width and height from image data"""
1106 """load pixel-doubled width and height from image data"""
1124 if not self.embed:
1107 if not self.embed:
@@ -1158,7 +1141,21 b' class Image(DisplayObject):'
1158 klass=klass,
1141 klass=klass,
1159 )
1142 )
1160
1143
1161 def _data_and_metadata(self):
1144 def _repr_mimebundle_(self, include=None, exclude=None):
1145 """Return the image as a mimebundle
1146
1147 Any new mimetype support should be implemented here.
1148 """
1149 if self.embed:
1150 mimetype = self._mimetype
1151 data, metadata = self._data_and_metadata(always_both=True)
1152 if metadata:
1153 metadata = {mimetype: metadata}
1154 return {mimetype: data}, metadata
1155 else:
1156 return {'text/html': self._repr_html_()}
1157
1158 def _data_and_metadata(self, always_both=False):
1162 """shortcut for returning metadata with shape information, if defined"""
1159 """shortcut for returning metadata with shape information, if defined"""
1163 md = {}
1160 md = {}
1164 if self.metadata:
1161 if self.metadata:
@@ -1169,7 +1166,7 b' class Image(DisplayObject):'
1169 md['height'] = self.height
1166 md['height'] = self.height
1170 if self.unconfined:
1167 if self.unconfined:
1171 md['unconfined'] = self.unconfined
1168 md['unconfined'] = self.unconfined
1172 if md:
1169 if md or always_both:
1173 return self.data, md
1170 return self.data, md
1174 else:
1171 else:
1175 return self.data
1172 return self.data
@@ -1179,16 +1176,13 b' class Image(DisplayObject):'
1179 return self._data_and_metadata()
1176 return self._data_and_metadata()
1180
1177
1181 def _repr_jpeg_(self):
1178 def _repr_jpeg_(self):
1182 if self.embed and (self.format == self._FMT_JPEG or self.format == u'jpg'):
1179 if self.embed and self.format == self._FMT_JPEG:
1183 return self._data_and_metadata()
1184
1185 def _repr_gif_(self):
1186 if self.embed and self.format == self._FMT_GIF:
1187 return self._data_and_metadata()
1180 return self._data_and_metadata()
1188
1181
1189 def _find_ext(self, s):
1182 def _find_ext(self, s):
1190 return s.split('.')[-1].lower()
1183 return s.split('.')[-1].lower()
1191
1184
1185
1192 class Video(DisplayObject):
1186 class Video(DisplayObject):
1193
1187
1194 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1188 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
@@ -1287,15 +1281,6 b' class Video(DisplayObject):'
1287 # TODO
1281 # TODO
1288 pass
1282 pass
1289
1283
1290 def _repr_png_(self):
1291 # TODO
1292 pass
1293 def _repr_jpeg_(self):
1294 # TODO
1295 pass
1296 def _repr_gif_(self):
1297 # TODO
1298 pass
1299
1284
1300 def clear_output(wait=False):
1285 def clear_output(wait=False):
1301 """Clear the output of the current cell receiving output.
1286 """Clear the output of the current cell receiving output.
@@ -74,7 +74,6 b' class DisplayFormatter(Configurable):'
74 MarkdownFormatter,
74 MarkdownFormatter,
75 SVGFormatter,
75 SVGFormatter,
76 PNGFormatter,
76 PNGFormatter,
77 GIFFormatter,
78 PDFFormatter,
77 PDFFormatter,
79 JPEGFormatter,
78 JPEGFormatter,
80 LatexFormatter,
79 LatexFormatter,
@@ -780,24 +779,6 b' class JPEGFormatter(BaseFormatter):'
780 _return_type = (bytes, str)
779 _return_type = (bytes, str)
781
780
782
781
783 class GIFFormatter(BaseFormatter):
784 """A PNG formatter.
785
786 To define the callables that compute the GIF representation of your
787 objects, define a :meth:`_repr_gif_` method or use the :meth:`for_type`
788 or :meth:`for_type_by_name` methods to register functions that handle
789 this.
790
791 The return value of this formatter should be raw GIF data, *not*
792 base64 encoded.
793 """
794 format_type = Unicode('image/gif')
795
796 print_method = ObjectName('_repr_gif_')
797
798 _return_type = (bytes, str)
799
800
801 class LatexFormatter(BaseFormatter):
782 class LatexFormatter(BaseFormatter):
802 """A LaTeX formatter.
783 """A LaTeX formatter.
803
784
@@ -977,10 +958,7 b' class MimeBundleFormatter(BaseFormatter):'
977 method = get_real_method(obj, self.print_method)
958 method = get_real_method(obj, self.print_method)
978
959
979 if method is not None:
960 if method is not None:
980 d = {}
961 return method(include=include, exclude=exclude)
981 d['include'] = include
982 d['exclude'] = exclude
983 return method(**d)
984 return None
962 return None
985 else:
963 else:
986 return None
964 return None
@@ -992,7 +970,6 b' FormatterABC.register(HTMLFormatter)'
992 FormatterABC.register(MarkdownFormatter)
970 FormatterABC.register(MarkdownFormatter)
993 FormatterABC.register(SVGFormatter)
971 FormatterABC.register(SVGFormatter)
994 FormatterABC.register(PNGFormatter)
972 FormatterABC.register(PNGFormatter)
995 FormatterABC.register(GIFFormatter)
996 FormatterABC.register(PDFFormatter)
973 FormatterABC.register(PDFFormatter)
997 FormatterABC.register(JPEGFormatter)
974 FormatterABC.register(JPEGFormatter)
998 FormatterABC.register(LatexFormatter)
975 FormatterABC.register(LatexFormatter)
@@ -1007,19 +984,6 b' def format_display_data(obj, include=None, exclude=None):'
1007
984
1008 By default all format types will be computed.
985 By default all format types will be computed.
1009
986
1010 The following MIME types are currently implemented:
1011
1012 * text/plain
1013 * text/html
1014 * text/markdown
1015 * text/latex
1016 * application/json
1017 * application/javascript
1018 * application/pdf
1019 * image/png
1020 * image/jpeg
1021 * image/svg+xml
1022
1023 Parameters
987 Parameters
1024 ----------
988 ----------
1025 obj : object
989 obj : object
@@ -32,6 +32,15 b' def test_image_size():'
32 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
32 nt.assert_equal(u'<img src="%s" class="unconfined"/>' % (thisurl), img._repr_html_())
33
33
34
34
35 def test_image_mimes():
36 fmt = get_ipython().display_formatter.format
37 for format in display.Image._ACCEPTABLE_EMBEDDINGS:
38 mime = display.Image._MIMETYPES[format]
39 img = display.Image(b'garbage', format=format)
40 data, metadata = fmt(img)
41 nt.assert_equal(sorted(data), sorted([mime, 'text/plain']))
42
43
35 def test_geojson():
44 def test_geojson():
36
45
37 gj = display.GeoJSON(data={
46 gj = display.GeoJSON(data={
@@ -361,3 +370,4 b' def test_display_handle():'
361 },
370 },
362 'update': True,
371 'update': True,
363 })
372 })
373
@@ -30,7 +30,10 b' class RichOutput(object):'
30 return data, self.metadata[mime]
30 return data, self.metadata[mime]
31 else:
31 else:
32 return data
32 return data
33
33
34 def _repr_mimebundle_(self, include=None, exclude=None):
35 return self.data, self.metadata
36
34 def _repr_html_(self):
37 def _repr_html_(self):
35 return self._repr_mime_("text/html")
38 return self._repr_mime_("text/html")
36
39
@@ -48,9 +51,6 b' class RichOutput(object):'
48
51
49 def _repr_jpeg_(self):
52 def _repr_jpeg_(self):
50 return self._repr_mime_("image/jpeg")
53 return self._repr_mime_("image/jpeg")
51
52 def _repr_gif_(self):
53 return self._repr_mime_("image/gif")
54
54
55 def _repr_svg_(self):
55 def _repr_svg_(self):
56 return self._repr_mime_("image/svg+xml")
56 return self._repr_mime_("image/svg+xml")
General Comments 0
You need to be logged in to leave comments. Login now