Commits

Georg Brandl committed fca9493 Merge

Merged in rolmei/sphinx-epub (pull request #42)

Comments (0)

Files changed (9)

 epub_pre_files = [('index.html', 'Welcome')]
 epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js',
     '_static/jquery.js', '_static/searchtools.js', '_static/underscore.js',
-    '_static/basic.css', 'search.html']
+    '_static/basic.css', 'search.html', '_static/websupport.js']
+epub_fix_images = False
+epub_max_image_width = 0
 
 latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
                     'Georg Brandl', 'manual', 1)]
    output is usually not wise.  This defaults to ``'epub'``, a theme designed to
    save visual space.
 
+.. confval:: epub_theme_options
+
+   A dictionary of options that influence the look and feel of the selected
+   theme.  These are theme-specific.  For the options understood by the builtin
+   themes, see :ref:`this section <builtin-themes>`.
+
 .. confval:: epub_title
 
    The title of the document.  It defaults to the :confval:`html_title` option
    depth in one list.  The default value is ``True``.
 
 
+.. confval:: epub_fix_images
+
+   This flag determines if sphinx should try to fix image formats that are not
+   supported by some epub readers.  At the moment palette images with a small
+   color table are upgraded.  You need the Python Image Library (PIL) installed
+   to use this option.  The default value is ``False`` because the automatic
+   conversion may lose information.
+
+.. confval:: epub_max_image_width
+
+   This option specifies the maximum width of images.  If it is set to a value
+   greater than zero, images with a width larger than the given value are
+   scaled accordingly.  If it is zero, no scaling is performed. The default
+   value is ``0``.  You need the Python Image Library (PIL) installed to use
+   this option.
+
+
 .. _latex-options:
 
 Options for LaTeX output
 * **traditional** -- A theme resembling the old Python documentation.  There are
   currently no options beyond *nosidebar* and *sidebarwidth*.
 
-* **epub** -- A theme for the epub builder.  There are currently no options.
-  This theme tries to save visual space which is a sparse resource on ebook
-  readers.
+* **epub** -- A theme for the epub builder.  This theme tries to save visual
+  space which is a sparse resource on ebook readers.  The following options
+  are supported:
 
+  - **relbar1** (true or false, default true): If this is true, the
+    `relbar1` block is inserted in the epub output, otherwise it is omitted.
+  - **footer**  (true or false, default true): If this is true, the
+    `footer` block is inserted in the epub output, otherwise it is ommitted.
 
 Creating themes
 ---------------

sphinx/builders/epub.py

 import zipfile
 from os import path
 
+try:
+    from PIL import Image
+except ImportError:
+    try:
+        import Image
+    except ImportError:
+        Image = None
+
 from docutils import nodes
 
 from sphinx import addnodes
 from sphinx.builders.html import StandaloneHTMLBuilder
-from sphinx.util.osutil import EEXIST
+from sphinx.util.osutil import ensuredir, EEXIST
 from sphinx.util.smartypants import sphinx_smarty_pants as ssp
+from sphinx.util.console import brown
 
 
 # (Fragment) templates from which the metainfo files content.opf, toc.ncx,
         self.playorder = 0
 
     def get_theme_config(self):
-        return self.config.epub_theme, {}
+        return self.config.epub_theme, self.config.epub_theme_options
 
     # generic support functions
     def make_id(self, name):
         return result
 
     def get_toc(self):
