mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add image format handling.
This commit is contained in:
parent
66b5f39bc7
commit
b05861454c
3
CHANGES
3
CHANGES
@ -38,6 +38,9 @@ New features added
|
|||||||
- The directories in the `html_static_path` can now contain
|
- The directories in the `html_static_path` can now contain
|
||||||
subdirectories.
|
subdirectories.
|
||||||
|
|
||||||
|
* The image directive now supports specifying the extension as ``.*``,
|
||||||
|
which makes the builder select the one that matches best.
|
||||||
|
|
||||||
* The new config value `exclude_trees` can be used to exclude whole
|
* The new config value `exclude_trees` can be used to exclude whole
|
||||||
subtrees from the search for source files.
|
subtrees from the search for source files.
|
||||||
|
|
||||||
|
9
TODO
9
TODO
@ -13,12 +13,3 @@ Sphinx
|
|||||||
- "often used" combo box in sidebar
|
- "often used" combo box in sidebar
|
||||||
- source file cross-references?
|
- source file cross-references?
|
||||||
|
|
||||||
Web App
|
|
||||||
*******
|
|
||||||
|
|
||||||
- fix /download
|
|
||||||
|
|
||||||
- discuss and debug comments system
|
|
||||||
- prepare for databases other than sqlite for comments
|
|
||||||
- add search via Xapian or Nucular (Python indexer - nucular.sf.net)
|
|
||||||
- optionally have a contents tree view in the sidebar (AJAX based)?
|
|
||||||
|
25
doc/rest.rst
25
doc/rest.rst
@ -72,7 +72,7 @@ or roman numerals, such as ::
|
|||||||
|
|
||||||
A. First item
|
A. First item
|
||||||
B. Second item
|
B. Second item
|
||||||
|
|
||||||
|
|
||||||
Nested lists are possible, but be aware that they must be separated from the
|
Nested lists are possible, but be aware that they must be separated from the
|
||||||
parent list items by blank lines::
|
parent list items by blank lines::
|
||||||
@ -214,12 +214,27 @@ Images
|
|||||||
|
|
||||||
reST supports an image directive, used like so::
|
reST supports an image directive, used like so::
|
||||||
|
|
||||||
.. image:: filename
|
.. image:: gnu.png
|
||||||
(options)
|
(options)
|
||||||
|
|
||||||
When used within Sphinx, the ``filename`` given must be relative to the source
|
When used within Sphinx, the file name given (here ``gnu.png``) must be relative
|
||||||
file, and Sphinx will automatically copy image files over to a subdirectory of
|
to the source file, and Sphinx will automatically copy image files over to a
|
||||||
the output directory on building.
|
subdirectory of the output directory on building (e.g. the ``_static`` directory
|
||||||
|
for HTML output.)
|
||||||
|
|
||||||
|
Sphinx extends the standard docutils behavior by allowing an asterisk for the
|
||||||
|
extension::
|
||||||
|
|
||||||
|
.. image:: gnu.*
|
||||||
|
|
||||||
|
Sphinx then searches for all images matching the provided pattern and determines
|
||||||
|
their type. Each builder then chooses the best image out of these candidates.
|
||||||
|
For instance, if the file name ``gnu.*`` was given and two files :file:`gnu.pdf`
|
||||||
|
and :file:`gnu.png` existed in the source tree, the LaTeX builder would choose
|
||||||
|
the former, while the HTML builder would prefer the latter.
|
||||||
|
|
||||||
|
.. versionchanged:: 0.4
|
||||||
|
Added the support for file names ending in an asterisk.
|
||||||
|
|
||||||
|
|
||||||
Footnotes
|
Footnotes
|
||||||
|
@ -62,6 +62,9 @@ class Builder(object):
|
|||||||
self.info = app.info
|
self.info = app.info
|
||||||
self.config = app.config
|
self.config = app.config
|
||||||
|
|
||||||
|
# images that need to be copied over (source -> dest)
|
||||||
|
self.images = {}
|
||||||
|
|
||||||
# if None, this is set in load_env()
|
# if None, this is set in load_env()
|
||||||
self.env = env
|
self.env = env
|
||||||
self.freshenv = freshenv
|
self.freshenv = freshenv
|
||||||
@ -118,6 +121,28 @@ class Builder(object):
|
|||||||
if l == 0:
|
if l == 0:
|
||||||
self.info()
|
self.info()
|
||||||
|
|
||||||
|
supported_image_types = []
|
||||||
|
|
||||||
|
def post_process_images(self, doctree):
|
||||||
|
"""
|
||||||
|
Pick the best candidate for all image URIs.
|
||||||
|
"""
|
||||||
|
for node in doctree.traverse(nodes.image):
|
||||||
|
uri = node['candidates'].get('*', None)
|
||||||
|
if not uri:
|
||||||
|
for imgtype in self.supported_image_types:
|
||||||
|
uri = node['candidates'].get(imgtype, None)
|
||||||
|
if uri:
|
||||||
|
node['uri'] = uri
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.warn('%s:%s: %s' %
|
||||||
|
(node.source, node.lineno,
|
||||||
|
'No matching candidate for uri: %(uri)s' % node))
|
||||||
|
continue
|
||||||
|
if uri in self.env.images:
|
||||||
|
self.images[uri] = self.env.images[uri][1]
|
||||||
|
|
||||||
# build methods
|
# build methods
|
||||||
|
|
||||||
def load_env(self):
|
def load_env(self):
|
||||||
@ -271,6 +296,8 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
copysource = True
|
copysource = True
|
||||||
out_suffix = '.html'
|
out_suffix = '.html'
|
||||||
indexer_format = 'json'
|
indexer_format = 'json'
|
||||||
|
supported_image_types = ['image/svg+xml', 'image/png', 'image/gif',
|
||||||
|
'image/jpeg']
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
"""Load templates."""
|
"""Load templates."""
|
||||||
@ -323,7 +350,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
|
|
||||||
favicon = self.config.html_favicon and \
|
favicon = self.config.html_favicon and \
|
||||||
path.basename(self.config.html_favicon) or ''
|
path.basename(self.config.html_favicon) or ''
|
||||||
if os.path.splitext(favicon)[1] != '.ico':
|
if favicon and os.path.splitext(favicon)[1] != '.ico':
|
||||||
self.warn('html_favicon is not an .ico file')
|
self.warn('html_favicon is not an .ico file')
|
||||||
|
|
||||||
if not isinstance(self.config.html_use_opensearch, basestring):
|
if not isinstance(self.config.html_use_opensearch, basestring):
|
||||||
@ -407,6 +434,7 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def write_doc(self, docname, doctree):
|
def write_doc(self, docname, doctree):
|
||||||
|
self.post_process_images(doctree)
|
||||||
destination = StringOutput(encoding='utf-8')
|
destination = StringOutput(encoding='utf-8')
|
||||||
doctree.settings = self.docsettings
|
doctree.settings = self.docsettings
|
||||||
|
|
||||||
@ -504,10 +532,10 @@ class StandaloneHTMLBuilder(Builder):
|
|||||||
self.info()
|
self.info()
|
||||||
|
|
||||||
# copy image files
|
# copy image files
|
||||||
if self.env.images:
|
if self.images:
|
||||||
self.info(bold('copying images...'), nonl=1)
|
self.info(bold('copying images...'), nonl=1)
|
||||||
ensuredir(path.join(self.outdir, '_images'))
|
ensuredir(path.join(self.outdir, '_images'))
|
||||||
for src, (_, dest) in self.env.images.iteritems():
|
for src, dest in self.images.iteritems():
|
||||||
self.info(' '+src, nonl=1)
|
self.info(' '+src, nonl=1)
|
||||||
shutil.copyfile(path.join(self.srcdir, src),
|
shutil.copyfile(path.join(self.srcdir, src),
|
||||||
path.join(self.outdir, '_images', dest))
|
path.join(self.outdir, '_images', dest))
|
||||||
@ -636,6 +664,8 @@ class PickleHTMLBuilder(StandaloneHTMLBuilder):
|
|||||||
name = 'pickle'
|
name = 'pickle'
|
||||||
out_suffix = '.fpickle'
|
out_suffix = '.fpickle'
|
||||||
indexer_format = 'pickle'
|
indexer_format = 'pickle'
|
||||||
|
supported_image_types = ('image/svg+xml', 'image/png', 'image/gif',
|
||||||
|
'image/jpeg')
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.init_translator_class()
|
self.init_translator_class()
|
||||||
@ -711,6 +741,7 @@ class HTMLHelpBuilder(StandaloneHTMLBuilder):
|
|||||||
|
|
||||||
# don't copy the reST source
|
# don't copy the reST source
|
||||||
copysource = False
|
copysource = False
|
||||||
|
supported_image_types = ['image/png', 'image/gif', 'image/jpeg']
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
StandaloneHTMLBuilder.init(self)
|
StandaloneHTMLBuilder.init(self)
|
||||||
@ -726,6 +757,8 @@ class LaTeXBuilder(Builder):
|
|||||||
Builds LaTeX output to create PDF.
|
Builds LaTeX output to create PDF.
|
||||||
"""
|
"""
|
||||||
name = 'latex'
|
name = 'latex'
|
||||||
|
supported_image_types = ['application/pdf', 'image/png', 'image/gif',
|
||||||
|
'image/jpeg']
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
self.docnames = []
|
self.docnames = []
|
||||||
@ -787,6 +820,7 @@ class LaTeXBuilder(Builder):
|
|||||||
self.info("processing " + targetname + "... ", nonl=1)
|
self.info("processing " + targetname + "... ", nonl=1)
|
||||||
doctree = self.assemble_doctree(docname, toctree_only,
|
doctree = self.assemble_doctree(docname, toctree_only,
|
||||||
appendices=(docclass == 'manual') and appendices or [])
|
appendices=(docclass == 'manual') and appendices or [])
|
||||||
|
self.post_process_images(doctree)
|
||||||
self.info("writing... ", nonl=1)
|
self.info("writing... ", nonl=1)
|
||||||
doctree.settings = docsettings
|
doctree.settings = docsettings
|
||||||
doctree.settings.author = author
|
doctree.settings.author = author
|
||||||
@ -852,9 +886,9 @@ class LaTeXBuilder(Builder):
|
|||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
# copy image files
|
# copy image files
|
||||||
if self.env.images:
|
if self.images:
|
||||||
self.info(bold('copying images...'), nonl=1)
|
self.info(bold('copying images...'), nonl=1)
|
||||||
for src, (_, dest) in self.env.images.iteritems():
|
for src, dest in self.images.iteritems():
|
||||||
self.info(' '+src, nonl=1)
|
self.info(' '+src, nonl=1)
|
||||||
shutil.copyfile(path.join(self.srcdir, src),
|
shutil.copyfile(path.join(self.srcdir, src),
|
||||||
path.join(self.outdir, dest))
|
path.join(self.outdir, dest))
|
||||||
|
@ -14,9 +14,11 @@ import os
|
|||||||
import time
|
import time
|
||||||
import heapq
|
import heapq
|
||||||
import types
|
import types
|
||||||
|
import imghdr
|
||||||
import difflib
|
import difflib
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
from os import path
|
from os import path
|
||||||
|
from glob import glob
|
||||||
from string import uppercase
|
from string import uppercase
|
||||||
from itertools import izip, groupby
|
from itertools import izip, groupby
|
||||||
try:
|
try:
|
||||||
@ -511,25 +513,43 @@ class BuildEnvironment:
|
|||||||
existing_names = set(v[1] for v in self.images.itervalues())
|
existing_names = set(v[1] for v in self.images.itervalues())
|
||||||
docdir = path.dirname(self.doc2path(docname, base=None))
|
docdir = path.dirname(self.doc2path(docname, base=None))
|
||||||
for node in doctree.traverse(nodes.image):
|
for node in doctree.traverse(nodes.image):
|
||||||
|
# Map the mimetype to the corresponding image. The writer may
|
||||||
|
# choose the best image from these candidates. The special key * is
|
||||||
|
# set if there is only single candiate to be used by a writer.
|
||||||
|
node['candidates'] = candidates = {}
|
||||||
imguri = node['uri']
|
imguri = node['uri']
|
||||||
if imguri.find('://') != -1:
|
if imguri.find('://') != -1:
|
||||||
self.warn(docname, 'Nonlocal image URI found: %s' % imguri, node.line)
|
self.warn(docname, 'Nonlocal image URI found: %s' % imguri, node.line)
|
||||||
|
candidates['*'] = imguri
|
||||||
|
continue
|
||||||
|
imgpath = path.normpath(path.join(docdir, imguri))
|
||||||
|
if imgpath.endswith(os.extsep + '*'):
|
||||||
|
for filename in glob(imgpath):
|
||||||
|
basename, ext = os.path.splitext(filename)
|
||||||
|
if ext == '.pdf':
|
||||||
|
candidates['application/pdf'] = filename
|
||||||
|
elif ext == '.svg':
|
||||||
|
candidates['image/svg+xml'] = filename
|
||||||
|
else:
|
||||||
|
imgtype = imghdr.what(filename)
|
||||||
|
if imgtype:
|
||||||
|
candidates['image/' + imgtype] = filename
|
||||||
else:
|
else:
|
||||||
imgpath = path.normpath(path.join(docdir, imguri))
|
candidates['*'] = imgpath
|
||||||
node['uri'] = imgpath
|
for img in candidates.itervalues():
|
||||||
self.dependencies.setdefault(docname, set()).add(imgpath)
|
self.dependencies.setdefault(docname, set()).add(img)
|
||||||
if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
|
if not os.access(path.join(self.srcdir, img), os.R_OK):
|
||||||
self.warn(docname, 'Image file not readable: %s' % imguri, node.line)
|
self.warn(docname, 'Image file not readable: %s' % img, node.line)
|
||||||
if imgpath in self.images:
|
if img in self.images:
|
||||||
self.images[imgpath][0].add(docname)
|
self.images[img][0].add(docname)
|
||||||
continue
|
continue
|
||||||
uniquename = path.basename(imgpath)
|
uniquename = path.basename(img)
|
||||||
base, ext = path.splitext(uniquename)
|
base, ext = path.splitext(uniquename)
|
||||||
i = 0
|
i = 0
|
||||||
while uniquename in existing_names:
|
while uniquename in existing_names:
|
||||||
i += 1
|
i += 1
|
||||||
uniquename = '%s%s%s' % (base, i, ext)
|
uniquename = '%s%s%s' % (base, i, ext)
|
||||||
self.images[imgpath] = (set([docname]), uniquename)
|
self.images[img] = (set([docname]), uniquename)
|
||||||
existing_names.add(uniquename)
|
existing_names.add(uniquename)
|
||||||
|
|
||||||
def process_metadata(self, docname, doctree):
|
def process_metadata(self, docname, doctree):
|
||||||
|
@ -250,9 +250,9 @@ class HTMLTranslator(BaseTranslator):
|
|||||||
def visit_image(self, node):
|
def visit_image(self, node):
|
||||||
olduri = node['uri']
|
olduri = node['uri']
|
||||||
# rewrite the URI if the environment knows about it
|
# rewrite the URI if the environment knows about it
|
||||||
if olduri in self.builder.env.images:
|
if olduri in self.builder.images:
|
||||||
node['uri'] = posixpath.join(self.builder.imgpath,
|
node['uri'] = posixpath.join(self.builder.imgpath,
|
||||||
self.builder.env.images[olduri][1])
|
self.builder.images[olduri])
|
||||||
BaseTranslator.visit_image(self, node)
|
BaseTranslator.visit_image(self, node)
|
||||||
|
|
||||||
def visit_toctree(self, node):
|
def visit_toctree(self, node):
|
||||||
|
@ -630,8 +630,8 @@ class LaTeXTranslator(nodes.NodeVisitor):
|
|||||||
pre.append('\n')
|
pre.append('\n')
|
||||||
post.append('\n')
|
post.append('\n')
|
||||||
pre.reverse()
|
pre.reverse()
|
||||||
if node['uri'] in self.builder.env.images:
|
if node['uri'] in self.builder.images:
|
||||||
uri = self.builder.env.images[node['uri']][1]
|
uri = self.builder.images[node['uri']]
|
||||||
else:
|
else:
|
||||||
uri = node['uri']
|
uri = node['uri']
|
||||||
if uri.find('://') != -1:
|
if uri.find('://') != -1:
|
||||||
|
Loading…
Reference in New Issue
Block a user