2

Consider a scenario, where large number of images are attached to a node and they are displayed as thumbnail gallery when that node is displayed/rendered. The node has access control so it displayed accordingly. All images and corresponding image styles are stored on private file system.

Since every thumbnail is accessed from private filesystem it incurs a high latency due to permission check an every image.

Is it possible to avoid bootstrap/permission check for every image when they are displayed/rendered as a part of a specific node? So behave like public filesystem in this special case only. When any item is directly accessed via url, the permission checks kick in as they normally do for private filesystem.

2 Answers 2

2

Haven't tried this before, but you could write an image field formatter that converts the thumbnail files to inline data URIs, eliminating the separate HTTP requests per image. That adds some overhead to the initial node render, but is probably more performant overall.

Here's a quick implementation. Encoding a thumbnail is almost trivially fast; the biggest performance hit is from generating image style derivatives if they don't exist yet.

/**
 * Implements hook_field_formatter_info().
 */
function image_datauri_field_formatter_info() {
  $formatters = array(
    'image_datauri' => array(
      'label' => t('Image Data URI'),
      'field types' => array('image'),
    ),
  );

  return $formatters;
}

/**
 * Implements hook_field_formatter_view().
 */
function image_datauri_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  $style_name = 'thumbnail';
  $style = image_style_load($style_name);
  foreach ($items as $delta => $item) {
    $image_style_path = image_style_path($style_name, $item['uri']);
    if (!file_exists($image_style_path)) {
      if (!image_style_create_derivative($style, $item['uri'], $image_style_path)) {
        continue;
      }
    }
    $encoded_image = base64_encode(file_get_contents($image_style_path));
    $data_uri = 'data:' . file_get_mimetype($image_style_path) . ';base64,' . $encoded_image;
    $attributes = array(
      'src' => $data_uri,
      'alt' => (isset($item['alt'])) ? $item['alt'] : NULL,
      'title' => (isset($item['title'])) ? $item['title'] : NULL,
    );
    $element[$delta] = array(
      '#markup' => '<img ' . drupal_attributes($attributes) . ' />',
    );
  }
  return $element;
}
4
  • Thanks for the idea and code @Les Lim I'll take a look at this. Currently I am experimenting performance in my view using Views PHP with following hack. $spath = image_style_path('thumbnail', $data->field_field_image_file[0]['raw']['uri']); $rpath = drupal_realpath($spath); $b64= base64_encode(file_get_contents($rpath)); echo '<img src="data:image/png;base64,' . $b64 . '">';
    – amit
    Feb 15, 2015 at 20:54
  • Ok. I tested the above code in a module. It works great. Is it possible to add a link to the original image in this code itself or we need to write another link formatter?
    – amit
    Feb 18, 2015 at 3:02
  • You can adapt the above code to whatever your needs are. The web-accessible URL to the original image can be generated with file_create_url($item['uri']) inside the foreach loop.
    – Les Lim
    Feb 18, 2015 at 14:22
  • I added the link code to your answer, but you need to review and accept it. Anyways I have it working, so thanks.
    – amit
    Feb 20, 2015 at 6:18
2

No because it are separate http(s) requests. Every requests needs to redo the check.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.