Show More
@@ -24,7 +24,7 b' import struct' | |||||
24 |
|
24 | |||
25 | from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, |
|
25 | from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, | |
26 | unicode_type) |
|
26 | unicode_type) | |
27 |
|
27 | from IPython.testing.skipdoctest import skip_doctest | ||
28 | from .displaypub import publish_display_data |
|
28 | from .displaypub import publish_display_data | |
29 |
|
29 | |||
30 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
@@ -271,6 +271,24 b' def display_javascript(*objs, **kwargs):' | |||||
271 | """ |
|
271 | """ | |
272 | _display_mimetype('application/javascript', objs, **kwargs) |
|
272 | _display_mimetype('application/javascript', objs, **kwargs) | |
273 |
|
273 | |||
|
274 | ||||
|
275 | def display_pdf(*objs, **kwargs): | |||
|
276 | """Display the PDF representation of an object. | |||
|
277 | ||||
|
278 | Parameters | |||
|
279 | ---------- | |||
|
280 | objs : tuple of objects | |||
|
281 | The Python objects to display, or if raw=True raw javascript data to | |||
|
282 | display. | |||
|
283 | raw : bool | |||
|
284 | Are the data objects raw data or Python objects that need to be | |||
|
285 | formatted before display? [default: False] | |||
|
286 | metadata : dict (optional) | |||
|
287 | Metadata to be associated with the specific mimetype output. | |||
|
288 | """ | |||
|
289 | _display_mimetype('application/pdf', objs, **kwargs) | |||
|
290 | ||||
|
291 | ||||
274 | #----------------------------------------------------------------------------- |
|
292 | #----------------------------------------------------------------------------- | |
275 | # Smart classes |
|
293 | # Smart classes | |
276 | #----------------------------------------------------------------------------- |
|
294 | #----------------------------------------------------------------------------- | |
@@ -699,3 +717,56 b' def clear_output(wait=False):' | |||||
699 | io.stdout.flush() |
|
717 | io.stdout.flush() | |
700 | print('\033[2K\r', file=io.stderr, end='') |
|
718 | print('\033[2K\r', file=io.stderr, end='') | |
701 | io.stderr.flush() |
|
719 | io.stderr.flush() | |
|
720 | ||||
|
721 | ||||
|
722 | @skip_doctest | |||
|
723 | def set_matplotlib_formats(*formats, **kwargs): | |||
|
724 | """Select figure formats for the inline backend. Optionally pass quality for JPEG. | |||
|
725 | ||||
|
726 | For example, this enables PNG and JPEG output with a JPEG quality of 90%:: | |||
|
727 | ||||
|
728 | In [1]: set_matplotlib_formats('png', 'jpeg', quality=90) | |||
|
729 | ||||
|
730 | To set this in your config files use the following:: | |||
|
731 | ||||
|
732 | c.InlineBackend.figure_formats = {'pdf', 'png', 'svg'} | |||
|
733 | c.InlineBackend.quality = 90 | |||
|
734 | ||||
|
735 | Parameters | |||
|
736 | ---------- | |||
|
737 | *formats : list, tuple | |||
|
738 | One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'. | |||
|
739 | quality : int | |||
|
740 | A percentage for the quality of JPEG figures. Defaults to 90. | |||
|
741 | """ | |||
|
742 | from IPython.core.interactiveshell import InteractiveShell | |||
|
743 | from IPython.core.pylabtools import select_figure_formats | |||
|
744 | shell = InteractiveShell.instance() | |||
|
745 | select_figure_formats(shell, formats, quality=90) | |||
|
746 | ||||
|
747 | @skip_doctest | |||
|
748 | def set_matplotlib_close(close): | |||
|
749 | """Set whether the inline backend closes all figures automatically or not. | |||
|
750 | ||||
|
751 | By default, the inline backend used in the IPython Notebook will close all | |||
|
752 | matplotlib figures automatically after each cell is run. This means that | |||
|
753 | plots in different cells won't interfere. Sometimes, you may want to make | |||
|
754 | a plot in one cell and then refine it in later cells. This can be accomplished | |||
|
755 | by:: | |||
|
756 | ||||
|
757 | In [1]: set_matplotlib_close(False) | |||
|
758 | ||||
|
759 | To set this in your config files use the following:: | |||
|
760 | ||||
|
761 | c.InlineBackend.close_figures = False | |||
|
762 | ||||
|
763 | Parameters | |||
|
764 | ---------- | |||
|
765 | close : bool | |||
|
766 | Should all matplotlib figures be automatically closed after each cell is | |||
|
767 | run? | |||
|
768 | """ | |||
|
769 | from IPython.kernel.zmq.pylab.backend_inline import InlineBackend | |||
|
770 | ilbe = InlineBackend.instance() | |||
|
771 | ilbe.close_figures = close | |||
|
772 |
@@ -93,6 +93,7 b' class DisplayFormatter(Configurable):' | |||||
93 | HTMLFormatter, |
|
93 | HTMLFormatter, | |
94 | SVGFormatter, |
|
94 | SVGFormatter, | |
95 | PNGFormatter, |
|
95 | PNGFormatter, | |
|
96 | PDFFormatter, | |||
96 | JPEGFormatter, |
|
97 | JPEGFormatter, | |
97 | LatexFormatter, |
|
98 | LatexFormatter, | |
98 | JSONFormatter, |
|
99 | JSONFormatter, | |
@@ -116,6 +117,7 b' class DisplayFormatter(Configurable):' | |||||
116 | * text/latex |
|
117 | * text/latex | |
117 | * application/json |
|
118 | * application/json | |
118 | * application/javascript |
|
119 | * application/javascript | |
|
120 | * application/pdf | |||
119 | * image/png |
|
121 | * image/png | |
120 | * image/jpeg |
|
122 | * image/jpeg | |
121 | * image/svg+xml |
|
123 | * image/svg+xml | |
@@ -766,11 +768,29 b' class JavascriptFormatter(BaseFormatter):' | |||||
766 |
|
768 | |||
767 | print_method = ObjectName('_repr_javascript_') |
|
769 | print_method = ObjectName('_repr_javascript_') | |
768 |
|
770 | |||
|
771 | ||||
|
772 | class PDFFormatter(BaseFormatter): | |||
|
773 | """A PDF formatter. | |||
|
774 | ||||
|
775 | To defined the callables that compute to PDF representation of your | |||
|
776 | objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type` | |||
|
777 | or :meth:`for_type_by_name` methods to register functions that handle | |||
|
778 | this. | |||
|
779 | ||||
|
780 | The return value of this formatter should be raw PDF data, *not* | |||
|
781 | base64 encoded. | |||
|
782 | """ | |||
|
783 | format_type = Unicode('application/pdf') | |||
|
784 | ||||
|
785 | print_method = ObjectName('_repr_pdf_') | |||
|
786 | ||||
|
787 | ||||
769 | FormatterABC.register(BaseFormatter) |
|
788 | FormatterABC.register(BaseFormatter) | |
770 | FormatterABC.register(PlainTextFormatter) |
|
789 | FormatterABC.register(PlainTextFormatter) | |
771 | FormatterABC.register(HTMLFormatter) |
|
790 | FormatterABC.register(HTMLFormatter) | |
772 | FormatterABC.register(SVGFormatter) |
|
791 | FormatterABC.register(SVGFormatter) | |
773 | FormatterABC.register(PNGFormatter) |
|
792 | FormatterABC.register(PNGFormatter) | |
|
793 | FormatterABC.register(PDFFormatter) | |||
774 | FormatterABC.register(JPEGFormatter) |
|
794 | FormatterABC.register(JPEGFormatter) | |
775 | FormatterABC.register(LatexFormatter) |
|
795 | FormatterABC.register(LatexFormatter) | |
776 | FormatterABC.register(JSONFormatter) |
|
796 | FormatterABC.register(JSONFormatter) | |
@@ -789,6 +809,7 b' def format_display_data(obj, include=None, exclude=None):' | |||||
789 | * text/latex |
|
809 | * text/latex | |
790 | * application/json |
|
810 | * application/json | |
791 | * application/javascript |
|
811 | * application/javascript | |
|
812 | * application/pdf | |||
792 | * image/png |
|
813 | * image/png | |
793 | * image/jpeg |
|
814 | * image/jpeg | |
794 | * image/svg+xml |
|
815 | * image/svg+xml |
@@ -47,28 +47,32 b' class PylabMagics(Magics):' | |||||
47 | """Set up matplotlib to work interactively. |
|
47 | """Set up matplotlib to work interactively. | |
48 |
|
48 | |||
49 | This function lets you activate matplotlib interactive support |
|
49 | This function lets you activate matplotlib interactive support | |
50 | at any point during an IPython session. |
|
50 | at any point during an IPython session. It does not import anything | |
51 |
|
|
51 | into the interactive namespace. | |
52 |
|
52 | |||
53 |
If you are using the inline matplotlib backend |
|
53 | If you are using the inline matplotlib backend in the IPython Notebook | |
54 | you can adjust its behavior via the %config magic:: |
|
54 | you can set which figure formats are enabled using the following:: | |
55 |
|
55 | |||
56 | # enable SVG figures, necessary for SVG+XHTML export in the qtconsole |
|
56 | In [1]: from IPython.display import set_matplotlib_formats | |
57 | In [1]: %config InlineBackend.figure_format = 'svg' |
|
|||
58 |
|
57 | |||
59 | # change the behavior of closing all figures at the end of each |
|
58 | In [2]: set_matplotlib_formats('pdf', 'svg') | |
60 | # execution (cell), or allowing reuse of active figures across |
|
59 | ||
61 | # cells: |
|
60 | See the docstring of `IPython.display.set_matplotlib_formats` and | |
62 | In [2]: %config InlineBackend.close_figures = False |
|
61 | `IPython.display.set_matplotlib_close` for more information on | |
|
62 | changing the behavior of the inline backend. | |||
63 |
|
63 | |||
64 | Examples |
|
64 | Examples | |
65 | -------- |
|
65 | -------- | |
66 | In this case, where the MPL default is TkAgg:: |
|
66 | To enable the inline backend for usage with the IPython Notebook:: | |
|
67 | ||||
|
68 | In [1]: %matplotlib inline | |||
|
69 | ||||
|
70 | In this case, where the matplotlib default is TkAgg:: | |||
67 |
|
71 | |||
68 | In [2]: %matplotlib |
|
72 | In [2]: %matplotlib | |
69 | Using matplotlib backend: TkAgg |
|
73 | Using matplotlib backend: TkAgg | |
70 |
|
74 | |||
71 | But you can explicitly request a different backend:: |
|
75 | But you can explicitly request a different GUI backend:: | |
72 |
|
76 | |||
73 | In [3]: %matplotlib qt |
|
77 | In [3]: %matplotlib qt | |
74 | """ |
|
78 | """ |
@@ -25,6 +25,7 b' from io import BytesIO' | |||||
25 |
|
25 | |||
26 | from IPython.core.display import _pngxy |
|
26 | from IPython.core.display import _pngxy | |
27 | from IPython.utils.decorators import flag_calls |
|
27 | from IPython.utils.decorators import flag_calls | |
|
28 | from IPython.utils import py3compat | |||
28 |
|
29 | |||
29 | # If user specifies a GUI, that dictates the backend, otherwise we read the |
|
30 | # If user specifies a GUI, that dictates the backend, otherwise we read the | |
30 | # user's mpl default from the mpl rc structure |
|
31 | # user's mpl default from the mpl rc structure | |
@@ -165,10 +166,17 b' def mpl_runner(safe_execfile):' | |||||
165 | return mpl_execfile |
|
166 | return mpl_execfile | |
166 |
|
167 | |||
167 |
|
168 | |||
168 | def select_figure_format(shell, fmt, quality=90): |
|
169 | def select_figure_formats(shell, formats, quality=90): | |
169 |
"""Select figure format for inline backend |
|
170 | """Select figure formats for the inline backend. | |
170 |
|
171 | |||
171 | Using this method ensures only one figure format is active at a time. |
|
172 | Parameters | |
|
173 | ========== | |||
|
174 | shell : InteractiveShell | |||
|
175 | The main IPython instance. | |||
|
176 | formats : list | |||
|
177 | One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'. | |||
|
178 | quality : int | |||
|
179 | A percentage for the quality of JPEG figures. | |||
172 | """ |
|
180 | """ | |
173 | from matplotlib.figure import Figure |
|
181 | from matplotlib.figure import Figure | |
174 | from IPython.kernel.zmq.pylab import backend_inline |
|
182 | from IPython.kernel.zmq.pylab import backend_inline | |
@@ -176,9 +184,14 b' def select_figure_format(shell, fmt, quality=90):' | |||||
176 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
184 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] | |
177 | png_formatter = shell.display_formatter.formatters['image/png'] |
|
185 | png_formatter = shell.display_formatter.formatters['image/png'] | |
178 | jpg_formatter = shell.display_formatter.formatters['image/jpeg'] |
|
186 | jpg_formatter = shell.display_formatter.formatters['image/jpeg'] | |
|
187 | pdf_formatter = shell.display_formatter.formatters['application/pdf'] | |||
|
188 | ||||
|
189 | if isinstance(formats, py3compat.string_types): | |||
|
190 | formats = {formats} | |||
179 |
|
191 | |||
180 | [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ] |
|
192 | [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ] | |
181 |
|
193 | |||
|
194 | for fmt in formats: | |||
182 | if fmt == 'png': |
|
195 | if fmt == 'png': | |
183 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) |
|
196 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) | |
184 | elif fmt in ('png2x', 'retina'): |
|
197 | elif fmt in ('png2x', 'retina'): | |
@@ -187,11 +200,10 b' def select_figure_format(shell, fmt, quality=90):' | |||||
187 | jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality)) |
|
200 | jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality)) | |
188 | elif fmt == 'svg': |
|
201 | elif fmt == 'svg': | |
189 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) |
|
202 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) | |
|
203 | elif fmt == 'pdf': | |||
|
204 | pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf')) | |||
190 | else: |
|
205 | else: | |
191 | raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt) |
|
206 | raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', 'pdf' not %r" % fmt) | |
192 |
|
||||
193 | # set the format to be used in the backend() |
|
|||
194 | backend_inline._figure_format = fmt |
|
|||
195 |
|
207 | |||
196 | #----------------------------------------------------------------------------- |
|
208 | #----------------------------------------------------------------------------- | |
197 | # Code for initializing matplotlib and importing pylab |
|
209 | # Code for initializing matplotlib and importing pylab | |
@@ -342,5 +354,5 b' def configure_inline_support(shell, backend):' | |||||
342 | del shell._saved_rcParams |
|
354 | del shell._saved_rcParams | |
343 |
|
355 | |||
344 | # Setup the default figure format |
|
356 | # Setup the default figure format | |
345 | select_figure_format(shell, cfg.figure_format, cfg.quality) |
|
357 | select_figure_formats(shell, cfg.figure_formats, cfg.quality) | |
346 |
|
358 |
@@ -8,7 +8,9 b' except:' | |||||
8 | numpy = None |
|
8 | numpy = None | |
9 | import nose.tools as nt |
|
9 | import nose.tools as nt | |
10 |
|
10 | |||
11 | from IPython.core.formatters import PlainTextFormatter, HTMLFormatter, _mod_name_key |
|
11 | from IPython.core.formatters import ( | |
|
12 | PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key | |||
|
13 | ) | |||
12 | from IPython.utils.io import capture_output |
|
14 | from IPython.utils.io import capture_output | |
13 |
|
15 | |||
14 | class A(object): |
|
16 | class A(object): | |
@@ -279,4 +281,11 b' def test_warn_error_pretty_method():' | |||||
279 | nt.assert_in("text/plain", captured.stderr) |
|
281 | nt.assert_in("text/plain", captured.stderr) | |
280 | nt.assert_in("argument", captured.stderr) |
|
282 | nt.assert_in("argument", captured.stderr) | |
281 |
|
283 | |||
|
284 | class MakePDF(object): | |||
|
285 | def _repr_pdf_(self): | |||
|
286 | return 'PDF' | |||
282 |
|
287 | |||
|
288 | def test_pdf_formatter(): | |||
|
289 | pdf = MakePDF() | |||
|
290 | f = PDFFormatter() | |||
|
291 | nt.assert_equal(f(pdf), 'PDF') |
@@ -252,6 +252,7 b' var IPython = (function (IPython) {' | |||||
252 | 'image/svg+xml', |
|
252 | 'image/svg+xml', | |
253 | 'image/png', |
|
253 | 'image/png', | |
254 | 'image/jpeg', |
|
254 | 'image/jpeg', | |
|
255 | 'application/pdf', | |||
255 | 'text/plain' |
|
256 | 'text/plain' | |
256 | ]; |
|
257 | ]; | |
257 |
|
258 | |||
@@ -620,6 +621,17 b' var IPython = (function (IPython) {' | |||||
620 | }; |
|
621 | }; | |
621 |
|
622 | |||
622 |
|
623 | |||
|
624 | OutputArea.prototype.append_pdf = function (pdf, md, element) { | |||
|
625 | var type = 'application/pdf'; | |||
|
626 | var toinsert = this.create_output_subarea(md, "output_pdf", type); | |||
|
627 | var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf); | |||
|
628 | a.attr('target', '_blank'); | |||
|
629 | a.text('View PDF') | |||
|
630 | toinsert.append(a); | |||
|
631 | element.append(toinsert); | |||
|
632 | return toinsert; | |||
|
633 | } | |||
|
634 | ||||
623 | OutputArea.prototype.append_latex = function (latex, md, element) { |
|
635 | OutputArea.prototype.append_latex = function (latex, md, element) { | |
624 | // This method cannot do the typesetting because the latex first has to |
|
636 | // This method cannot do the typesetting because the latex first has to | |
625 | // be on the page. |
|
637 | // be on the page. | |
@@ -807,6 +819,7 b' var IPython = (function (IPython) {' | |||||
807 | "image/svg+xml" : "svg", |
|
819 | "image/svg+xml" : "svg", | |
808 | "image/png" : "png", |
|
820 | "image/png" : "png", | |
809 | "image/jpeg" : "jpeg", |
|
821 | "image/jpeg" : "jpeg", | |
|
822 | "application/pdf" : "pdf", | |||
810 | "text/latex" : "latex", |
|
823 | "text/latex" : "latex", | |
811 | "application/json" : "json", |
|
824 | "application/json" : "json", | |
812 | "application/javascript" : "javascript", |
|
825 | "application/javascript" : "javascript", | |
@@ -818,6 +831,7 b' var IPython = (function (IPython) {' | |||||
818 | "svg" : "image/svg+xml", |
|
831 | "svg" : "image/svg+xml", | |
819 | "png" : "image/png", |
|
832 | "png" : "image/png", | |
820 | "jpeg" : "image/jpeg", |
|
833 | "jpeg" : "image/jpeg", | |
|
834 | "pdf" : "application/pdf", | |||
821 | "latex" : "text/latex", |
|
835 | "latex" : "text/latex", | |
822 | "json" : "application/json", |
|
836 | "json" : "application/json", | |
823 | "javascript" : "application/javascript", |
|
837 | "javascript" : "application/javascript", | |
@@ -830,6 +844,7 b' var IPython = (function (IPython) {' | |||||
830 | 'image/svg+xml', |
|
844 | 'image/svg+xml', | |
831 | 'image/png', |
|
845 | 'image/png', | |
832 | 'image/jpeg', |
|
846 | 'image/jpeg', | |
|
847 | 'application/pdf', | |||
833 | 'text/plain' |
|
848 | 'text/plain' | |
834 | ]; |
|
849 | ]; | |
835 |
|
850 | |||
@@ -842,6 +857,7 b' var IPython = (function (IPython) {' | |||||
842 | "text/latex" : OutputArea.prototype.append_latex, |
|
857 | "text/latex" : OutputArea.prototype.append_latex, | |
843 | "application/json" : OutputArea.prototype.append_json, |
|
858 | "application/json" : OutputArea.prototype.append_json, | |
844 | "application/javascript" : OutputArea.prototype.append_javascript, |
|
859 | "application/javascript" : OutputArea.prototype.append_javascript, | |
|
860 | "application/pdf" : OutputArea.prototype.append_pdf | |||
845 | }; |
|
861 | }; | |
846 |
|
862 | |||
847 | IPython.OutputArea = OutputArea; |
|
863 | IPython.OutputArea = OutputArea; |
@@ -14,7 +14,9 b' This module does not import anything from matplotlib.' | |||||
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 |
|
15 | |||
16 | from IPython.config.configurable import SingletonConfigurable |
|
16 | from IPython.config.configurable import SingletonConfigurable | |
17 | from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int, TraitError |
|
17 | from IPython.utils.traitlets import ( | |
|
18 | Dict, Instance, CaselessStrEnum, Set, Bool, Int, TraitError, Unicode | |||
|
19 | ) | |||
18 | from IPython.utils.warn import warn |
|
20 | from IPython.utils.warn import warn | |
19 |
|
21 | |||
20 | #----------------------------------------------------------------------------- |
|
22 | #----------------------------------------------------------------------------- | |
@@ -63,21 +65,26 b' class InlineBackend(InlineBackendConfig):' | |||||
63 | inline backend.""" |
|
65 | inline backend.""" | |
64 | ) |
|
66 | ) | |
65 |
|
67 | |||
|
68 | figure_formats = Set({'png'}, config=True, | |||
|
69 | help="""A set of figure formats to enable: 'png', | |||
|
70 | 'retina', 'jpeg', 'svg', 'pdf'.""") | |||
66 |
|
71 | |||
67 | figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'], |
|
72 | def _figure_formats_changed(self, name, old, new): | |
68 | default_value='png', config=True, |
|
73 | from IPython.core.pylabtools import select_figure_formats | |
69 | help="""The image format for figures with the inline |
|
74 | if 'jpg' in new or 'jpeg' in new: | |
70 | backend. JPEG requires the PIL/Pillow library.""") |
|
|||
71 |
|
||||
72 | def _figure_format_changed(self, name, old, new): |
|
|||
73 | from IPython.core.pylabtools import select_figure_format |
|
|||
74 | if new in {"jpg", "jpeg"}: |
|
|||
75 | if not pil_available(): |
|
75 | if not pil_available(): | |
76 | raise TraitError("Requires PIL/Pillow for JPG figures") |
|
76 | raise TraitError("Requires PIL/Pillow for JPG figures") | |
77 | if self.shell is None: |
|
77 | if self.shell is None: | |
78 | return |
|
78 | return | |
79 | else: |
|
79 | else: | |
80 | select_figure_format(self.shell, new) |
|
80 | select_figure_formats(self.shell, new) | |
|
81 | ||||
|
82 | figure_format = Unicode(config=True, help="""The figure format to enable (deprecated | |||
|
83 | use `figure_formats` instead)""") | |||
|
84 | ||||
|
85 | def _figure_format_changed(self, name, old, new): | |||
|
86 | if new: | |||
|
87 | self.figure_formats = {new} | |||
81 |
|
88 | |||
82 | quality = Int(default_value=90, config=True, |
|
89 | quality = Int(default_value=90, config=True, | |
83 | help="Quality of compression [10-100], currently for lossy JPEG only.") |
|
90 | help="Quality of compression [10-100], currently for lossy JPEG only.") |
@@ -119,6 +119,8 b" PNG64 = b'iVBORw0KG'" | |||||
119 | JPEG = b'\xff\xd8' |
|
119 | JPEG = b'\xff\xd8' | |
120 | # front of JPEG base64-encoded |
|
120 | # front of JPEG base64-encoded | |
121 | JPEG64 = b'/9' |
|
121 | JPEG64 = b'/9' | |
|
122 | # front of PDF base64-encoded | |||
|
123 | PDF64 = b'JVBER' | |||
122 |
|
124 | |||
123 | def encode_images(format_dict): |
|
125 | def encode_images(format_dict): | |
124 | """b64-encodes images in a displaypub format dict |
|
126 | """b64-encodes images in a displaypub format dict | |
@@ -136,7 +138,7 b' def encode_images(format_dict):' | |||||
136 |
|
138 | |||
137 | format_dict : dict |
|
139 | format_dict : dict | |
138 | A copy of the same dictionary, |
|
140 | A copy of the same dictionary, | |
139 |
but binary image data ('image/png' |
|
141 | but binary image data ('image/png', 'image/jpeg' or 'application/pdf') | |
140 | is base64-encoded. |
|
142 | is base64-encoded. | |
141 |
|
143 | |||
142 | """ |
|
144 | """ | |
@@ -156,6 +158,13 b' def encode_images(format_dict):' | |||||
156 | jpegdata = encodebytes(jpegdata) |
|
158 | jpegdata = encodebytes(jpegdata) | |
157 | encoded['image/jpeg'] = jpegdata.decode('ascii') |
|
159 | encoded['image/jpeg'] = jpegdata.decode('ascii') | |
158 |
|
160 | |||
|
161 | pdfdata = format_dict.get('application/pdf') | |||
|
162 | if isinstance(pdfdata, bytes): | |||
|
163 | # make sure we don't double-encode | |||
|
164 | if not pdfdata.startswith(PDF64): | |||
|
165 | pdfdata = encodebytes(pdfdata) | |||
|
166 | encoded['application/pdf'] = pdfdata.decode('ascii') | |||
|
167 | ||||
159 | return encoded |
|
168 | return encoded | |
160 |
|
169 | |||
161 |
|
170 |
@@ -69,10 +69,12 b' def test_encode_images():' | |||||
69 | # invalid data, but the header and footer are from real files |
|
69 | # invalid data, but the header and footer are from real files | |
70 | pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82' |
|
70 | pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82' | |
71 | jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9' |
|
71 | jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9' | |
|
72 | pdfdata = b'%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>' | |||
72 |
|
73 | |||
73 | fmt = { |
|
74 | fmt = { | |
74 | 'image/png' : pngdata, |
|
75 | 'image/png' : pngdata, | |
75 | 'image/jpeg' : jpegdata, |
|
76 | 'image/jpeg' : jpegdata, | |
|
77 | 'application/pdf' : pdfdata | |||
76 | } |
|
78 | } | |
77 | encoded = encode_images(fmt) |
|
79 | encoded = encode_images(fmt) | |
78 | for key, value in iteritems(fmt): |
|
80 | for key, value in iteritems(fmt): |
General Comments 0
You need to be logged in to leave comments.
Login now