From b4484c7a96f94fa99fa630c9bbd0a1f6872df37e 2013-03-27 19:21:06 From: Matthias Bussonnier Date: 2013-03-27 19:21:06 Subject: [PATCH] Merge pull request #3082 from minrk/image_garbage A few small patches to image handling --- diff --git a/IPython/core/display.py b/IPython/core/display.py index 22abacb..80e86b9 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -7,7 +7,7 @@ Authors: """ #----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team +# Copyright (C) 2013 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. @@ -19,6 +19,8 @@ Authors: from __future__ import print_function +import os + from .displaypub import ( publish_pretty, publish_html, publish_latex, publish_svg, @@ -29,6 +31,17 @@ from .displaypub import ( from IPython.utils.py3compat import string_types #----------------------------------------------------------------------------- +# utility functions +#----------------------------------------------------------------------------- + +def _safe_exists(path): + """check path, but don't let exceptions raise""" + try: + return os.path.exists(path) + except Exception: + return False + +#----------------------------------------------------------------------------- # Main functions #----------------------------------------------------------------------------- @@ -248,20 +261,26 @@ class DisplayObject(object): Parameters ---------- data : unicode, str or bytes - The raw data or a URL to download the data from. + The raw data or a URL or file to load the data from url : unicode A URL to download the data from. filename : unicode Path to a local file to load the data from. """ - if data is not None and isinstance(data, string_types) and data.startswith('http'): - self.url = data - self.filename = None - self.data = None - else: - self.data = data - self.url = url - self.filename = None if filename is None else unicode(filename) + if data is not None and isinstance(data, string_types): + if data.startswith('http') and url is None: + url = data + filename = None + data = None + elif _safe_exists(data) and filename is None: + url = None + filename = data + data = None + + self.data = data + self.url = url + self.filename = None if filename is None else unicode(filename) + self.reload() def reload(self): @@ -420,6 +439,9 @@ class Javascript(DisplayObject): r += lib_t2*len(self.lib) return r +# constants for identifying png/jpeg data +_PNG = b'\x89PNG\r\n\x1a\n' +_JPEG = b'\xff\xd8' class Image(DisplayObject): @@ -476,7 +498,9 @@ class Image(DisplayObject): ext = self._find_ext(url) elif data is None: raise ValueError("No image data found. Expecting filename, url, or data.") - elif isinstance(data, string_types) and data.startswith('http'): + elif isinstance(data, string_types) and ( + data.startswith('http') or _safe_exists(data) + ): ext = self._find_ext(data) else: ext = None @@ -487,6 +511,11 @@ class Image(DisplayObject): format = self._FMT_JPEG if ext == u'png': format = self._FMT_PNG + elif isinstance(data, bytes) and format == 'png': + # infer image type from image data header, + # only if format might not have been specified. + if data[:2] == _JPEG: + format = 'jpeg' self.format = unicode(format).lower() self.embed = embed if embed is not None else (url is None) diff --git a/IPython/utils/jsonutil.py b/IPython/utils/jsonutil.py index 87d99bc..0d25c3d 100644 --- a/IPython/utils/jsonutil.py +++ b/IPython/utils/jsonutil.py @@ -97,7 +97,11 @@ def date_default(obj): # constants for identifying png/jpeg data PNG = b'\x89PNG\r\n\x1a\n' +# front of PNG base64-encoded +PNG64 = b'iVBORw0KG' JPEG = b'\xff\xd8' +# front of JPEG base64-encoded +JPEG64 = b'/9' def encode_images(format_dict): """b64-encodes images in a displaypub format dict @@ -120,12 +124,21 @@ def encode_images(format_dict): """ encoded = format_dict.copy() + pngdata = format_dict.get('image/png') - if isinstance(pngdata, bytes) and pngdata[:8] == PNG: - encoded['image/png'] = encodebytes(pngdata).decode('ascii') + if isinstance(pngdata, bytes): + # make sure we don't double-encode + if not pngdata.startswith(PNG64): + pngdata = encodebytes(pngdata) + encoded['image/png'] = pngdata.decode('ascii') + jpegdata = format_dict.get('image/jpeg') - if isinstance(jpegdata, bytes) and jpegdata[:2] == JPEG: - encoded['image/jpeg'] = encodebytes(jpegdata).decode('ascii') + if isinstance(jpegdata, bytes): + # make sure we don't double-encode + if not jpegdata.startswith(JPEG64): + jpegdata = encodebytes(jpegdata) + encoded['image/jpeg'] = jpegdata.decode('ascii') + return encoded