diff options
| -rw-r--r-- | docutils/HISTORY.txt | 1 | ||||
| -rw-r--r-- | docutils/RELEASE-NOTES.txt | 4 | ||||
| -rw-r--r-- | docutils/docs/user/config.txt | 26 | ||||
| -rw-r--r-- | docutils/docutils/writers/_html_base.py | 48 | ||||
| -rw-r--r-- | docutils/docutils/writers/html4css1/__init__.py | 9 | ||||
| -rw-r--r-- | docutils/docutils/writers/html5_polyglot/__init__.py | 9 | ||||
| -rw-r--r-- | docutils/test/functional/expected/embed_images_html5.html | 32 | ||||
| -rw-r--r-- | docutils/test/functional/input/embed_images.txt | 25 | ||||
| -rw-r--r-- | docutils/test/functional/tests/embed_images_html5.py | 14 |
9 files changed, 145 insertions, 23 deletions
diff --git a/docutils/HISTORY.txt b/docutils/HISTORY.txt index 31507c122..d20229244 100644 --- a/docutils/HISTORY.txt +++ b/docutils/HISTORY.txt @@ -25,6 +25,7 @@ Changes Since 0.16 - Installing with ``setup.py`` now requires ``setuptools``. Alternatively, install with `pip`_ (or "manually"). - Apply patch for bug #399 Fixes in Korean translation. + - Implement feature request #40 `Option to embed images as data URI`. * docutils/MANIFEST.in diff --git a/docutils/RELEASE-NOTES.txt b/docutils/RELEASE-NOTES.txt index c405c0d9a..4760b2440 100644 --- a/docutils/RELEASE-NOTES.txt +++ b/docutils/RELEASE-NOTES.txt @@ -78,6 +78,8 @@ Release 0.17 * Installing with ``setup.py`` now requires setuptools_. Alternatively, install with pip_. + +* HTML writers: new option to embed images. * HTML5 writer: @@ -101,8 +103,6 @@ Release 0.17 .. _initial_header_level: docs/user/config.html#initial-header-level __ https://stackoverflow.com/questions/39547412/same-font-size-for-h1-and-h2-in-article - - * LaTeX writer: - New configuration setting `legacy_class_functions`_. diff --git a/docutils/docs/user/config.txt b/docutils/docs/user/config.txt index 2ca4c30c1..641fd977a 100644 --- a/docutils/docs/user/config.txt +++ b/docutils/docs/user/config.txt @@ -956,6 +956,21 @@ attributes (values "compact" and "open") in the document. Default: enabled (True). Options: ``--compact-field-lists, --no-compact-field-lists``. +embed_images +~~~~~~~~~~~~ + +Embed images in the output HTML file. If the image can be read from +the local file system and its MIME type can be determined, it is +base64_ encoded and included as a `data URI`_. + +Default: disabled (False). +Options: ``--embed-images``, ``--link-images`` + +New in Docutils 0.17. + +.. _base64: https://en.wikipedia.org/wiki/Base64 +.. _data URI: https://en.wikipedia.org/wiki/Data_URI_scheme + .. _embed_stylesheet [html writers]: @@ -1033,7 +1048,7 @@ the output document. Supported values are (case insensitive): * It is recommended to install__ the MathJax library on the same server as the rest of the deployed site files. - __ http://docs.mathjax.org/en/latest/installation.html + __ https://www.mathjax.org/#installnow Example: Install the library at the top level of the web server’s hierarchy in the directory ``MathJax`` and set:: @@ -1046,13 +1061,14 @@ the output document. Supported values are (case insensitive): Downside: Downloads JavaScript code from a third-party site --- opens the door to cross-site scripting attacs! - Example: MathJax.org recommends ``cdnjs.cloudflare.com``:: + Example: MathJax `getting started`__ documentation uses:: math-output: mathjax - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js + https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js - See https://cdnjs.com/about and https://www.cloudflare.com/terms/ for - details and terms of use. + See https://www.jsdelivr.com/ for details and terms of use. + + __ https://www.mathjax.org/#gettingstarted * Use a local MathJax installation on the *client* machine, e.g.:: diff --git a/docutils/docutils/writers/_html_base.py b/docutils/docutils/writers/_html_base.py index 4352eb346..c7ff96e81 100644 --- a/docutils/docutils/writers/_html_base.py +++ b/docutils/docutils/writers/_html_base.py @@ -17,9 +17,11 @@ """common definitions for Docutils HTML writers""" -import sys -import os.path +import base64 +import mimetypes +import os, os.path import re +import sys try: # check for the Python Imaging Library import PIL.Image @@ -905,19 +907,10 @@ class HTMLTranslator(nodes.NodeVisitor): self.header.extend(header) del self.body[start:] - # Image types to place in an <object> element - object_image_types = {'.swf': 'application/x-shockwave-flash'} - def visit_image(self, node): atts = {} uri = node['uri'] - ext = os.path.splitext(uri)[1].lower() - if ext in self.object_image_types: - atts['data'] = uri - atts['type'] = self.object_image_types[ext] - else: - atts['src'] = uri - atts['alt'] = node.get('alt', uri) + mimetype = mimetypes.guess_type(uri)[0] # image size if 'width' in node: atts['width'] = node['width'] @@ -966,12 +959,35 @@ class HTMLTranslator(nodes.NodeVisitor): suffix = '' if 'align' in node: atts['class'] = 'align-%s' % node['align'] - if ext in self.object_image_types: + # Embed image file (embedded SVG or data URI): + if self.settings.embed_images or ('embed' in node): + err_msg = '' + if not mimetype: + err_msg = 'unknown MIME type for "%s"' % uri + if not self.settings.file_insertion_enabled: + err_msg = 'file insertion disabled.' + try: + with open(url2pathname(uri), 'rb') as imagefile: + imagedata = imagefile.read() + except IOError as err: + err_msg = str(err) + if not err_msg: + # TODO (test mimetype for SVG and insert directly) + data64 = base64.b64encode(imagedata).decode() + uri = u'data:%s;base64,%s' % (mimetype, data64) + else: + # raise NotImplementedError(os.getcwd() + err_msg) + self.document.reporter.error("Cannot embed image\n "+err_msg) + + if mimetype == 'application/x-shockwave-flash': + atts['type'] = mimetype # do NOT use an empty tag: incorrect rendering in browsers - self.body.append(self.starttag(node, 'object', '', **atts) + - node.get('alt', uri) + '</object>' + suffix) + tag = (self.starttag(node, 'object', '', data=uri, **atts) + + node.get('alt', uri) + '</object>' + suffix) else: - self.body.append(self.emptytag(node, 'img', suffix, **atts)) + atts['alt'] = node.get('alt', node['uri']) + tag = self.emptytag(node, 'img', suffix, src=uri, **atts) + self.body.append(tag) def depart_image(self, node): pass diff --git a/docutils/docutils/writers/html4css1/__init__.py b/docutils/docutils/writers/html4css1/__init__.py index b3af3d996..f5dfd540c 100644 --- a/docutils/docutils/writers/html4css1/__init__.py +++ b/docutils/docutils/writers/html4css1/__init__.py @@ -124,6 +124,15 @@ class Writer(writers._html_base.Writer): ('Disable compact simple field lists.', ['--no-compact-field-lists'], {'dest': 'compact_field_lists', 'action': 'store_false'}), + ('Embed images in the output HTML file, if the image ' + 'files are accessible during processing.', + ['--embed-images'], + {'default': 0, 'action': 'store_true', + 'validator': frontend.validate_boolean}), + ('Link to images in the output HTML file. ' + 'This is the default.', + ['--link-images'], + {'dest': 'embed_images', 'action': 'store_false'}), ('Added to standard table classes. ' 'Defined styles: "borderless". Default: ""', ['--table-style'], diff --git a/docutils/docutils/writers/html5_polyglot/__init__.py b/docutils/docutils/writers/html5_polyglot/__init__.py index e98dba121..311623df0 100644 --- a/docutils/docutils/writers/html5_polyglot/__init__.py +++ b/docutils/docutils/writers/html5_polyglot/__init__.py @@ -114,6 +114,15 @@ class Writer(writers._html_base.Writer): ('Disable compact simple field lists.', ['--no-compact-field-lists'], {'dest': 'compact_field_lists', 'action': 'store_false'}), + ('Embed images in the output HTML file, if the image ' + 'files are accessible during processing.', + ['--embed-images'], + {'default': 0, 'action': 'store_true', + 'validator': frontend.validate_boolean}), + ('Link to images in the output HTML file. ' + 'This is the default.', + ['--link-images'], + {'dest': 'embed_images', 'action': 'store_false'}), ('Added to standard table classes. ' 'Defined styles: borderless, booktabs, ' 'align-left, align-center, align-right, colwidths-auto. ' diff --git a/docutils/test/functional/expected/embed_images_html5.html b/docutils/test/functional/expected/embed_images_html5.html new file mode 100644 index 000000000..a8bcef150 --- /dev/null +++ b/docutils/test/functional/expected/embed_images_html5.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta charset="utf-8"/> +<meta name="generator" content="Docutils 0.17b.dev: http://docutils.sourceforge.net/" /> +<title>Embedded Images</title> +<link rel="stylesheet" href="../../../docutils/writers/html5_polyglot/minimal.css" type="text/css" /> +<link rel="stylesheet" href="../../../docutils/writers/html5_polyglot/plain.css" type="text/css" /> +</head> +<body> +<main id="embedded-images"> +<h1 class="title">Embedded Images</h1> + +<p>The “embed” flag tells Docutils that it should +try to embed the image in the output document.</p> +<p>If the image can be read from the local file system, it is <a class="reference external" href="https://en.wikipedia.org/wiki/Base64">base64</a> +encoded and included as a <a class="reference external" href="https://en.wikipedia.org/wiki/Data_URI_scheme">data URI</a>. +In future, SVG images may be directly inserted into HTML5.</p> +<blockquote> +<figure class="align-center"> +<img alt="biohazard" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICBzb2RpcG9kaTpkb2NuYW1lPSJiaW9oYXphcmQuc3ZnIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ3IHIyMjU4MyIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaWQ9InN2ZzI0MTU5IgogICBoZWlnaHQ9IjQ4IgogICB3aWR0aD0iNDgiCiAgIHZlcnNpb249IjEuMCI+CiAgPHRpdGxlCiAgICAgaWQ9InRpdGxlMjgzNyI+QmlvaGF6YXJkPC90aXRsZT4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE3Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT5CaW9oYXphcmQ8L2RjOnRpdGxlPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9wdWJsaWNkb21haW4vIiAvPgogICAgICAgIDxkYzpkZXNjcmlwdGlvbj5TdGFuZGFsb25lIGJpb2hhemFyZCBzeW1ib2wsIHdpdGggbm8gYm9yZGVyLCBiYWNrZ3JvdW5kIG9yIGRlc2NyaXB0aXZlIHRleHQuPC9kYzpkZXNjcmlwdGlvbj4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlNpbHNvcjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj48L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnNvdXJjZT48L2RjOnNvdXJjZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL2RlLndpa2lwZWRpYS5vcmcvd2lraS9EYXRlaTpCaW9oYXphcmRfc3ltYm9sLnN2ZzwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPldpa2lwZWRpYTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkJhc3RpcXVlLCBBbmR1eCwgTWFyaWFuU2lnbGVyLCBHTTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgIDwvY2M6V29yaz4KICAgICAgPGNjOkxpY2Vuc2UKICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9wdWJsaWNkb21haW4vIj4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjUmVwcm9kdWN0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNEaXN0cmlidXRpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI0Rlcml2YXRpdmVXb3JrcyIgLz4KICAgICAgPC9jYzpMaWNlbnNlPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczUiPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDE3OC4xMzEyNiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSIzNzYuNDM3NSA6IDE3OC4xMzEyNiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMTg4LjIxODc1IDogMTE4Ljc1NDE3IDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MzUiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcyNDE1OSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMzMiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjAiCiAgICAgaW5rc2NhcGU6Y3k9IjIyLjQ1NTQxOCIKICAgICBpbmtzY2FwZTpjeD0iMjIuMTUyNjM5IgogICAgIGlua3NjYXBlOnpvb209IjguOTMxNjY5MyIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3NzEiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSI5OTMiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgaWQ9ImJhc2UiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiIC8+CiAgPHBhdGgKICAgICBpZD0icGF0aDcyMTQiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtkaXNwbGF5OmlubGluZSIKICAgICBkPSJtIDIzLjU4NTE2MywxLjM3Nzc3MSBjIC03LjNlLTUsMS4xZS00IDYuMmUtNSwwLjAwMzkgMCwwLjAwMzkgMC4wMDEzLC0zLjU0ZS00IDAuMDAyNiwtMC4wMDMyIDAuMDAzOSwtMC4wMDM5IC00Ljc4ZS00LDAgLTAuMDAzNCwtMi4zZS01IC0wLjAwMzksMCB6IG0gLTAuMjkzMjg3LDAuMDExNzMgYyAtMC4wMDI3LDMuMzllLTQgLTAuMDA1MSwwLjAwMzIgLTAuMDA3OCwwLjAwMzkgMC4wMTA0NywtNi40N2UtNCAwLjAyMDgsLTAuMDAzMiAwLjAzMTMsLTAuMDAzOSAtMC4wMDI2LDMuMWUtNSAtMC4wMDUzLC0xLjE4ZS00IC0wLjAwNzgsMCAtMC4wMDU3LDIuNmUtNCAtMC4wMTAxNiwtNi45NGUtNCAtMC4wMTU2NCwwIHogbSAxLjQyMzQsMC4wMDc4IGMgMC4wMjA4NSwwLjAwMTYgMC4wNDE3NiwwLjAwMjMgMC4wNjI1NywwLjAwMzkgLTAuMDIwNDcsLTAuMDAxNiAtMC4wNDIwNCwtMC4wMDMyIC0wLjA2MjU3LC0wLjAwMzkgeiBtIDAuMDYyNTcsMC4wMDM5IGMgNS4yNjU5ODcsMC40MTg1NDcgOS40MTI0NTQsNC44MzMyMzQzIDkuNDEyNDU0LDEwLjIwNjI1OCAwLDUuNDcwNzY3IC00LjMwMzU1Myw5LjkzMjc4MSAtOS43MDU3NDMsMTAuMjEwMTgyIGwgMCwyLjA5NjAwNCBjIDEuNDc0ODUyLDAuMjMzMTcgMi42MDQzNzEsMS41MTM5OTMgMi42MDQzNzEsMy4wNTQwNTkgMCwwLjM3NjkzMiAtMC4wNjc4NiwwLjczNzM5MyAtMC4xOTE2MTQsMS4wNzE0NjUgbCAxLjkxNjEyNSwxLjEwNjY1MyBjIDIuOTYxMTgsLTQuNDczMDQyIDguOTM1NDg1LC01LjkzMjU4NiAxMy42NDM1NDMsLTMuMjE0Mzk1IDQuNjk2ODU4LDIuNzExNzM5IDYuNDMxMTE3LDguNTk0NzA2IDQuMDYyOTUxLDEzLjM4OTM3MyAzLjI1MDEyLC02LjMyNTkyNyAwLjk5MDAzNywtMTQuMTY2NTg2IC01LjIzNjA3OSwtMTcuNzYxMjQ2IC0xLjU1Nzc4MywtMC44OTkzODMgLTMuMjE3NTYsLTEuNDQ3MzAyIC00Ljg5NTg4MywtMS42NzM2NjYgMC42NDI0MjYsLTEuNTY2Mjk5IDAuOTk3MTU5LC0zLjI4MTM4NCAwLjk5NzE1OSwtNS4wNzk2NzggMCwtNy4xMzY5NDk3IC01LjU3NjYzOSwtMTIuOTc5NTM2IC0xMi42MDcyODQsLTEzLjQwNTAwOSB6IG0gLTEuNzE2NjgyLDAuMDA3OCBjIC02Ljk5NTUwNywwLjQ2MjA0NyAtMTIuNTM2ODk3LDYuMjg1NDY5MyAtMTIuNTM2ODk3LDEzLjM5NzE4NyAwLDEuNzQ3MSAwLjMzMzkyLDMuNDE2ODI3IDAuOTQyNDE4LDQuOTQ2NzA5IEMgOS44MzgyOTkyLDE5Ljk5MTQ5OCA4LjIyNDA3MjIsMjAuNTMzOTg5IDYuNzExNTc5MiwyMS40MDcyMiAwLjUyNzE0NTU1LDI0Ljk3NzgwNiAtMS43MzgzMjk1LDMyLjczNTk4OSAxLjQxNjg0MzksMzkuMDM5NDM0IC0wLjg2MTIxMjg1LDM0LjI2NzczIDAuODg1Nzg1ODUsMjguNDYzNjYzIDUuNTQyMzU1MiwyNS43NzUxODYgMTAuMjgwMTc5LDIzLjAzOTgxNCAxNi4yOTU0MTYsMjQuNTM1ODkzIDE5LjIzNjczMSwyOS4wNzU2MSBsIDEuODQ5NjUzLC0xLjA2NzU1IGMgLTAuMTE2MjQ1LC0wLjMyNDk1OCAtMC4xNzU5NjgsLTAuNjc1NDIyIC0wLjE3NTk2OCwtMS4wNDAxNzcgMCwtMS40NzQ2ODQgMS4wMzM5MDQsLTIuNzA4MSAyLjQxNjY1MywtMy4wMTQ5NjMgbCAwLC0yLjEzODk5OCBjIC01LjM1NDM2MSwtMC4zMjc5NTkgLTkuNjA0MDUzLC00Ljc2OTg3OCAtOS42MDQwNTMsLTEwLjIwNjI4NCAwLC01LjM0ODQzNzcgNC4xMDY1MTEsLTkuNzQ1NTgxIDkuMzM4MTQxLC0xMC4xOTg0MzYgeiBtIDAuNTk4MywxMi44NTc1MzkgYyAtMi43MDI1MTMsMC4wNjIxNSAtNS4xOTM5LDAuOTgyMTk5IC03LjIzODIzOSwyLjQ3OTIzOSAwLjE2MzMxOSwwLjI0MTY3OCAwLjMzODgsMC40NzU1ODEgMC41MjM5OTUsMC42OTk5NjggMC4xODUyMTEsMC4yMjQzNzkgMC4zODEwMTgsMC40Mzk2NiAwLjU4NjU3MiwwLjY0NTIyIDAuMjA1NTUyLDAuMjA1NTUyIDAuNDIwODM4LDAuNDAxMzY4IDAuNjQ1MjMzLDAuNTg2NTY1IDAuMTY0OTc0LDAuMTM2MTY5IDAuMzQxNzMsMC4yNTg3NjMgMC41MTYxNzQsMC4zODMyMjYgMS41MDkwNDEsLTAuOTkwODAxIDMuMzE2MTU3LC0xLjU3MTk5MyA1LjI2MzQ2NiwtMS41NzE5OTMgMS45NDcyODYsLThlLTYgMy43NTA1MDYsMC41ODExOTIgNS4yNTk1NDUsMS41NzE5OTMgMC4xNzQ0NDYsLTAuMTI0NDYzIDAuMzUxMTkzLC0wLjI0NzA1NyAwLjUxNjE3NiwtMC4zODMyMjYgMC4yMjQzOSwtMC4xODUxOTcgMC40Mzk2NzMsLTAuMzgxMDEzIDAuNjQ1MjE5LC0wLjU4NjU2NSAwLjIwNTU2NywtMC4yMDU1NiAwLjQwMTM3NSwtMC40MjA4NDEgMC41ODY1NzgsLTAuNjQ1MjIgMC4xODUxOTUsLTAuMjI0Mzg3IDAuMzYwNjY5LC0wLjQ1ODI5IDAuNTIzOTk4LC0wLjY5OTk2OCAtMi4xMTgyMjgsLTEuNTUxMTQzIC00LjcxNjA1MSwtMi40NzkyMzkgLTcuNTMxNTE2LC0yLjQ3OTIzOSAtMC4wNjU5OSwwIC0wLjEzMzY4OSwtNy44OGUtNCAtMC4xOTk0NDUsMCAtMC4wMzIxLDUuMDRlLTQgLTAuMDY1NzIsLTcuMzNlLTQgLTAuMDk3NzUsMCB6IG0gLTEyLjMxNzkxLDExLjI3Nzg2NyBjIC0wLjI4NDIyMywyLjYxMDAwMyAwLjIxMTE5OSw1LjMyMzk3MSAxLjYxODkyNCw3Ljc2MjI0IDEuNDA3NzM0LDIuNDM4MjUyIDMuNTEwMTU4LDQuMjI4MDU2IDUuOTEyNTkyLDUuMjg2OTE2IDAuMTI3NjQ4LC0wLjI2MjI4NCAwLjI0MjM5NCwtMC41MzI5NjcgMC4zNDQxMjEsLTAuODA1NTU2IDAuMTAxNzMxLC0wLjI3MjU3MyAwLjE5MDY3NiwtMC41NDgyMDkgMC4yNjU5MDIsLTAuODI4OTk5IDAuMDc1MjUsLTAuMjgwNzk3IDAuMTM5NTA0LC0wLjU2NTU2NCAwLjE4NzcwNCwtMC44NTI0ODEgMC4wMzU0NSwtMC4yMTA5NjQgMC4wNTM3NCwtMC40MjQxMSAwLjA3NDMxLC0wLjYzNzQxNSAtMS42MTI1ODgsLTAuODExNDYzIC0zLjAxODkyNSwtMi4wODcxNTcgLTMuOTkyNTc0LC0zLjc3MzU3OCAtMC45NzM2NTIsLTEuNjg2NDEyIC0xLjM3NDQzNiwtMy41MzkzOTkgLTEuMjcwODk5LC01LjM0MTY2NCAtMC4xOTQ5OTUsLTAuMDg4ODQgLTAuMzkwMDYyLC0wLjE3OTM5MSAtMC41OTA0ODIsLTAuMjU0MTg3IC0wLjI3MjU3NywtMC4xMDE3MSAtMC41NDgyMTYsLTAuMTkwNjY0IC0wLjgyOTAxMiwtMC4yNjU5MDkgLTAuMjgwNzk0LC0wLjA3NTIzIC0wLjU2NTU1MiwtMC4xMzU1ODUgLTAuODUyNDczLC0wLjE4Mzc4NiAtMC4yODY5MTksLTAuMDQ4MjEgLTAuNTc3MTU1LC0wLjA4NDk5IC0wLjg2ODExOSwtMC4xMDU1ODIgeiBtIDI1LjMxNjIzNCwwLjE1MjQ5OCBjIC0wLjI5MDk3NiwwLjAyMDY0IC0wLjU4MTE5NiwwLjA1NzQzIC0wLjg2ODExOCwwLjEwNTU5MiAtMC4yODY5MjQsMC4wNDgyMSAtMC41NzE2OTQsMC4xMDg1NTEgLTAuODUyNDg5LDAuMTgzNzk2IC0wLjI4MDc4LDAuMDc1MjMgLTAuNTYwMzMxLDAuMTY0MTg4IC0wLjgzMjkxNywwLjI2NTkxNiAtMC4yMDA0MTYsMC4wNzQ3NSAtMC4zOTE1NjgsMC4xNjkyMzggLTAuNTg2NTYyLDAuMjU4MDc5IDAuMTAzNTI5LDEuODAyMjU3IC0wLjI5NzI1NCwzLjY1NTI2OCAtMS4yNzA5MDQsNS4zNDE2NzIgLTAuOTczNjQ0LDEuNjg2NDA1IC0yLjM3OTk4NywyLjk1ODE5OCAtMy45OTI1NTYsMy43Njk2NjMgMC4wMjA1NiwwLjIxMzI5NiAwLjAzODg1LDAuNDI2NDUgMC4wNzQyOSwwLjYzNzQwNiAwLjA0ODIsMC4yODY5MjUgMC4xMDg1NDQsMC41NzE2ODQgMC4xODM3ODcsMC44NTI0OSAwLjA3NTI0LDAuMjgwNzg5IDAuMTY0MTk1LDAuNTYwMzQ5IDAuMjY1OTE3LDAuODMyOTEzIDAuMTAxNzEsMC4yNzI1OTggMC4yMTY0OCwwLjUzOTM1NyAwLjM0NDExNSwwLjgwMTY1IDIuNDAyNDQxLC0xLjA1ODg3IDQuNTA0ODYzLC0yLjg0NDc1NiA1LjkxMjU5LC01LjI4MzAxOCAxLjQwNzc0OSwtMi40MzgyNjggMS45MDcwNTgsLTUuMTU2MTUxIDEuNjIyODQzLC03Ljc2NjE1NSB6IG0gLTE0Ljk4NDgzNiwzLjMwMDQyNCAtMS44NjEzNzYsMS4wNzkyODYgYyAyLjM5MzE3NSw0LjgwMDk3IDAuNjcyNDgsMTAuNzAyNDQ4IC00LjAzNTU2NCwxMy40MjA2NTQgLTQuNjg0ODc2LDIuNzA0ODA3IC0xMC42Mjg1NDE4LDEuMjgxNDM3IC0xMy42MDQ0NTM4LC0zLjE0MDA4NyAzLjg2MTY0NSw1Ljk1MDI4NiAxMS43NTg0Njk4LDcuOTAwODQyIDE3Ljk3MjQxMDgsNC4zMTMyMSAxLjUwNTI3MSwtMC44NjkwNzEgMi43NzUwNjIsLTEuOTg5NDMxIDMuNzkzMTMzLC0zLjI3MzAyNiAxLjAzODA2MiwxLjM0OTMyMyAyLjM1MTg2NCwyLjUyMTE3OCAzLjkxODI2NiwzLjQyNTUzOSA2LjIyMDkzMiwzLjU5MTY1MiAxNC4xMjcyNjMsMS42MzMxNyAxNy45ODQxNSwtNC4zMzI3NjggLTIuOTcwNDAxLDQuNDQwNjU4IC04LjkyMjcxNSw1Ljg3NzIzMSAtMTMuNjE2MTc0LDMuMTY3NDYxIC00LjczNzgxOCwtMi43MzUzODggLTYuNDQ5NTExLC04LjY5MzQ2NSAtMy45ODg2NTksLTEzLjUxMDU5IEwgMjYuMjk5MDIsMjkuMDI4NjE3IGMgLTAuNTY1NjkyLDAuNjI5ODQ0IC0xLjM4Njc2OCwxLjAyODQ0OCAtMi4yOTkzNDgsMS4wMjg0NDggLTAuOTI3NTc3LDAgLTEuNzYwMjk5LC0wLjQxMTc5MSAtMi4zMjY3MiwtMS4wNTk3MzYgeiIgLz4KPC9zdmc+Cg==" /> +<figcaption> +<p>SVG image embedded in a figure.</p> +</figcaption> +</figure> +</blockquote> +<p>Embedded inline image <img alt="inline-embedded" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABGdBTUEAANkE3LLaAgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAZQTFRF////AAAAVcLTfgAAAAF0Uk5TAEDm2GYAAAA2SURBVHicYmBRYOAQYJCQYJC+wSBjAUL2fxjq6hgueTNM7AQh3g0MzAdAiP0BUBYAAAD//wMA4pkLDrFBDzUAAAAASUVORK5CYII=" style="height: 0.8em;" /> scaled to a height of 0.8 em.</p> +<blockquote> +</blockquote> +</main> +</body> +</html> diff --git a/docutils/test/functional/input/embed_images.txt b/docutils/test/functional/input/embed_images.txt new file mode 100644 index 000000000..bd42e35aa --- /dev/null +++ b/docutils/test/functional/input/embed_images.txt @@ -0,0 +1,25 @@ +Embedded Images +--------------- + +The "embed" flag tells Docutils that it should +try to embed the image in the output document. + +If the image can be read from the local file system, it is base64_ +encoded and included as a `data URI`_. +In future, SVG images may be directly inserted into HTML5. + + .. figure:: ../docs/user/rst/images/biohazard.svg + :alt: biohazard + :align: center + + SVG image embedded in a figure. + + +Embedded inline image |inline-embedded| scaled to a height of 0.8 em. + + .. |inline-embedded| image:: ../docs/user/rst/images/biohazard.png + :height: 0.8 em + +.. _base64: https://en.wikipedia.org/wiki/Base64 +.. _data URI: https://en.wikipedia.org/wiki/Data_URI_scheme + diff --git a/docutils/test/functional/tests/embed_images_html5.py b/docutils/test/functional/tests/embed_images_html5.py new file mode 100644 index 000000000..3adac07a7 --- /dev/null +++ b/docutils/test/functional/tests/embed_images_html5.py @@ -0,0 +1,14 @@ +with open('functional/tests/_standalone_rst_defaults.py') as _f: + exec(_f.read()) + +# Source and destination file names. +test_source = "embed_images.txt" +test_destination = "embed_images_html5.html" + +# Keyword parameters passed to publish_file. +writer_name = "html5" + +# Settings: +settings_overrides['smart_quotes'] = 'yes' +settings_overrides['embed_images'] = 'yes' + |
