Dynamic image size loading in Pelican using javascript



I don't really know what to call this. But for the background images, I load the smallest size that fits close enough to the height of the page. Hoping to save bandwidth for mobile users.

This was fun to write since the code was linked from the Pelican settings file, into the template, so the javascript can run properly without me editing multiple files.

I used a plugin for Pelican called thumbnailer. There are many plugins to help you compress your images into different file formats, however this one was standalone and seemed to fit my idea the easiest.

Pelican settings file
PLUGIN_PATHS = ['plugins']
PLUGINS = ['thumbnailer']

IMAGE_PATH = 'images'
THUMBNAIL_DIR = 'thumb'
THUMBNAIL_KEEP_NAME = True
THUMBNAIL_KEEP_TREE = True
THUMBNAIL_SIZES = {
    'tiny': '?x144',
    'smaller': '?x240',
    'small': '?x360',
    'medium': '?x480',
    'large': '?x720',
    'huge': '?x1080'
}

Above, I am telling the plugin 'thumbnailer' to take my 'images' folder and create thumbnail versions of all the images.

The THUMBNAIL_DIR is the root folder for all thumbs.

The THUMBNAIL_KEEP_TREE tells the plugin to keep the same directory structure found inside IMAGE_PATH

The 'key' in THUMBNAIL_SIZES is the name of the sub folder that contains all the images at that size.

The '?' in front of each implies that it will keep the aspect ratio of the original file.

Putting all these together, I can access thumbnail version by changing the root image folder to thumb, and adding the appropriate size key as a prefix. But everything else about the filename stays the same. Here is an example of how the URL shifts

/images/background/cover0.jpg
/thumb/tiny/background/cover0.jpg
/thumb/huge/background/cover0.jpg
Jinja template file
<script type="text/javascript">
  // array of possible images sizes built off config filename
  var imageSizes = [];
  {% for name, dim in THUMBNAIL_SIZES.iteritems() %}
    imageSizes[ {{ loop.index-1 }} ] = {
      name: "{{name}}",
      size:"{{ dim }}",
      width: parseInt("{{dim}}".replace(/x.+/, '')),
      height: parseInt("{{dim}}".replace(/.+x/, ''))
    }
  {% endfor %}
  // sorted largest to smallest so if two sizes match abs, it choses the smaller
  imageSizes.sort(function(a,b) {return (a.height > b.height) ? -1 : ((b.height > a.height) ? 1 : 0);} );

  function imgUrlByHeight(filename, height) {
    var chosenSize = imageSizes[0]; //start at smallest size
    for (var i = 0; i < imageSizes.length; i++){ // redo smallest to calculate abs
      var curSize = imageSizes[i];
      curSize.abs = Math.abs(height - curSize.height);
      if (curSize.abs <= chosenSize.abs) chosenSize = curSize;
    }
    return "url({{ SITEURL }}/{{ THUMBNAIL_DIR}}/" + chosenSize.name + "/" + filename;
  }
</script>

This may be a bit hard to unpack since it's Jinja and JS combined. However I have left the Jinja highlighted. What's important here is near the top.

The for loop through THUMBNAIL_SIZES allows me to build an array in javascript to be used by the rest of the code.

I parse out the value of the key using js function replace since I cannot do this kind of string manipulation in Jinja.

At the bottom I build the URL using the appropriate settings from the Pelican settings file, and thumbnailer options.

Finally

I could use this function anywhere, but it's currently only being used by the background code. I will eventually place it elsewhere but I need to stop focusing on this and move on. I have to go north!

Comments are loading... I hope ;)