PLUGINS += ['m.htmlsanity', 'm.images']
M_IMAGES_REQUIRE_ALT_TEXT = False
-To use the image grid feature (see below), in addition you need the
-`Pillow <https://pypi.python.org/pypi/Pillow>`_ library installed. Get it via
-``pip`` or your distribution package manager:
+To use the image grid feature and image/figure :rst:`:scale:` option (see
+below), in addition you need the `Pillow <https://pypi.python.org/pypi/Pillow>`_
+library installed. Get it via ``pip`` or your distribution package manager:
.. code:: sh
- Adds :css:`.m-image` / :css:`.m-figure` CSS classes to them so they have
the expected m.css `image <{filename}/css/components.rst#images>`_ and
`figure <{filename}/css/components.rst#figures>`_ styling.
-- Removes the :rst:`:align:`, :rst:`:figwidth:` and :rst:`:scale:` options,
- as this is better handled by m.css features.
+- Removes the :rst:`:align:` option, as this is better handled by m.css
+ features and removes the redundant :rst:`:figwidth:` option (use
+ :rst:`:width:` instead).
+- The original :rst:`:width:`, :rst:`:height:` and :rst:`:scale:` options are
+ supported, only converted to a CSS ``style`` attribute instead of using
+ deprecated HTML attributes. The width/height options take CSS units, the
+ scale takes a percentage.
- To maintain accessibility easier, makes it possible to enforce :rst:`:alt:`
text for every image and figure by setting :py:`M_IMAGES_REQUIRE_ALT_TEXT`
to :py:`True`.
def depart_abbreviation(self, node):
self.body.append('</abbr>')
- # Remove useless cruft from images, such as width, height, scale; don't put
- # URI in alt text.
+ # Convert outdated width/height attributes to CSS styles, handle the scale
+ # directly inside m.images; don't put URI in alt text.
def visit_image(self, node):
atts = {}
uri = node['uri']
else:
atts['src'] = uri
if 'alt' in node: atts['alt'] = node['alt']
+ style = []
+ if node.get('width'):
+ style += ['width: {}'.format(node['width'])]
+ if node.get('height'):
+ style += ['height: {}'.format(node['height'])]
+ if style:
+ atts['style'] = '; '.join(style)
if (isinstance(node.parent, nodes.TextElement) or
(isinstance(node.parent, nodes.reference) and
not isinstance(node.parent.parent, nodes.TextElement))):
atts = {}
if node.get('id'):
atts['ids'] = [node['id']]
+ style = []
if node.get('width'):
- atts['style'] = 'width: %s' % node['width']
+ style += ['width: {}'.format(node['width'])]
+ if style:
+ atts['style'] = '; '.join(style)
self.body.append(self.starttag(node, 'figure', **atts))
def depart_figure(self, node):
from pelican import StaticGenerator
# If Pillow is not available, it's not an error unless one uses the image grid
-# functionality
+# functionality (or :scale: option for Image)
try:
import PIL.Image
import PIL.ExifTags
Copy of docutils.parsers.rst.directives.Image with:
- - the align, scale, width, height options removed (handled better by
- m.css)
+ - the align option removed (handled better by m.css)
+ - moved the implementation of scale here instead of it being handled in
+ the HTML writer
- .m-image CSS class added
- adding a outer container for clickable image to make the clickable area
cover only the image
final_argument_whitespace = True
option_spec = {'alt': directives.unchanged_required,
'name': directives.unchanged,
+ 'height': directives.length_or_unitless,
+ 'width': directives.length_or_percentage_or_unitless,
+ 'scale': directives.percentage,
'class': directives.class_option,
'target': directives.unchanged_required}
messages.append(data) # data is a system message
del self.options['target']
+ width = None
+ height = None
+ # If scaling requested, open the files and calculate the scaled size
+ # Support both {filename} (3.7.1) and {static} (3.8) placeholders. In
+ # all cases use only width and not both so the max-width can correctly
+ # scale the image down on smaller screen sizes.
+ # TODO: implement ratio-preserving scaling to avoid jumps on load using
+ # the margin-bottom hack
+ if 'scale' in self.options:
+ file = os.path.join(os.getcwd(), settings['PATH'])
+ absuri = reference.format(filename=file, static=file)
+ im = PIL.Image.open(absuri)
+ width = "{}px".format(int(im.width*self.options['scale']/100.0))
+ elif 'width' in self.options:
+ width = self.options['width']
+ elif 'height' in self.options:
+ height = self.options['height'] # TODO: convert to width instead?
+
# Remove the classes from the image element, will be added either to it
# or to the wrapping element later
set_classes(self.options)
classes = self.options.get('classes', [])
if 'classes' in self.options: del self.options['classes']
- image_node = nodes.image(self.block_text, **self.options)
+ if 'width' in self.options: del self.options['width']
+ if 'height' in self.options: del self.options['height']
+ image_node = nodes.image(self.block_text, width=width, height=height, **self.options)
if not 'alt' in self.options and settings['M_IMAGES_REQUIRE_ALT_TEXT']:
error = self.state_machine.reporter.error(
Copy of docutils.parsers.rst.directives.Figure with:
- - the align, figwidth options removed (handled better by m.css)
+ - the align option removed (handled better by m.css)
+ - the redundant figwidth option removed (use width/scale/height from the
+ Image directive instead)
- .m-figure CSS class added
"""
<div class="m-image m-fullwidth">
<a href="./ship.jpg"><img src="./ship.jpg" /></a>
</div>
+<p>Image with custom width, height and scale (scale gets picked):</p>
+<img class="m-image" src="./ship.jpg" style="width: 384px" />
+<p>Image with custom width and height (width gets picked):</p>
+<img class="m-image" src="./ship.jpg" style="width: 300px" />
+<p>Image with custom height:</p>
+<img class="m-image" src="./ship.jpg" style="height: 100px" />
<p>Figure:</p>
<figure class="m-figure">
<img src="./ship.jpg" />
<span>
Yes.</span>
</figure>
-<p>Figure with link and only a caption:</p>
+<p>Figure with link, scale and only a caption:</p>
<figure class="m-figure">
-<a href="./ship.jpg"><img src="./ship.jpg" /></a>
+<a href="./ship.jpg"><img src="./ship.jpg" style="width: 568px" /></a>
<figcaption>A Ship</figcaption>
</figure>
<p>Figure with link and class on top:</p>
<a href="./ship.jpg"><img src="./ship.jpg" /></a>
<figcaption>A Ship</figcaption>
</figure>
+<p>Figure with a width:</p>
+<figure class="m-figure">
+<img src="./ship.jpg" style="width: 250px" />
+<figcaption>A Ship</figcaption>
+</figure>
+<p>Figure with a height:</p>
+<figure class="m-figure">
+<a href="./ship.jpg"><img src="./ship.jpg" style="height: 200px" /></a>
+<figcaption>A Ship</figcaption>
+</figure>
<p>Image grid:</p>
<div class="m-imagegrid m-container-inflate">
<div>
:target: {static}/ship.jpg
:class: m-fullwidth
+Image with custom width, height and scale (scale gets picked):
+
+.. image:: {static}/ship.jpg
+ :width: 4000px
+ :height: 8000px
+ :scale: 25%
+
+Image with custom width and height (width gets picked):
+
+.. image:: {static}/ship.jpg
+ :width: 300px
+ :height: 8000px
+
+Image with custom height:
+
+.. image:: {static}/ship.jpg
+ :height: 100px
+
Figure:
.. figure:: {static}/ship.jpg
Yes.
-Figure with link and only a caption:
+Figure with link, scale and only a caption:
.. figure:: {static}/ship.jpg
:target: {static}/ship.jpg
+ :scale: 37%
A Ship
A Ship
+Figure with a width:
+
+.. figure:: {static}/ship.jpg
+ :width: 250px
+
+ A Ship
+
+Figure with a height:
+
+.. figure:: {static}/ship.jpg
+ :target: {static}/ship.jpg
+ :height: 200px
+
+ A Ship
+
Image grid:
.. image-grid::