-        """Get the total table of contents, containg the master_doc
+        """Get the total table of contents, containing the master_doc
         and pre and post files not managed by sphinx.
         """
         doctree = self.env.get_and_resolve_doctree(self.config.master_doc,
-            self, prune_toctrees=False)
+            self, prune_toctrees=False, includehidden=True)
         self.refnodes = self.get_refnodes(doctree, [])
         master_dir = os.path.dirname(self.config.master_doc)
         if master_dir:
                             subentrylinks[i] = (ismain,
                                 self.fix_fragment(m.group(1), m.group(2)))
 
+    def copy_image_files_pil(self):
+        """Copy images using the PIL.
+        The method tries to read and write the files with the PIL,
+        converting the format and resizing the image if necessary/possible.
+        """
+        ensuredir(path.join(self.outdir, '_images'))
+        for src in self.status_iterator(self.images, 'copying images... ',
+                                        brown, len(self.images)):
+            dest = self.images[src]
+            try:
+                img = Image.open(path.join(self.srcdir, src))
+            except IOError:
+                self.warn('cannot read image file %r: copying it instead' %
+                          (path.join(self.srcdir, src), ))
+                try:
+                    copyfile(path.join(self.srcdir, src),
+                             path.join(self.outdir, '_images', dest))
+                except Exception, err:
+                    self.warn('cannot copy image file %r: %s' %
+                              (path.join(self.srcdir, src), err))
+                continue
+            if self.config.epub_fix_images:
+                if img.mode in ('P',):
+                    # See PIL documentation for Image.convert()
+                    img = img.convert()
+            if self.config.epub_max_image_width > 0:
+                (width, height) = img.size
+                nw = self.config.epub_max_image_width
+                if width > nw:
+                    nh = (height * nw) / width
+                    img = img.resize((nw, nh), Image.BICUBIC)
+            try:
+                img.save(path.join(self.outdir, '_images', dest))
+            except IOError, err:
+                self.warn('cannot write image file %r: %s' %
+                          (path.join(self.srcdir, src), err))
+
+    def copy_image_files(self):
+        """Copy image files to destination directory.
+        This overwritten method can use the PIL to convert image files.
+        """
+        if self.images:
+            if self.config.epub_fix_images or self.config.epub_max_image_width:
+                if not Image:
+                    self.warn('PIL not found - copying image files')
+                    super(EpubBuilder, self).copy_image_files()
+                else:
+                    self.copy_image_files_pil()
+            else:
+                super(EpubBuilder, self).copy_image_files()
+
     def handle_page(self, pagename, addctx, templatename='page.html',
                     outfilename=None, event_arg=None):
         """Create a rendered page.
         """Write the metainfo file toc.ncx."""
         self.info('writing %s file...' % outname)
 
-        navpoints = self.build_navpoints(self.refnodes)
+        doctree = self.env.get_and_resolve_doctree(self.config.master_doc,
+            self, prune_toctrees=False, includehidden=False)
+        refnodes = self.get_refnodes(doctree, [])
+        navpoints = self.build_navpoints(refnodes)
         level = max(item['level'] for item in self.refnodes)
         level = min(level, self.config.epub_tocdepth)
         f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')
         # Epub options
         epub_basename = (lambda self: make_filename(self.project), None),
         epub_theme = ('epub', 'html'),
+        epub_theme_options = ({}, 'html'),
         epub_title = (lambda self: self.html_title, 'html'),
         epub_author = ('unknown', 'html'),
         epub_language = (lambda self: self.language or 'en', 'html'),
         epub_exclude_files = ([], 'env'),
         epub_tocdepth = (3, 'env'),
         epub_tocdup = (True, 'env'),
+        epub_fix_images = (False, 'env'),
+        epub_max_image_width = (0, 'env'),
 
         # LaTeX options
         latex_documents = ([], None),

sphinx/environment.py

 
 
     def get_and_resolve_doctree(self, docname, builder, doctree=None,
-                                prune_toctrees=True):
+                                prune_toctrees=True, includehidden=False):
         """Read the doctree from the pickle, resolve cross-references and
         toctrees and return it.
         """
         # now, resolve all toctree nodes
         for toctreenode in doctree.traverse(addnodes.toctree):
             result = self.resolve_toctree(docname, builder, toctreenode,
-                                          prune=prune_toctrees)
+                          prune=prune_toctrees, includehidden=includehidden)
             if result is None:
                 toctreenode.replace_self([])
             else:

sphinx/quickstart.py

 
 # Allow duplicate toc entries.
 #epub_tocdup = True
+
+# Fix unsupported image types using the PIL.
+#epub_fix_images = False
+
+# Scale large images.
+#epub_max_image_width = 0
 '''
 
 INTERSPHINX_CONFIG = '''

sphinx/themes/epub/layout.html

 {% block sidebar2 %}{% endblock %}
 {% block relbar2 %}{% endblock %}
 {% block linktags %}{% endblock %}
+
+{# redefine relbar1 and footer to only call super if options are true #}
+{%- block relbar1 %}
+{% if theme_relbar1|tobool %}{{ super() }}{% endif %}
+{%- endblock %}
+{%- block footer %}
+{% if theme_footer|tobool %}{{ super() }}{% endif %}
+{%- endblock %}
+

sphinx/themes/epub/theme.conf

 inherit = basic
 stylesheet = epub.css
 pygments_style = none
+
+[options]
+relbar1 = true
+footer = true