Support images in Data URI on non-HTML builders

This commit is contained in:
Takeshi KOMIYA 2017-04-19 01:38:30 +09:00
parent be261ed71e
commit ebdec70dfc
6 changed files with 47 additions and 8 deletions

View File

@ -106,7 +106,8 @@ Features added
``suppress_warnings``
* #2803: Discovery of builders by entry point
* #1764, #1676: Allow setting 'rel' and 'title' attributes for stylesheets
* #3589: Support remote images
* #3589: Support remote images on non-HTML builders
* #3589: Support images in Data URI on non-HTML builders
Bugs fixed
----------

View File

@ -227,7 +227,6 @@ General configuration
* app.add_generic_role
* app.add_source_parser
* download.not_readable
* image.data_uri
* image.not_readable
* ref.term
* ref.ref

View File

@ -65,6 +65,7 @@ class Builder(object):
#: Image files are searched in the order in which they appear here.
supported_image_types = [] # type: List[unicode]
supported_remote_images = True
supported_data_uri_images = False
def __init__(self, app):
# type: (Sphinx) -> None

View File

@ -103,6 +103,7 @@ class StandaloneHTMLBuilder(Builder):
html_scaled_image_link = True
supported_image_types = ['image/svg+xml', 'image/png',
'image/gif', 'image/jpeg']
supported_data_uri_images = True
searchindex_filename = 'searchindex.js'
add_permalinks = True
allow_sharp_as_current_path = True

View File

@ -59,8 +59,6 @@ class ImageCollector(EnvironmentCollector):
node['candidates'] = candidates
imguri = node['uri']
if imguri.startswith('data:'):
logger.warning('image data URI found. some builders might not support',
location=node, type='image', subtype='data_uri')
candidates['?'] = imguri
continue
elif imguri.find('://') != -1:

View File

@ -10,13 +10,14 @@
"""
import os
from hashlib import sha1
from six import text_type
from docutils import nodes
from sphinx.transforms import SphinxTransform
from sphinx.util import logging, requests
from sphinx.util.images import guess_mimetype
from sphinx.util.images import guess_mimetype, get_image_extension, parse_data_uri
from sphinx.util.osutil import ensuredir
if False:
@ -43,6 +44,11 @@ class BaseImageConverter(SphinxTransform):
# type: (nodes.Node) -> None
pass
@property
def imagedir(self):
# type: () -> unicode
return os.path.join(self.app.doctreedir, 'images')
class ImageDownloader(BaseImageConverter):
default_priority = 100
@ -56,14 +62,13 @@ class ImageDownloader(BaseImageConverter):
def handle(self, node):
# type: (nodes.Node) -> None
imgdir = os.path.join(self.app.doctreedir, 'images')
basename = os.path.basename(node['uri'])
if '?' in basename:
basename = basename.split('?')[0]
dirname = node['uri'].replace('://', '/').translate({ord("?"): u"/",
ord("&"): u"/"})
ensuredir(os.path.join(imgdir, dirname))
path = os.path.join(imgdir, dirname, basename)
ensuredir(os.path.join(self.imagedir, dirname))
path = os.path.join(self.imagedir, dirname, basename)
try:
r = requests.get(node['uri'])
if r.status_code != 200:
@ -85,9 +90,43 @@ class ImageDownloader(BaseImageConverter):
(node['uri'], text_type(exc)))
class DataURIExtractor(BaseImageConverter):
default_priority = 150
def match(self, node):
# type: (nodes.Node) -> bool
if self.app.builder.supported_data_uri_images:
return False
else:
return 'data:' in node['uri']
def handle(self, node):
# type: (nodes.Node) -> None
image = parse_data_uri(node['uri'])
ext = get_image_extension(image.mimetype)
if ext is None:
logger.warning('Unknown image format: %s...', node['uri'][:32],
location=node)
return
ensuredir(os.path.join(self.imagedir, 'embeded'))
digest = sha1(image.data).hexdigest()
path = os.path.join(self.imagedir, 'embeded', digest + ext)
self.app.env.original_image_uri[path] = node['uri']
with open(path, 'wb') as f:
f.write(image.data)
node['candidates'].pop('?')
node['candidates'][image.mimetype] = path
node['uri'] = path
self.app.env.images.add_file(self.env.docname, path)
def setup(app):
# type: (Sphinx) -> Dict[unicode, Any]
app.add_post_transform(ImageDownloader)
app.add_post_transform(DataURIExtractor)
return {
'version': 'builtin',