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

This commit is contained in:
Georg Brandl 2012-02-18 08:04:31 +01:00
commit ea5dc363e2
9 changed files with 125 additions and 11 deletions

View File

@ -36,7 +36,9 @@ epub_identifier = epub_publisher
epub_pre_files = [('index.html', 'Welcome')] epub_pre_files = [('index.html', 'Welcome')]
epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js', epub_exclude_files = ['_static/opensearch.xml', '_static/doctools.js',
'_static/jquery.js', '_static/searchtools.js', '_static/underscore.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', latex_documents = [('contents', 'sphinx.tex', 'Sphinx Documentation',
'Georg Brandl', 'manual', 1)] 'Georg Brandl', 'manual', 1)]

View File

@ -785,6 +785,12 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
output is usually not wise. This defaults to ``'epub'``, a theme designed to output is usually not wise. This defaults to ``'epub'``, a theme designed to
save visual space. 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 .. confval:: epub_title
The title of the document. It defaults to the :confval:`html_title` option The title of the document. It defaults to the :confval:`html_title` option
@ -884,6 +890,23 @@ the `Dublin Core metadata <http://dublincore.org/>`_.
depth in one list. The default value is ``True``. 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: .. _latex-options:
Options for LaTeX output Options for LaTeX output

View File

@ -200,10 +200,14 @@ These themes are:
* **traditional** -- A theme resembling the old Python documentation. There are * **traditional** -- A theme resembling the old Python documentation. There are
currently no options beyond *nosidebar* and *sidebarwidth*. currently no options beyond *nosidebar* and *sidebarwidth*.
* **epub** -- A theme for the epub builder. There are currently no options. * **epub** -- A theme for the epub builder. This theme tries to save visual
This theme tries to save visual space which is a sparse resource on ebook space which is a sparse resource on ebook readers. The following options
readers. 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 Creating themes
--------------- ---------------

View File

@ -18,12 +18,21 @@ import codecs
import zipfile import zipfile
from os import path from os import path
try:
from PIL import Image
except ImportError:
try:
import Image
except ImportError:
Image = None
from docutils import nodes from docutils import nodes
from sphinx import addnodes from sphinx import addnodes
from sphinx.builders.html import StandaloneHTMLBuilder 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.smartypants import sphinx_smarty_pants as ssp
from sphinx.util.console import brown
# (Fragment) templates from which the metainfo files content.opf, toc.ncx, # (Fragment) templates from which the metainfo files content.opf, toc.ncx,
@ -165,7 +174,7 @@ class EpubBuilder(StandaloneHTMLBuilder):
self.playorder = 0 self.playorder = 0
def get_theme_config(self): def get_theme_config(self):
return self.config.epub_theme, {} return self.config.epub_theme, self.config.epub_theme_options
# generic support functions # generic support functions
def make_id(self, name): def make_id(self, name):
@ -206,11 +215,11 @@ class EpubBuilder(StandaloneHTMLBuilder):
return result return result
def get_toc(self): 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. and pre and post files not managed by sphinx.
""" """
doctree = self.env.get_and_resolve_doctree(self.config.master_doc, 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, []) self.refnodes = self.get_refnodes(doctree, [])
master_dir = os.path.dirname(self.config.master_doc) master_dir = os.path.dirname(self.config.master_doc)
if master_dir: if master_dir:
@ -301,6 +310,57 @@ class EpubBuilder(StandaloneHTMLBuilder):
subentrylinks[i] = (ismain, subentrylinks[i] = (ismain,
self.fix_fragment(m.group(1), m.group(2))) 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', def handle_page(self, pagename, addctx, templatename='page.html',
outfilename=None, event_arg=None): outfilename=None, event_arg=None):
"""Create a rendered page. """Create a rendered page.
@ -529,7 +589,10 @@ class EpubBuilder(StandaloneHTMLBuilder):
"""Write the metainfo file toc.ncx.""" """Write the metainfo file toc.ncx."""
self.info('writing %s file...' % outname) 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 = max(item['level'] for item in self.refnodes)
level = min(level, self.config.epub_tocdepth) level = min(level, self.config.epub_tocdepth)
f = codecs.open(path.join(outdir, outname), 'w', 'utf-8') f = codecs.open(path.join(outdir, outname), 'w', 'utf-8')

View File

@ -123,6 +123,7 @@ class Config(object):
# Epub options # Epub options
epub_basename = (lambda self: make_filename(self.project), None), epub_basename = (lambda self: make_filename(self.project), None),
epub_theme = ('epub', 'html'), epub_theme = ('epub', 'html'),
epub_theme_options = ({}, 'html'),
epub_title = (lambda self: self.html_title, 'html'), epub_title = (lambda self: self.html_title, 'html'),
epub_author = ('unknown', 'html'), epub_author = ('unknown', 'html'),
epub_language = (lambda self: self.language or 'en', 'html'), epub_language = (lambda self: self.language or 'en', 'html'),
@ -137,6 +138,8 @@ class Config(object):
epub_exclude_files = ([], 'env'), epub_exclude_files = ([], 'env'),
epub_tocdepth = (3, 'env'), epub_tocdepth = (3, 'env'),
epub_tocdup = (True, 'env'), epub_tocdup = (True, 'env'),
epub_fix_images = (False, 'env'),
epub_max_image_width = (0, 'env'),
# LaTeX options # LaTeX options
latex_documents = ([], None), latex_documents = ([], None),

View File

@ -1217,7 +1217,7 @@ class BuildEnvironment:
def get_and_resolve_doctree(self, docname, builder, doctree=None, 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 """Read the doctree from the pickle, resolve cross-references and
toctrees and return it. toctrees and return it.
""" """
@ -1230,7 +1230,7 @@ class BuildEnvironment:
# now, resolve all toctree nodes # now, resolve all toctree nodes
for toctreenode in doctree.traverse(addnodes.toctree): for toctreenode in doctree.traverse(addnodes.toctree):
result = self.resolve_toctree(docname, builder, toctreenode, result = self.resolve_toctree(docname, builder, toctreenode,
prune=prune_toctrees) prune=prune_toctrees, includehidden=includehidden)
if result is None: if result is None:
toctreenode.replace_self([]) toctreenode.replace_self([])
else: else:

View File

@ -325,6 +325,12 @@ epub_copyright = u'%(copyright_str)s'
# Allow duplicate toc entries. # Allow duplicate toc entries.
#epub_tocdup = True #epub_tocdup = True
# Fix unsupported image types using the PIL.
#epub_fix_images = False
# Scale large images.
#epub_max_image_width = 0
''' '''
INTERSPHINX_CONFIG = ''' INTERSPHINX_CONFIG = '''

View File

@ -14,3 +14,12 @@
{% block sidebar2 %}{% endblock %} {% block sidebar2 %}{% endblock %}
{% block relbar2 %}{% endblock %} {% block relbar2 %}{% endblock %}
{% block linktags %}{% 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 %}

View File

@ -2,3 +2,7 @@
inherit = basic inherit = basic
stylesheet = epub.css stylesheet = epub.css
pygments_style = none pygments_style = none
[options]
relbar1 = true
footer = true