Skip to main content
RegEx Corner

RegEx Corner: Images for Retina Displays

Front-end Development
Back-end Development

Regular expressions are an invaluable development tool, and also extremely handy for non-developers who need to comb through plain text in an editor. In this article, we'll look at a simple regex problem and dissect a possible solution.

The Problem

We have a Drupal site with a bunch of uploaded images, processed through the normal Drupal 7 image style mechanism. On high-DPI displays (such as newer iPhones and iPads), we want to deliver double-size images. We'll do this by having a second, separate set of image styles producing the double-sized images, but we need a way to deliver the appropriate images for each screen.

The Text

<img src="/sites/default/files/styles/event_medium/public/event_image/First%20Birthday%20cake.jpg">

The Regex

One solution to our problem is to use JavaScript to find all the images on the page, and append _retina to the ends of the image style names. If we can take a look at the src attribute of each image, a quick regular expression replacement is all it will take.

Search

\/styles\/([^\/]+)\/

Replace:

/styles/$1_retina/

There are four backslashes in our search expression, each escaping a forward slash. It will be a bit easier to see what's going on if we look at the search expression without those backslashes it it:

/styles/([^/]+)/

The interesting part here is the bit in parentheses. Square brackets indicate a "character class," which stands for any one of the characters inside the brackets. The ^ character, though, negates the character class, so in this case it means "anything but a slash." Since there's a + character after the class, the part of the expression inside the brackets matches one or more characters that aren't slashes—or, in other words, one segment of the file path to the image.

The replacement path is a simple one. The only special sequence is $1, which refers to whatever was in the parenthesized part of the search pattern.

Putting it in context

Now that we have crafted our regular expression, we need to invoke it at the right time. We've decided to use Javascript, so let's look at a little jQuery routine to detect retina displays and run our regular expression in those cases.

jQuery(document).ready(function($) {
  function isRetina() {
    if (window.devicePixelRatio > 1) return true;
    var mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\
                      (min--moz-device-pixel-ratio: 1.5),\
                      (-o-min-device-pixel-ratio: 3/2),\
                      (min-resolution: 1.5dppx)";
    if (window.matchMedia && window.matchMedia(mediaQuery).matches) return true;
    return false;
  }
  
  if (isRetina()) {
    $('img').attr('src', function() {
      return this.src.replace(/\/styles\/([^\/]+)\//, '/styles/$1_retina/');
    });
  }
});

Our script contains a small function to test whether we are on a high-resolution device, and if we are, a jQuery selector runs to find all images on the page. For each one, we update the src attribute by running our regular expression replacement across it. If /styles/ is not in the file path, we'll ignore the image and leave it as-is. If /styles/ is there, however, we'll update the path with the new image style name, and we are done!

Drupal note

The above technique works, but runs afoul of an anti-DDOS mechanism in Drupal 7. To avoid image styles being generated when not needed, Drupal requires a token to be added to the image URL. We can turn this feature off in our settings.php file like so:

$conf['image_allow_insecure_derivatives'] = TRUE;