Anonymous avatar Anonymous committed 596ba81

Add image format handling.

Comments (0)

Files changed (7)

   - The directories in the `html_static_path` can now contain
     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
   subtrees from the search for source files.
 
 - "often used" combo box in sidebar
 - 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)?
 
    A. First item
    B. Second item
-   
+
 
 Nested lists are possible, but be aware that they must be separated from the
 parent list items by blank lines::
 
 reST supports an image directive, used like so::
 
-   .. image:: filename
+   .. image:: gnu.png
       (options)
 
-When used within Sphinx, the ``filename`` given must be relative to the source
-file, and Sphinx will automatically copy image files over to a subdirectory of
-the output directory on building.
+When used within Sphinx, the file name given (here ``gnu.png``) must be relative
+to the source file, and Sphinx will automatically copy image files over to a
+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

sphinx/builder.py

         self.info = app.info
         self.config = app.config
 
+        # images that need to be copied over (source -> dest)
+        self.images = {}
+
         # if None, this is set in load_env()
         self.env = env
         self.freshenv = freshenv
         if l == 0:
             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
 
     def load_env(self):
     copysource = True
     out_suffix = '.html'
     indexer_format = 'json'
+    supported_image_types = ['image/svg+xml', 'image/png', 'image/gif',
+                             'image/jpeg']
 
     def init(self):
         """Load templates."""
 
         favicon = self.config.html_favicon and \
                   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')
 
         if not isinstance(self.config.html_use_opensearch, basestring):
         )
 
     def write_doc(self, docname, doctree):
+        self.post_process_images(doctree)
         destination = StringOutput(encoding='utf-8')
         doctree.settings = self.docsettings
 
         self.info()
 
         # copy image files
-        if self.env.images:
+        if self.images:
             self.info(bold('copying images...'), nonl=1)
             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)
                 shutil.copyfile(path.join(self.srcdir, src),
                                 path.join(self.outdir, '_images', dest))
     name = 'pickle'
     out_suffix = '.fpickle'
     indexer_format = 'pickle'
+    supported_image_types = ('image/svg+xml', 'image/png', 'image/gif',
+                             'image/jpeg')
 
     def init(self):
         self.init_translator_class()
 
     # don't copy the reST source
     copysource = False
+    supported_image_types = ['image/png', 'image/gif', 'image/jpeg']
 
     def init(self):
         StandaloneHTMLBuilder.init(self)
     Builds LaTeX output to create PDF.
     """
     name = 'latex'
+    supported_image_types = ['application/pdf', 'image/png', 'image/gif',
+                             'image/jpeg']
 
     def init(self):
         self.docnames = []
             self.info("processing " + targetname + "... ", nonl=1)
             doctree = self.assemble_doctree(docname, toctree_only,
                 appendices=(docclass == 'manual') and appendices or [])
+            self.post_process_images(doctree)
             self.info("writing... ", nonl=1)
             doctree.settings = docsettings
             doctree.settings.author = author
 
     def finish(self):
         # copy image files
-        if self.env.images:
+        if self.images:
             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)
                 shutil.copyfile(path.join(self.srcdir, src),
                                 path.join(self.outdir, dest))

sphinx/environment.py

 import time
 import heapq
 import types
+import imghdr
 import difflib
 import cPickle as pickle
 from os import path
+from glob import glob
 from string import uppercase
 from itertools import izip, groupby
 try:
         existing_names = set(v[1] for v in self.images.itervalues())
         docdir = path.dirname(self.doc2path(docname, base=None))
         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']
             if imguri.find('://') != -1:
                 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:
-                imgpath = path.normpath(path.join(docdir, imguri))
-                node['uri'] = imgpath
-                self.dependencies.setdefault(docname, set()).add(imgpath)
-                if not os.access(path.join(self.srcdir, imgpath), os.R_OK):
-                    self.warn(docname, 'Image file not readable: %s' % imguri, node.line)
-                if imgpath in self.images:
-                    self.images[imgpath][0].add(docname)
+                candidates['*'] = imgpath
+            for img in candidates.itervalues():
+                self.dependencies.setdefault(docname, set()).add(img)
+                if not os.access(path.join(self.srcdir, img), os.R_OK):
+                    self.warn(docname, 'Image file not readable: %s' % img, node.line)
+                if img in self.images:
+                    self.images[img][0].add(docname)
                     continue
-                uniquename = path.basename(imgpath)
+                uniquename = path.basename(img)
                 base, ext = path.splitext(uniquename)
                 i = 0
                 while uniquename in existing_names:
                     i += 1
                     uniquename = '%s%s%s' % (base, i, ext)
-                self.images[imgpath] = (set([docname]), uniquename)
+                self.images[img] = (set([docname]), uniquename)
                 existing_names.add(uniquename)
 
     def process_metadata(self, docname, doctree):

sphinx/htmlwriter.py

     def visit_image(self, node):
         olduri = node['uri']
         # 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,
-                                         self.builder.env.images[olduri][1])
+                                         self.builder.images[olduri])
         BaseTranslator.visit_image(self, node)
 
     def visit_toctree(self, node):

sphinx/latexwriter.py

             pre.append('\n')
             post.append('\n')
         pre.reverse()
-        if node['uri'] in self.builder.env.images:
-            uri = self.builder.env.images[node['uri']][1]
+        if node['uri'] in self.builder.images:
+            uri = self.builder.images[node['uri']]
         else:
             uri = node['uri']
         if uri.find('://') != -1:
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.