##// END OF EJS Templates
Merge pull request #1643 from Carreau/jpegQtconsole...
Bussonnier Matthias -
r6641:f387e4a2 merge
parent child Browse files
Show More
@@ -1,3 +1,11 b''
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2010, IPython Development Team.
3 #
4 # Distributed under the terms of the Modified BSD License.
5 #
6 # The full license is in the file COPYING.txt, distributed with this software.
7 #-----------------------------------------------------------------------------
8
1 # Standard libary imports.
9 # Standard libary imports.
2 from base64 import decodestring
10 from base64 import decodestring
3 import os
11 import os
@@ -7,6 +15,7 b' import re'
7 from IPython.external.qt import QtCore, QtGui
15 from IPython.external.qt import QtCore, QtGui
8
16
9 # Local imports
17 # Local imports
18 from IPython.utils.traitlets import Bool
10 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
19 from IPython.frontend.qt.svg import save_svg, svg_to_clipboard, svg_to_image
11 from ipython_widget import IPythonWidget
20 from ipython_widget import IPythonWidget
12
21
@@ -19,7 +28,7 b' class RichIPythonWidget(IPythonWidget):'
19
28
20 # RichIPythonWidget protected class variables.
29 # RichIPythonWidget protected class variables.
21 _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload'
30 _payload_source_plot = 'IPython.zmq.pylab.backend_payload.add_plot_payload'
22
31 _jpg_supported = Bool(False)
23 #---------------------------------------------------------------------------
32 #---------------------------------------------------------------------------
24 # 'object' interface
33 # 'object' interface
25 #---------------------------------------------------------------------------
34 #---------------------------------------------------------------------------
@@ -36,6 +45,13 b' class RichIPythonWidget(IPythonWidget):'
36 # Dictionary for resolving document resource names to SVG data.
45 # Dictionary for resolving document resource names to SVG data.
37 self._name_to_svg_map = {}
46 self._name_to_svg_map = {}
38
47
48 # Do we support jpg ?
49 # it seems that sometime jpg support is a plugin of QT, so try to assume
50 # it is not always supported.
51 _supported_format = map(str, QtGui.QImageReader.supportedImageFormats())
52 self._jpg_supported = 'jpeg' in _supported_format
53
54
39 #---------------------------------------------------------------------------
55 #---------------------------------------------------------------------------
40 # 'ConsoleWidget' protected interface
56 # 'ConsoleWidget' protected interface
41 #---------------------------------------------------------------------------
57 #---------------------------------------------------------------------------
@@ -65,6 +81,15 b' class RichIPythonWidget(IPythonWidget):'
65 #---------------------------------------------------------------------------
81 #---------------------------------------------------------------------------
66 # 'BaseFrontendMixin' abstract interface
82 # 'BaseFrontendMixin' abstract interface
67 #---------------------------------------------------------------------------
83 #---------------------------------------------------------------------------
84 def _pre_image_append(self, msg, prompt_number):
85 """ Append the Out[] prompt and make the output nicer
86
87 Shared code for some the following if statement
88 """
89 self.log.debug("pyout: %s", msg.get('content', ''))
90 self._append_plain_text(self.output_sep, True)
91 self._append_html(self._make_out_prompt(prompt_number), True)
92 self._append_plain_text('\n', True)
68
93
69 def _handle_pyout(self, msg):
94 def _handle_pyout(self, msg):
70 """ Overridden to handle rich data types, like SVG.
95 """ Overridden to handle rich data types, like SVG.
@@ -74,19 +99,17 b' class RichIPythonWidget(IPythonWidget):'
74 prompt_number = content['execution_count']
99 prompt_number = content['execution_count']
75 data = content['data']
100 data = content['data']
76 if data.has_key('image/svg+xml'):
101 if data.has_key('image/svg+xml'):
77 self.log.debug("pyout: %s", msg.get('content', ''))
102 self._pre_image_append(msg, prompt_number)
78 self._append_plain_text(self.output_sep, True)
79 self._append_html(self._make_out_prompt(prompt_number), True)
80 self._append_svg(data['image/svg+xml'], True)
103 self._append_svg(data['image/svg+xml'], True)
81 self._append_html(self.output_sep2, True)
104 self._append_html(self.output_sep2, True)
82 elif data.has_key('image/png'):
105 elif data.has_key('image/png'):
83 self.log.debug("pyout: %s", msg.get('content', ''))
106 self._pre_image_append(msg, prompt_number)
84 self._append_plain_text(self.output_sep, True)
85 self._append_html(self._make_out_prompt(prompt_number), True)
86 # This helps the output to look nice.
87 self._append_plain_text('\n', True)
88 self._append_png(decodestring(data['image/png'].encode('ascii')), True)
107 self._append_png(decodestring(data['image/png'].encode('ascii')), True)
89 self._append_html(self.output_sep2, True)
108 self._append_html(self.output_sep2, True)
109 elif data.has_key('image/jpeg') and self._jpg_supported:
110 self._pre_image_append(msg, prompt_number)
111 self._append_jpg(decodestring(data['image/jpeg'].encode('ascii')), True)
112 self._append_html(self.output_sep2, True)
90 else:
113 else:
91 # Default back to the plain text representation.
114 # Default back to the plain text representation.
92 return super(RichIPythonWidget, self)._handle_pyout(msg)
115 return super(RichIPythonWidget, self)._handle_pyout(msg)
@@ -110,6 +133,10 b' class RichIPythonWidget(IPythonWidget):'
110 # in a JSON structure so we decode it.
133 # in a JSON structure so we decode it.
111 png = decodestring(data['image/png'].encode('ascii'))
134 png = decodestring(data['image/png'].encode('ascii'))
112 self._append_png(png, True)
135 self._append_png(png, True)
136 elif data.has_key('image/jpeg') and self._jpg_supported:
137 self.log.debug("display: %s", msg.get('content', ''))
138 jpg = decodestring(data['image/jpeg'].encode('ascii'))
139 self._append_jpg(jpg, True)
113 else:
140 else:
114 # Default back to the plain text representation.
141 # Default back to the plain text representation.
115 return super(RichIPythonWidget, self)._handle_display_data(msg)
142 return super(RichIPythonWidget, self)._handle_display_data(msg)
@@ -118,6 +145,10 b' class RichIPythonWidget(IPythonWidget):'
118 # 'RichIPythonWidget' protected interface
145 # 'RichIPythonWidget' protected interface
119 #---------------------------------------------------------------------------
146 #---------------------------------------------------------------------------
120
147
148 def _append_jpg(self, jpg, before_prompt=False):
149 """ Append raw JPG data to the widget."""
150 self._append_custom(self._insert_jpg, jpg, before_prompt)
151
121 def _append_png(self, png, before_prompt=False):
152 def _append_png(self, png, before_prompt=False):
122 """ Append raw PNG data to the widget.
153 """ Append raw PNG data to the widget.
123 """
154 """
@@ -168,10 +199,10 b' class RichIPythonWidget(IPythonWidget):'
168 written (e.g., for linked images). If None, all images are to be
199 written (e.g., for linked images). If None, all images are to be
169 included inline.
200 included inline.
170
201
171 format : "png"|"svg", optional [default "png"]
202 format : "png"|"svg"|"jpg", optional [default "png"]
172 Format for returned or referenced images.
203 Format for returned or referenced images.
173 """
204 """
174 if format == "png":
205 if format in ("png","jpg"):
175 try:
206 try:
176 image = self._get_image(match.group("name"))
207 image = self._get_image(match.group("name"))
177 except KeyError:
208 except KeyError:
@@ -181,20 +212,20 b' class RichIPythonWidget(IPythonWidget):'
181 if not os.path.exists(path):
212 if not os.path.exists(path):
182 os.mkdir(path)
213 os.mkdir(path)
183 relpath = os.path.basename(path)
214 relpath = os.path.basename(path)
184 if image.save("%s/qt_img%s.png" % (path,match.group("name")),
215 if image.save("%s/qt_img%s.%s" % (path, match.group("name"), format),
185 "PNG"):
216 "PNG"):
186 return '<img src="%s/qt_img%s.png">' % (relpath,
217 return '<img src="%s/qt_img%s.%s">' % (relpath,
187 match.group("name"))
218 match.group("name"),format)
188 else:
219 else:
189 return "<b>Couldn't save image!</b>"
220 return "<b>Couldn't save image!</b>"
190 else:
221 else:
191 ba = QtCore.QByteArray()
222 ba = QtCore.QByteArray()
192 buffer_ = QtCore.QBuffer(ba)
223 buffer_ = QtCore.QBuffer(ba)
193 buffer_.open(QtCore.QIODevice.WriteOnly)
224 buffer_.open(QtCore.QIODevice.WriteOnly)
194 image.save(buffer_, "PNG")
225 image.save(buffer_, format.upper())
195 buffer_.close()
226 buffer_.close()
196 return '<img src="data:image/png;base64,\n%s\n" />' % (
227 return '<img src="data:image/%s;base64,\n%s\n" />' % (
197 re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
228 format,re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
198
229
199 elif format == "svg":
230 elif format == "svg":
200 try:
231 try:
@@ -215,14 +246,22 b' class RichIPythonWidget(IPythonWidget):'
215 else:
246 else:
216 return '<b>Unrecognized image format</b>'
247 return '<b>Unrecognized image format</b>'
217
248
249 def _insert_jpg(self, cursor, jpg):
250 """ Insert raw PNG data into the widget."""
251 self._insert_img(cursor, jpg, 'jpg')
252
218 def _insert_png(self, cursor, png):
253 def _insert_png(self, cursor, png):
219 """ Insert raw PNG data into the widget.
254 """ Insert raw PNG data into the widget.
220 """
255 """
256 self._insert_img(cursor, png, 'png')
257
258 def _insert_img(self, cursor, img, fmt):
259 """ insert a raw image, jpg or png """
221 try:
260 try:
222 image = QtGui.QImage()
261 image = QtGui.QImage()
223 image.loadFromData(png, 'PNG')
262 image.loadFromData(img, fmt.upper())
224 except ValueError:
263 except ValueError:
225 self._insert_plain_text(cursor, 'Received invalid PNG data.')
264 self._insert_plain_text(cursor, 'Received invalid %s data.'%fmt)
226 else:
265 else:
227 format = self._add_image(image)
266 format = self._add_image(image)
228 cursor.insertBlock()
267 cursor.insertBlock()
General Comments 0
You need to be logged in to leave comments. Login now