Show More
@@ -7,7 +7,7 b' Authors:' | |||||
7 | """ |
|
7 | """ | |
8 |
|
8 | |||
9 | #----------------------------------------------------------------------------- |
|
9 | #----------------------------------------------------------------------------- | |
10 |
# Copyright (C) 20 |
|
10 | # Copyright (C) 2013 The IPython Development Team | |
11 | # |
|
11 | # | |
12 | # Distributed under the terms of the BSD License. The full license is in |
|
12 | # Distributed under the terms of the BSD License. The full license is in | |
13 | # the file COPYING, distributed as part of this software. |
|
13 | # the file COPYING, distributed as part of this software. | |
@@ -19,6 +19,8 b' Authors:' | |||||
19 |
|
19 | |||
20 | from __future__ import print_function |
|
20 | from __future__ import print_function | |
21 |
|
21 | |||
|
22 | import os | |||
|
23 | ||||
22 | from .displaypub import ( |
|
24 | from .displaypub import ( | |
23 | publish_pretty, publish_html, |
|
25 | publish_pretty, publish_html, | |
24 | publish_latex, publish_svg, |
|
26 | publish_latex, publish_svg, | |
@@ -29,6 +31,17 b' from .displaypub import (' | |||||
29 | from IPython.utils.py3compat import string_types |
|
31 | from IPython.utils.py3compat import string_types | |
30 |
|
32 | |||
31 | #----------------------------------------------------------------------------- |
|
33 | #----------------------------------------------------------------------------- | |
|
34 | # utility functions | |||
|
35 | #----------------------------------------------------------------------------- | |||
|
36 | ||||
|
37 | def _safe_exists(path): | |||
|
38 | """check path, but don't let exceptions raise""" | |||
|
39 | try: | |||
|
40 | return os.path.exists(path) | |||
|
41 | except Exception: | |||
|
42 | return False | |||
|
43 | ||||
|
44 | #----------------------------------------------------------------------------- | |||
32 | # Main functions |
|
45 | # Main functions | |
33 | #----------------------------------------------------------------------------- |
|
46 | #----------------------------------------------------------------------------- | |
34 |
|
47 | |||
@@ -248,20 +261,26 b' class DisplayObject(object):' | |||||
248 | Parameters |
|
261 | Parameters | |
249 | ---------- |
|
262 | ---------- | |
250 | data : unicode, str or bytes |
|
263 | data : unicode, str or bytes | |
251 |
The raw data or a URL |
|
264 | The raw data or a URL or file to load the data from | |
252 | url : unicode |
|
265 | url : unicode | |
253 | A URL to download the data from. |
|
266 | A URL to download the data from. | |
254 | filename : unicode |
|
267 | filename : unicode | |
255 | Path to a local file to load the data from. |
|
268 | Path to a local file to load the data from. | |
256 | """ |
|
269 | """ | |
257 |
if data is not None and isinstance(data, string_types) |
|
270 | if data is not None and isinstance(data, string_types): | |
258 | self.url = data |
|
271 | if data.startswith('http') and url is None: | |
259 | self.filename = None |
|
272 | url = data | |
260 |
|
|
273 | filename = None | |
261 | else: |
|
274 | data = None | |
|
275 | elif _safe_exists(data) and filename is None: | |||
|
276 | url = None | |||
|
277 | filename = data | |||
|
278 | data = None | |||
|
279 | ||||
262 |
|
|
280 | self.data = data | |
263 |
|
|
281 | self.url = url | |
264 |
|
|
282 | self.filename = None if filename is None else unicode(filename) | |
|
283 | ||||
265 | self.reload() |
|
284 | self.reload() | |
266 |
|
285 | |||
267 | def reload(self): |
|
286 | def reload(self): | |
@@ -420,6 +439,9 b' class Javascript(DisplayObject):' | |||||
420 | r += lib_t2*len(self.lib) |
|
439 | r += lib_t2*len(self.lib) | |
421 | return r |
|
440 | return r | |
422 |
|
441 | |||
|
442 | # constants for identifying png/jpeg data | |||
|
443 | _PNG = b'\x89PNG\r\n\x1a\n' | |||
|
444 | _JPEG = b'\xff\xd8' | |||
423 |
|
445 | |||
424 | class Image(DisplayObject): |
|
446 | class Image(DisplayObject): | |
425 |
|
447 | |||
@@ -476,7 +498,9 b' class Image(DisplayObject):' | |||||
476 | ext = self._find_ext(url) |
|
498 | ext = self._find_ext(url) | |
477 | elif data is None: |
|
499 | elif data is None: | |
478 | raise ValueError("No image data found. Expecting filename, url, or data.") |
|
500 | raise ValueError("No image data found. Expecting filename, url, or data.") | |
479 |
elif isinstance(data, string_types) and |
|
501 | elif isinstance(data, string_types) and ( | |
|
502 | data.startswith('http') or _safe_exists(data) | |||
|
503 | ): | |||
480 | ext = self._find_ext(data) |
|
504 | ext = self._find_ext(data) | |
481 | else: |
|
505 | else: | |
482 | ext = None |
|
506 | ext = None | |
@@ -487,6 +511,11 b' class Image(DisplayObject):' | |||||
487 | format = self._FMT_JPEG |
|
511 | format = self._FMT_JPEG | |
488 | if ext == u'png': |
|
512 | if ext == u'png': | |
489 | format = self._FMT_PNG |
|
513 | format = self._FMT_PNG | |
|
514 | elif isinstance(data, bytes) and format == 'png': | |||
|
515 | # infer image type from image data header, | |||
|
516 | # only if format might not have been specified. | |||
|
517 | if data[:2] == _JPEG: | |||
|
518 | format = 'jpeg' | |||
490 |
|
519 | |||
491 | self.format = unicode(format).lower() |
|
520 | self.format = unicode(format).lower() | |
492 | self.embed = embed if embed is not None else (url is None) |
|
521 | self.embed = embed if embed is not None else (url is None) |
@@ -97,7 +97,11 b' def date_default(obj):' | |||||
97 |
|
97 | |||
98 | # constants for identifying png/jpeg data |
|
98 | # constants for identifying png/jpeg data | |
99 | PNG = b'\x89PNG\r\n\x1a\n' |
|
99 | PNG = b'\x89PNG\r\n\x1a\n' | |
|
100 | # front of PNG base64-encoded | |||
|
101 | PNG64 = b'iVBORw0KG' | |||
100 | JPEG = b'\xff\xd8' |
|
102 | JPEG = b'\xff\xd8' | |
|
103 | # front of JPEG base64-encoded | |||
|
104 | JPEG64 = b'/9' | |||
101 |
|
105 | |||
102 | def encode_images(format_dict): |
|
106 | def encode_images(format_dict): | |
103 | """b64-encodes images in a displaypub format dict |
|
107 | """b64-encodes images in a displaypub format dict | |
@@ -120,12 +124,21 b' def encode_images(format_dict):' | |||||
120 |
|
124 | |||
121 | """ |
|
125 | """ | |
122 | encoded = format_dict.copy() |
|
126 | encoded = format_dict.copy() | |
|
127 | ||||
123 | pngdata = format_dict.get('image/png') |
|
128 | pngdata = format_dict.get('image/png') | |
124 |
if isinstance(pngdata, bytes) |
|
129 | if isinstance(pngdata, bytes): | |
125 | encoded['image/png'] = encodebytes(pngdata).decode('ascii') |
|
130 | # make sure we don't double-encode | |
|
131 | if not pngdata.startswith(PNG64): | |||
|
132 | pngdata = encodebytes(pngdata) | |||
|
133 | encoded['image/png'] = pngdata.decode('ascii') | |||
|
134 | ||||
126 | jpegdata = format_dict.get('image/jpeg') |
|
135 | jpegdata = format_dict.get('image/jpeg') | |
127 |
if isinstance(jpegdata, bytes) |
|
136 | if isinstance(jpegdata, bytes): | |
128 | encoded['image/jpeg'] = encodebytes(jpegdata).decode('ascii') |
|
137 | # make sure we don't double-encode | |
|
138 | if not jpegdata.startswith(JPEG64): | |||
|
139 | jpegdata = encodebytes(jpegdata) | |||
|
140 | encoded['image/jpeg'] = jpegdata.decode('ascii') | |||
|
141 | ||||
129 | return encoded |
|
142 | return encoded | |
130 |
|
143 | |||
131 |
|
144 |
General Comments 0
You need to be logged in to leave comments.
Login now