##// END OF EJS Templates
Add HTML export options...
Mark Voorhies -
Show More
@@ -507,6 +507,89 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
507 return
507 return
508 self._control.print_(printer)
508 self._control.print_(printer)
509
509
510 def exportHtmlInline(self, parent = None):
511 self.exportHtml(parent, inline = True)
512
513 def exportHtml(self, parent = None, inline = False):
514 """ Export the contents of the ConsoleWidget as an HTML file.
515
516 If inline == True, include images as inline PNGs. Otherwise,
517 include them as links to external PNG files, mimicking the
518 Firefox's "Web Page, complete" behavior.
519 """
520 dialog = QtGui.QFileDialog(parent, 'Save HTML Document')
521 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
522 dialog.setDefaultSuffix('htm')
523 dialog.setNameFilter('HTML document (*.htm)')
524 if dialog.exec_():
525 filename = str(dialog.selectedFiles()[0])
526 if(inline):
527 path = None
528 else:
529 offset = filename.rfind(".")
530 if(offset > 0):
531 path = filename[:offset]+"_files"
532 else:
533 path = filename+"_files"
534 import os
535 try:
536 os.mkdir(path)
537 except OSError:
538 # TODO: check that this is an "already exists" error
539 pass
540
541 f = open(filename, 'w')
542 try:
543 # N.B. this is overly restrictive, but Qt's output is
544 # predictable...
545 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
546 f.write(img_re.sub(
547 lambda x: self.imagetag(x, path = path, format = "PNG"),
548 str(self._control.toHtml().toUtf8())))
549 finally:
550 f.close()
551 return filename
552 return None
553
554 def exportXhtml(self, parent = None):
555 """ Export the contents of the ConsoleWidget as an XHTML file
556 with figures as inline SVG.
557 """
558 dialog = QtGui.QFileDialog(parent, 'Save XHTML Document')
559 dialog.setAcceptMode(QtGui.QFileDialog.AcceptSave)
560 dialog.setDefaultSuffix('xml')
561 dialog.setNameFilter('XHTML document (*.xml)')
562 if dialog.exec_():
563 filename = str(dialog.selectedFiles()[0])
564 f = open(filename, 'w')
565 try:
566 # N.B. this is overly restrictive, but Qt's output is
567 # predictable...
568 img_re = re.compile(r'<img src="(?P<name>[\d]+)" />')
569 html = str(self._control.toHtml().toUtf8())
570 # Hack to make xhtml header -- note that we are not doing
571 # any check for valid xml
572 offset = html.find("<html>")
573 assert(offset > -1)
574 html = ('<html xmlns="http://www.w3.org/1999/xhtml">\n'+
575 html[offset+6:])
576 f.write(img_re.sub(
577 lambda x: self.imagetag(x, path = None, format = "SVG"),
578 html))
579 finally:
580 f.close()
581 return filename
582 return None
583
584 def imagetag(self, match, path = None):
585 """ Given an re.match object matching an image name in an HTML export,
586 return an appropriate substitution string for the image tag
587 (e.g., link, embedded image, ...). As a side effect, files may
588 be generated in the directory given by path."""
589
590 # Default case -- not enough information to generate tag
591 return ""
592
510 def prompt_to_top(self):
593 def prompt_to_top(self):
511 """ Moves the prompt to the top of the viewport.
594 """ Moves the prompt to the top of the viewport.
512 """
595 """
@@ -744,7 +827,15 b' class ConsoleWidget(Configurable, QtGui.QWidget):'
744 menu.addSeparator()
827 menu.addSeparator()
745 print_action = menu.addAction('Print', self.print_)
828 print_action = menu.addAction('Print', self.print_)
746 print_action.setEnabled(True)
829 print_action.setEnabled(True)
747
830 html_action = menu.addAction('Export HTML (external PNGs)',
831 self.exportHtml)
832 html_action.setEnabled(True)
833 html_inline_action = menu.addAction('Export HTML (inline PNGs)',
834 self.exportHtmlInline)
835 html_inline_action.setEnabled(True)
836 xhtml_action = menu.addAction('Export XHTML (inline SVGs)',
837 self.exportXhtml)
838 xhtml_action.setEnabled(True)
748 return menu
839 return menu
749
840
750 def _control_key_down(self, modifiers, include_command=True):
841 def _control_key_down(self, modifiers, include_command=True):
@@ -25,6 +25,9 b' class RichIPythonWidget(IPythonWidget):'
25 """
25 """
26 kw['kind'] = 'rich'
26 kw['kind'] = 'rich'
27 super(RichIPythonWidget, self).__init__(*args, **kw)
27 super(RichIPythonWidget, self).__init__(*args, **kw)
28 # Dictionary for resolving Qt names to images when
29 # generating XHTML output
30 self._name2svg = {}
28
31
29 #---------------------------------------------------------------------------
32 #---------------------------------------------------------------------------
30 # 'ConsoleWidget' protected interface
33 # 'ConsoleWidget' protected interface
@@ -68,6 +71,7 b' class RichIPythonWidget(IPythonWidget):'
68 self._append_plain_text('Received invalid plot data.')
71 self._append_plain_text('Received invalid plot data.')
69 else:
72 else:
70 format = self._add_image(image)
73 format = self._add_image(image)
74 self._name2svg[str(format.name())] = svg
71 format.setProperty(self._svg_text_format_property, svg)
75 format.setProperty(self._svg_text_format_property, svg)
72 cursor = self._get_end_cursor()
76 cursor = self._get_end_cursor()
73 cursor.insertBlock()
77 cursor.insertBlock()
@@ -121,3 +125,53 b' class RichIPythonWidget(IPythonWidget):'
121 filename = dialog.selectedFiles()[0]
125 filename = dialog.selectedFiles()[0]
122 image = self._get_image(name)
126 image = self._get_image(name)
123 image.save(filename, format)
127 image.save(filename, format)
128
129 def imagetag(self, match, path = None, format = "PNG"):
130 """ Given an re.match object matching an image name in an HTML dump,
131 return an appropriate substitution string for the image tag
132 (e.g., link, embedded image, ...). As a side effect, files may
133 be generated in the directory given by path."""
134
135 if(format == "PNG"):
136 try:
137 image = self._get_image(match.group("name"))
138 except KeyError:
139 return "<b>Couldn't find image %s</b>" % match.group("name")
140
141 if(path is not None):
142 relpath = path[path.rfind("/")+1:]
143 if(image.save("%s/qt_img%s.png" % (path,match.group("name")),
144 "PNG")):
145 return '<img src="%s/qt_img%s.png">' % (relpath,
146 match.group("name"))
147 else:
148 return "<b>Couldn't save image!</b>"
149 else:
150 ba = QtCore.QByteArray()
151 buffer_ = QtCore.QBuffer(ba)
152 buffer_.open(QtCore.QIODevice.WriteOnly)
153 image.save(buffer_, "PNG")
154 buffer_.close()
155 import re
156 return '<img src="data:image/png;base64,\n%s\n" />' % (
157 re.sub(r'(.{60})',r'\1\n',str(ba.toBase64())))
158
159 elif(format == "SVG"):
160 try:
161 svg = str(self._name2svg[match.group("name")])
162 except KeyError:
163 return "<b>Couldn't find image %s</b>" % match.group("name")
164
165 # Not currently checking path, because it's tricky to find a
166 # cross-browser way to embed external SVG images (e.g., via
167 # object or embed tags).
168
169 # Chop stand-alone header from matplotlib SVG
170 offset = svg.find("<svg")
171 assert(offset > -1)
172
173 return svg[offset:]
174
175 else:
176 return '<b>Unrecognized image format</b>'
177
General Comments 0
You need to be logged in to leave comments. Login now