##// END OF EJS Templates
Add more image handler backends...
Takafumi Arakaki -
Show More
@@ -21,21 +21,18 b' import bdb'
21 import signal
21 import signal
22 import sys
22 import sys
23 import time
23 import time
24 import tempfile
25 import subprocess
24 from io import BytesIO
26 from io import BytesIO
25 import base64
27 import base64
26
28
27 from Queue import Empty
29 from Queue import Empty
28
30
29 try:
30 import PIL
31 except ImportError:
32 PIL = None
33
34 from IPython.core.alias import AliasManager, AliasError
31 from IPython.core.alias import AliasManager, AliasError
35 from IPython.core import page
32 from IPython.core import page
36 from IPython.utils.warn import warn, error, fatal
33 from IPython.utils.warn import warn, error, fatal
37 from IPython.utils import io
34 from IPython.utils import io
38 from IPython.utils.traitlets import List
35 from IPython.utils.traitlets import List, Enum, Any
39
36
40 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
37 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
41 from IPython.frontend.terminal.console.completer import ZMQCompleter
38 from IPython.frontend.terminal.console.completer import ZMQCompleter
@@ -45,14 +42,50 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
45 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
42 """A subclass of TerminalInteractiveShell that uses the 0MQ kernel"""
46 _executing = False
43 _executing = False
47
44
48 image_handler = List([], allow_none=False, config=True, help=
45 image_handler = Enum(('PIL', 'stream', 'tempfile', 'callable'),
46 config=True, help=
49 """
47 """
50 Handlers for image type output. This is useful, for example,
48 Handler for image type output. This is useful, for example,
51 when connecting to the kernel in which pylab inline backend is
49 when connecting to the kernel in which pylab inline backend is
52 activated. Handlers in the list is tried one-by-one and first
50 activated. There are four handlers defined. 'PIL': Use
53 available handler is used. Currently IPython only supports
51 Python Imaging Library to popup image; 'stream': Use an
54 handler `PIL`. IPython shell pops up window to show image
52 external program to show the image. Image will be fed into
55 when the kernel sends image (e.g., when you plot a graph).
53 the STDIN of the program. You will need to configure
54 `stream_image_handler`; 'tempfile': Use an external program to
55 show the image. Image will be saved in a temporally file and
56 the program is called with the temporally file. You will need
57 to configure `tempfile_image_handler`; 'callable': You can set
58 any Python callable which is called with the image data. You
59 will need to configure `callable_image_handler`.
60 """
61 )
62
63 stream_image_handler = List(config=True, help=
64 """
65 Command to invoke an image viewer program when you are using
66 'stream' image handler. This option is a list of string where
67 the first element is the command itself and reminders are the
68 options for the command. Raw image data is given as STDIN to
69 the program.
70 """
71 )
72
73 tempfile_image_handler = List(config=True, help=
74 """
75 Command to invoke an image viewer program when you are using
76 'tempfile' image handler. This option is a list of string
77 where the first element is the command itself and reminders
78 are the options for the command. You can use {file} in the
79 string to represent the location of the generated image file.
80 """
81 )
82
83 callable_image_handler = Any(config=True, help=
84 """
85 Callable object called via 'callable' image handler with one
86 argument, `data`, which is `msg["content"]["data"]` where
87 `msg` is the message from iopub channel. For exmaple, you can
88 find base64 encoded PNG data as `data['image/png']`.
56 """
89 """
57 )
90 )
58
91
@@ -195,16 +228,44 b' class ZMQTerminalInteractiveShell(TerminalInteractiveShell):'
195 self.handle_rich_data(sub_msg["content"]["data"])
228 self.handle_rich_data(sub_msg["content"]["data"])
196
229
197 def handle_rich_data(self, data):
230 def handle_rich_data(self, data):
198 if 'image/png' in data:
231 for mime in ['image/png', 'image/jpeg', 'image/svg+xml']:
199 self.handle_image(data['image/png'])
232 if mime in data:
200 elif 'image/jpeg' in data:
233 self.handle_image(data, mime)
201 self.handle_image(data['image/jpeg'])
234
202
235 def handle_image(self, data, mime):
203 def handle_image(self, string):
236 handler = getattr(
204 if 'PIL' in self.image_handler and PIL:
237 self, 'handle_image_{0}'.format(self.image_handler), None)
205 data = base64.decodestring(string)
238 if handler:
206 img = PIL.Image.open(BytesIO(data))
239 handler(data, mime)
207 img.show()
240
241 def handle_image_PIL(self, data, mime):
242 if mime not in ('image/png', 'image/jpeg'):
243 return
244 import PIL
245 raw = base64.decodestring(data[mime])
246 img = PIL.Image.open(BytesIO(raw))
247 img.show()
248
249 def handle_image_stream(self, data, mime):
250 raw = base64.decodestring(data[mime])
251 proc = subprocess.Popen(
252 self.stream_image_handler, stdin=subprocess.PIPE,
253 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
254 proc.communicate(raw)
255
256 def handle_image_tempfile(self, data, mime):
257 raw = base64.decodestring(data[mime])
258 with tempfile.NamedTemporaryFile() as f:
259 f.write(raw)
260 f.flush()
261 fmt = dict(file=f.name)
262 args = [s.format(**fmt) for s in self.tempfile_image_handler]
263 subprocess.Popen(
264 args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
265 ).communicate()
266
267 def handle_image_callable(self, data, mime):
268 self.callable_image_handler(data)
208
269
209 def handle_stdin_request(self, timeout=0.1):
270 def handle_stdin_request(self, timeout=0.1):
210 """ Method to capture raw_input
271 """ Method to capture raw_input
General Comments 0
You need to be logged in to leave comments. Login now