diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 957dbbf..10ea0a6 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -95,7 +95,7 @@ def figsize(sizex, sizey): def print_figure(fig, fmt='png', quality=90): - """Convert a figure to svg, jpg (if PIL is installed) or png for inline display.""" + """Convert a figure to svg, png or jpg for inline display.""" from matplotlib import rcParams # When there's an empty figure, we shouldn't return anything, otherwise we # get big blank areas in the qt console. @@ -164,7 +164,7 @@ def mpl_runner(safe_execfile): def select_figure_format(shell, fmt, quality): - """Select figure format for inline backend, can be 'png', 'retina', or 'svg'. + """Select figure format for inline backend, can be 'png', 'retina', 'jpg', or 'svg'. Using this method ensures only one figure format is active at a time. """ @@ -175,20 +175,18 @@ def select_figure_format(shell, fmt, quality): png_formatter = shell.display_formatter.formatters['image/png'] jpg_formatter = shell.display_formatter.formatters['image/jpeg'] + [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ] + if fmt == 'png': - svg_formatter.pop(Figure, None) png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) - elif fmt in ('jpg', 'jpeg'): - svg_formatter.type_printers.pop(Figure, None) - jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality)) elif fmt in ('png2x', 'retina'): - svg_formatter.pop(Figure, None) png_formatter.for_type(Figure, retina_figure) + elif fmt in ('jpg', 'jpeg'): + jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality)) elif fmt == 'svg': - png_formatter.pop(Figure, None) svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) else: - raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt) + raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt) # set the format to be used in the backend() backend_inline._figure_format = fmt diff --git a/IPython/kernel/zmq/pylab/config.py b/IPython/kernel/zmq/pylab/config.py index f7859bc..314bfa7 100644 --- a/IPython/kernel/zmq/pylab/config.py +++ b/IPython/kernel/zmq/pylab/config.py @@ -21,11 +21,15 @@ from IPython.utils.warn import warn # Configurable for inline backend options #----------------------------------------------------------------------------- -try: - from PIL import Image - has_pil = True -except: - has_pil = False +def pil_available(): + """Test if PIL/Pillow is available""" + out = False + try: + from PIL import Image + out = True + except: + pass + return out # inherit from InlineBackendConfig for deprecation purposes class InlineBackendConfig(SingletonConfigurable): @@ -59,28 +63,28 @@ class InlineBackend(InlineBackendConfig): inline backend.""" ) - fmts = ['svg', 'png', 'retina'] - if has_pil: - # If we have PIL using jpeg as inline image format can save some bytes. - fmts.append('jpg') - - # Matplotlib's JPEG printer supports a quality option that can be tweaked. - # We expose it only if PIL is available so the user isn't confused. But it - # isn't guarded by "has_pil" test because core/pylabtools.py expects this - # field OR we need to propagate the has_pil test to that module too. - quality = Int(default_value=90, config=has_pil, - help="Quality of compression [0-100], currently for lossy JPEG only.") - - figure_format = CaselessStrEnum(fmts, default_value='png', config=True, - help="The image format for figures with the inline backend.") + figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'], + default_value='png', config=True, + help="""The image format for figures with the inline backend. + JPEG requires the PIL/Pillow library.""") def _figure_format_changed(self, name, old, new): from IPython.core.pylabtools import select_figure_format + if new in {"jpg", "jpeg"}: + if not pil_available(): + raise TraitError("Requires PIL/Pillow for JPG figures") if self.shell is None: return else: select_figure_format(self.shell, new) + + quality = Int(default_value=90, config=True, + help="Quality of compression [0-100], currently for lossy JPEG only.") + + def _quality_changed(self, name, old, new): + if new < 0 or new > 100: + raise TraitError("figure quality must be in [0-100] range.") close_figures = Bool(True, config=True, help="""Close all figures at the end of each cell.