From: Vladimír Vondruš Date: Fri, 22 Feb 2019 19:40:44 +0000 (+0100) Subject: m.images: support width/height/scale options. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=cbed319113bb6ed60bfb0b23b6e475dff4ede015;p=blog.git m.images: support width/height/scale options. --- diff --git a/doc/plugins/images.rst b/doc/plugins/images.rst index fc33ace8..b5900d98 100644 --- a/doc/plugins/images.rst +++ b/doc/plugins/images.rst @@ -58,9 +58,9 @@ presence of `m.htmlsanity <{filename}/plugins/htmlsanity.rst>`_. 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 `_ 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 `_ +library installed. Get it via ``pip`` or your distribution package manager: .. code:: sh @@ -77,8 +77,13 @@ directives and: - 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`. diff --git a/pelican-plugins/m/htmlsanity.py b/pelican-plugins/m/htmlsanity.py index 144b4fbe..86af90a7 100644 --- a/pelican-plugins/m/htmlsanity.py +++ b/pelican-plugins/m/htmlsanity.py @@ -263,8 +263,8 @@ class SaneHtmlTranslator(HTMLTranslator): def depart_abbreviation(self, node): self.body.append('') - # 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'] @@ -275,6 +275,13 @@ class SaneHtmlTranslator(HTMLTranslator): 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))): @@ -412,8 +419,11 @@ class SaneHtmlTranslator(HTMLTranslator): 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): diff --git a/pelican-plugins/m/images.py b/pelican-plugins/m/images.py index 46224839..e6c834d3 100644 --- a/pelican-plugins/m/images.py +++ b/pelican-plugins/m/images.py @@ -33,7 +33,7 @@ from pelican import signals 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 @@ -47,8 +47,9 @@ class Image(Directive): 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 @@ -60,6 +61,9 @@ class Image(Directive): 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} @@ -89,12 +93,32 @@ class Image(Directive): 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( @@ -123,7 +147,9 @@ class Figure(Image): 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 """ diff --git a/pelican-plugins/m/test/images/page.html b/pelican-plugins/m/test/images/page.html index 005d09cc..3e16d9fa 100644 --- a/pelican-plugins/m/test/images/page.html +++ b/pelican-plugins/m/test/images/page.html @@ -35,6 +35,12 @@
+

Image with custom width, height and scale (scale gets picked):

+ +

Image with custom width and height (width gets picked):

+ +

Image with custom height:

+

Figure:

@@ -42,9 +48,9 @@ Yes.
-

Figure with link and only a caption:

+

Figure with link, scale and only a caption:

- +
A Ship

Figure with link and class on top:

@@ -52,6 +58,16 @@ Yes.
A Ship
+

Figure with a width:

+
+ +
A Ship
+
+

Figure with a height:

+
+ +
A Ship
+

Image grid:

diff --git a/pelican-plugins/m/test/images/page.rst b/pelican-plugins/m/test/images/page.rst index 3dbbf5b5..1aea1188 100644 --- a/pelican-plugins/m/test/images/page.rst +++ b/pelican-plugins/m/test/images/page.rst @@ -24,6 +24,24 @@ Image with link, class on top: :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 @@ -32,10 +50,11 @@ Figure: 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 @@ -47,6 +66,21 @@ Figure with link and class on top: 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::