Django, reStructuredText and image thumbnails

August 21, 2012 - IT

I use reStructuredText at my blog. I have decided to write my own simple directive for generating image thumbnails and returning html tags. I'm using sorl.thumbnail for this.

import os
from docutils import nodes
from docutils.parsers.rst import directives, Directive
from sorl.thumbnail import get_thumbnail
from project.settings import MEDIA_ROOT, MEDIA_URL

class Thumb(Directive):

    def align(argument):
        """Conversion function for the "align" option."""
        return directives.choice(argument, ('left', 'center', 'right'))

    required_arguments = 1
    optional_arguments = 0
    final_argument_whitespace = True
    option_spec = {
        'alt': directives.unchanged,
        'height': directives.length_or_unitless,
        'width': directives.length_or_percentage_or_unitless,
        'align': align

    def run(self):
        alt = self.options.get('alt')
        img = self.arguments[0].strip()
        # Default parameters
        width = 500
        height = ''
        align = 'center'

        if 'width' in self.options:
            width = self.options['width']

        if 'height' in self.options:
            height = self.options['height']

        if 'align' in self.options:
            align = self.options['align']

        # Get image path.
        if any(x in img for x in ['http', 'www']):
            # Received path like /media/test/1.jpg
            img_path = os.path.join(MEDIA_ROOT, img.replace(MEDIA_URL, ''))
            # Received url like
            project_root = os.path.abspath(os.path.dirname(__file__))
            img_path = os.path.realpath(project_root + img)

        if width and height:
            size = '{0}x{1}'.format(width, height)
        elif not width and height:
            size = 'x{0}'.format(height)
            size = str(width)

        img_thumb = get_thumbnail(img_path, size, upscale=False, quality=99)

        html = u'<a href="{0}" title="{1}" class="align-{2}">' \
            u'<img src="{3}" alt="{4}" /></a>'.format(
            img, alt, align, img_thumb.url, alt

        return [nodes.raw('', html, format='html')]

directives.register_directive('thumb', Thumb)

Now I can use this in RST code.

.. thumb:: /media/test/1.jpg
    :alt: Test

.. thumb::
    :alt: Test

.. thumb:: /media/test/1.jpg
    :alt: Test
    :width: 300
    :height: 300

.. thumb:: /media/test/1.jpg
    :alt: Test
    :height: 200