You are here

retina_images.module in Retina Images 7

Same filename and directory in other branches
  1. 8 retina_images.module

This module provides an image effect to assist in outputing high resolution images.

File

retina_images.module
View source
<?php

/**
 * @file
 * This module provides an image effect to assist in outputing high resolution images.
 */

/**
 * Implements hook_image_effect_info_alter
 */
function retina_images_image_effect_info_alter(&$effects) {

  // Scale effect
  $effects['image_scale']['form callback'] = 'retina_images_image_scale_form';
  $effects['image_scale']['effect callback'] = 'retina_images_image_scale_effect';
  $effects['image_scale']['summary theme'] = 'retina_images_image_scale_summary';

  // Scale and crop effect
  $effects['image_scale_and_crop']['form callback'] = 'retina_images_image_resize_form';
  $effects['image_scale_and_crop']['effect callback'] = 'retina_images_image_scale_and_crop_effect';
  $effects['image_scale_and_crop']['summary theme'] = 'retina_images_image_resize_summary';

  // Resize effect
  $effects['image_resize']['form callback'] = 'retina_images_image_resize_form';
  $effects['image_resize']['effect callback'] = 'retina_images_image_resize_effect';
  $effects['image_resize']['summary theme'] = 'retina_images_image_resize_summary';

  // Crop effect
  $effects['image_crop']['form callback'] = 'retina_images_image_crop_form';
  $effects['image_crop']['effect callback'] = 'retina_images_image_crop_effect';
  $effects['image_crop']['summary theme'] = 'retina_images_image_crop_summary';
}

/**
 * Implements hook_theme().
 */
function retina_images_theme() {
  return array(
    'retina_images_image_crop_summary' => array(
      'variables' => array(
        'data' => NULL,
      ),
    ),
    'retina_images_image_resize_summary' => array(
      'variables' => array(
        'data' => NULL,
      ),
    ),
    'retina_images_image_scale_summary' => array(
      'variables' => array(
        'data' => NULL,
      ),
    ),
    'retina_images_style_preview' => array(
      'variables' => array(
        'style' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function retina_images_menu() {
  $items = array();
  $items['admin/config/media/image-styles/retina_preview/%image_style'] = array(
    'title' => 'Preview retinafied style',
    'page callback' => 'retina_images_retina_style_preview',
    'page arguments' => array(
      5,
    ),
    'access arguments' => array(
      'administer image styles',
    ),
  );
  return $items;
}

/**
 * Conditionally multiply the height and width keys of an array by a variable amount.
 *
 * @param $data
 *   The configuration data for a specific image effect. This is expected to
 *   have a 'width' and 'height' key that will be modified. Passed by reference.
 * @param int $int
 *   The amount that the width and height will be multiplied by. Defaults to 2.
 */
function retina_images_multiply_data_dimensions(&$data, $int = 2) {
  if (isset($data['retinafy']) && $data['retinafy']) {
    $data['width'] = $data['width'] * $int;
    $data['height'] = $data['height'] * $int;
  }
}

/**
 * Helper function to add a "Retinafy" checkbox to a image effect form.
 *
 * @param array $form
 *   The form to modify. Passed by reference.
 * @param array $data
 *   The configuration data for the specific image effect.
 */
function retina_images_form_helper(&$form, $data) {
  $form['retinafy'] = array(
    '#type' => 'checkbox',
    '#default_value' => isset($data['retinafy']) ? $data['retinafy'] : 0,
    '#title' => t('Retinafy'),
    '#description' => t('Scale and output this image with increased resolution. It is recommended to allow upscaling with this option and set image qualtiy to 25.'),
  );
}

/**
 * Form structure for the image scale form.
 *
 * Note that this is not a complete form, it only contains the portion of the
 * form for configuring the scale options. Therefore it does not not need to
 * include metadata about the effect, nor a submit button.
 *
 * @param $data
 *   The current configuration for this scale effect.
 */
function retina_images_image_scale_form($data) {
  $form = image_scale_form($data);
  retina_images_form_helper($form, $data);
  return $form;
}

/**
 * Image effect callback; Scale an image resource.
 *
 * @param $image
 *   An image object returned by image_load().
 * @param $data
 *   An array of attributes to use when performing the scale effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *   - "upscale": A boolean indicating that the image should be upscaled if the
 *     dimensions are larger than the original image.
 *
 * @return
 *   TRUE on success. FALSE on failure to scale image.
 *
 * @see image_scale()
 */
function retina_images_image_scale_effect(&$image, $data) {

  // Set sane default values.
  $data += array(
    'width' => NULL,
    'height' => NULL,
    'upscale' => FALSE,
  );
  retina_images_multiply_data_dimensions($data);
  return image_scale_effect($image, $data);
}

/**
 * Form structure for the image resize form.
 *
 * Note that this is not a complete form, it only contains the portion of the
 * form for configuring the resize options. Therefore it does not not need to
 * include metadata about the effect, nor a submit button.
 *
 * @param $data
 *   The current configuration for this resize effect.
 */
function retina_images_image_resize_form($data) {
  $form = image_resize_form($data);
  retina_images_form_helper($form, $data);
  return $form;
}

/**
 * Image effect callback; Resize an image resource.
 *
 * @param $image
 *   An image object returned by image_load().
 * @param $data
 *   An array of attributes to use when performing the resize effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *
 * @return
 *   TRUE on success. FALSE on failure to resize image.
 *
 * @see image_resize()
 */
function retina_images_image_resize_effect(&$image, $data) {
  retina_images_multiply_data_dimensions($data);
  return image_resize_effect($image, $data);
}

/**
 * Image effect callback; Scale and crop an image resource.
 *
 * @param $image
 *   An image object returned by image_load().
 * @param $data
 *   An array of attributes to use when performing the scale and crop effect
 *   with the following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 * @return
 *   TRUE on success. FALSE on failure to scale and crop image.
 * @see image_scale_and_crop()
 */
function retina_images_image_scale_and_crop_effect(&$image, $data) {
  retina_images_multiply_data_dimensions($data);
  return image_scale_and_crop_effect($image, $data);
}

/**
 * Form structure for the image crop form.
 *
 * Note that this is not a complete form, it only contains the portion of the
 * form for configuring the crop options. Therefore it does not not need to
 * include metadata about the effect, nor a submit button.
 *
 * @param $data
 *   The current configuration for this crop effect.
 */
function retina_images_image_crop_form($data) {
  $form = image_crop_form($data);
  retina_images_form_helper($form, $data);
  return $form;
}

/**
 * Image effect callback; Crop an image resource.
 *
 * @param $image
 *   An image object returned by image_load().
 * @param $data
 *   An array of attributes to use when performing the crop effect with the
 *   following items:
 *   - "width": An integer representing the desired width in pixels.
 *   - "height": An integer representing the desired height in pixels.
 *   - "anchor": A string describing where the crop should originate in the form
 *     of "XOFFSET-YOFFSET". XOFFSET is either a number of pixels or
 *     "left", "center", "right" and YOFFSET is either a number of pixels or
 *     "top", "center", "bottom".
 * @return
 *   TRUE on success. FALSE on failure to crop image.
 * @see image_crop()
 */
function retina_images_image_crop_effect(&$image, $data) {

  // Set sane default values.
  $data += array(
    'anchor' => 'center-center',
  );
  retina_images_multiply_data_dimensions($data);
  return image_crop_effect($image, $data);
}

/**
 * Implements hook_image_default_styles().
 */
function retina_images_image_default_styles() {
  $styles = array();
  $styles['thumbnail_retina'] = array(
    'label' => 'Thumbnail (100x100 retinafied)',
    'effects' => array(
      array(
        'name' => 'image_scale',
        'data' => array(
          'width' => 100,
          'height' => 100,
          'upscale' => 1,
          'retinafy' => 1,
        ),
        'weight' => 0,
      ),
    ),
  );
  $styles['medium_retina'] = array(
    'label' => 'Medium (220x220 retinafied)',
    'effects' => array(
      array(
        'name' => 'image_scale',
        'data' => array(
          'width' => 220,
          'height' => 220,
          'upscale' => 1,
          'retinafy' => 1,
        ),
        'weight' => 0,
      ),
    ),
  );
  $styles['large_retina'] = array(
    'label' => 'Large (480x480 retinafied)',
    'effects' => array(
      array(
        'name' => 'image_scale',
        'data' => array(
          'width' => 480,
          'height' => 480,
          'upscale' => 0,
          'retinafy' => 1,
        ),
        'weight' => 0,
      ),
    ),
  );
  return $styles;
}

/**
 * Returns HTML for a summary of an image scale effect.
 *
 * @param $variables
 *   An associative array containing:
 *   - data: The current configuration for this scale effect.
 *
 * @ingroup themeable
 */
function theme_retina_images_image_scale_summary($variables) {
  $data = $variables['data'];
  $retinafied = isset($data['retinafy']) ? $data['retinafy'] : FALSE;
  return theme('image_scale_summary', $variables) . ' ' . ($retinafied ? '(' . t('retinafied') . ')' : '');
}

/**
 * Returns HTML for a summary of an image resize effect.
 *
 * @param $variables
 *   An associative array containing:
 *   - data: The current configuration for this resize effect.
 *
 * @ingroup themeable
 */
function theme_retina_images_image_resize_summary($variables) {
  $data = $variables['data'];
  $retinafied = isset($data['retinafy']) ? $data['retinafy'] : FALSE;
  return theme('image_resize_summary', $variables) . ' ' . ($retinafied ? '(' . t('retinafied') . ')' : '');
}

/**
 * Returns HTML for a summary of an image crop effect.
 *
 * @param $variables
 *   An associative array containing:
 *   - data: The current configuration for this crop effect.
 *
 * @ingroup themeable
 */
function theme_retina_images_image_crop_summary($variables) {
  $data = $variables['data'];
  $retinafied = isset($data['retinafy']) ? $data['retinafy'] : FALSE;
  return theme('image_crop_summary', $variables) . ' ' . ($retinafied ? '(' . t('retinafied') . ')' : '');
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function retina_images_form_image_style_form_alter(&$form, &$form_state) {

  // Get the style to pass to our new theme function.
  $style = $form_state['image_style'];

  // Override the preview image area to use our own preview.
  $form['preview']['#markup'] = theme('retina_images_style_preview', array(
    'style' => $style,
  ));
}

/**
 * Returns HTML for a preview of an image style.
 *
 * @param $variables
 *   An associative array containing:
 *   - style: The image style array being previewed.
 *
 * @ingroup themeable
 */
function theme_retina_images_style_preview($variables) {
  $style = $variables['style'];
  $sample_image = variable_get('image_style_preview_image', drupal_get_path('module', 'image') . '/sample.png');
  $sample_width = 160;
  $sample_height = 160;

  // Set up original file information.
  $original_path = $sample_image;
  $original_image = image_get_info($original_path);
  if ($original_image['width'] > $original_image['height']) {
    $original_width = min($original_image['width'], $sample_width);
    $original_height = round($original_width / $original_image['width'] * $original_image['height']);
  }
  else {
    $original_height = min($original_image['height'], $sample_height);
    $original_width = round($original_height / $original_image['height'] * $original_image['width']);
  }
  $original_attributes = array_intersect_key($original_image, array(
    'width' => '',
    'height' => '',
  ));
  $original_attributes['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;';

  // Set up preview file information.
  $preview_file = image_style_path($style['name'], $original_path);
  if (!file_exists($preview_file)) {
    image_style_create_derivative($style, $original_path, $preview_file);
  }
  $preview_image = image_get_info($preview_file);
  if ($preview_image['width'] > $preview_image['height']) {
    $preview_width = min($preview_image['width'], $sample_width);
    $preview_height = round($preview_width / $preview_image['width'] * $preview_image['height']);
  }
  else {
    $preview_height = min($preview_image['height'], $sample_height);
    $preview_width = round($preview_height / $preview_image['height'] * $preview_image['width']);
  }
  $preview_attributes = array_intersect_key($preview_image, array(
    'width' => '',
    'height' => '',
  ));
  $preview_attributes['style'] = 'width: ' . $preview_width . 'px; height: ' . $preview_height . 'px;';

  // Calculate the final output size as theme_image_style would use since the
  // image may be retinafied.
  $final_output_size = array(
    'width' => $preview_image['width'],
    'height' => $preview_image['height'],
  );
  image_style_transform_dimensions($style['name'], $final_output_size);

  // Build our URL for our retinafied preview
  $url = 'admin/config/media/image-styles/retina_preview/' . $style['name'];

  // In the previews, timestamps are added to prevent caching of images.
  $output = '<div class="image-style-preview preview clearfix">';

  // Build the preview of the original image.
  $original_url = file_create_url($original_path);
  $output .= '<div class="preview-image-wrapper">';
  $output .= t('original') . ' (' . l(t('view actual size'), $original_url) . ')';
  $output .= '<div class="preview-image original-image" style="' . $original_attributes['style'] . '">';
  $output .= '<a href="' . $original_url . '">' . theme('image', array(
    'path' => $original_path,
    'alt' => t('Sample original image'),
    'title' => '',
    'attributes' => $original_attributes,
  )) . '</a>';
  $output .= '<div class="height" style="height: ' . $original_height . 'px"><span>' . $original_image['height'] . 'px</span></div>';
  $output .= '<div class="width" style="width: ' . $original_width . 'px"><span>' . $original_image['width'] . 'px</span></div>';
  $output .= '</div>';

  // End preview-image.
  $output .= '</div>';

  // End preview-image-wrapper.
  // Build the preview of the image style.
  $preview_url = file_create_url($preview_file) . '?cache_bypass=' . REQUEST_TIME;
  $output .= '<div class="preview-image-wrapper">';
  $output .= check_plain($style['name']) . ' (' . l(t('view actual size'), $url) . ')';
  $output .= '<div class="preview-image modified-image" style="' . $preview_attributes['style'] . '">';
  $output .= '<a href="' . url($url) . '?' . time() . '">' . theme('image', array(
    'path' => $preview_url,
    'alt' => t('Sample modified image'),
    'title' => '',
    'attributes' => $preview_attributes,
  )) . '</a>';
  $output .= '<div class="height" style="height: ' . $preview_height . 'px"><span>' . $final_output_size['height'] . 'px</span></div>';
  $output .= '<div class="width" style="width: ' . $preview_width . 'px"><span>' . $final_output_size['width'] . 'px</span></div>';
  $output .= '</div>';

  // End preview-image.
  $output .= '</div>';

  // End preview-image-wrapper.
  $output .= '</div>';

  // End image-style-preview.
  return $output;
}

/**
 * Menu callback for previewing a retinafied image.
 */
function retina_images_retina_style_preview($style) {
  $image = $sample_image = variable_get('image_style_preview_image', drupal_get_path('module', 'image') . '/sample.png');
  $image_tag = theme('image_style', array(
    'style_name' => $style['name'],
    'path' => $image,
  ));
  $final_output_size = array(
    'width' => 0,
    'height' => 0,
  );
  image_style_transform_dimensions($style['name'], $final_output_size);
  $filename = drupal_basename($image);
  $output = <<<EOT
<html>
  <head>
  <title>{<span class="php-variable">$filename</span>} {<span class="php-variable">$final_output_size</span>[<span class="php-string">'width'</span>]}&times;{<span class="php-variable">$final_output_size</span>[<span class="php-string">'height'</span>]} pixels</title>
  </head>
  <body>
    {<span class="php-variable">$image_tag</span>}
  </body>
</html>

EOT;
  print $output;
  drupal_exit();
}

Functions

Namesort descending Description
retina_images_form_helper Helper function to add a "Retinafy" checkbox to a image effect form.
retina_images_form_image_style_form_alter Implements hook_form_FORM_ID_alter().
retina_images_image_crop_effect Image effect callback; Crop an image resource.
retina_images_image_crop_form Form structure for the image crop form.
retina_images_image_default_styles Implements hook_image_default_styles().
retina_images_image_effect_info_alter Implements hook_image_effect_info_alter
retina_images_image_resize_effect Image effect callback; Resize an image resource.
retina_images_image_resize_form Form structure for the image resize form.
retina_images_image_scale_and_crop_effect Image effect callback; Scale and crop an image resource.
retina_images_image_scale_effect Image effect callback; Scale an image resource.
retina_images_image_scale_form Form structure for the image scale form.
retina_images_menu Implements hook_menu().
retina_images_multiply_data_dimensions Conditionally multiply the height and width keys of an array by a variable amount.
retina_images_retina_style_preview Menu callback for previewing a retinafied image.
retina_images_theme Implements hook_theme().
theme_retina_images_image_crop_summary Returns HTML for a summary of an image crop effect.
theme_retina_images_image_resize_summary Returns HTML for a summary of an image resize effect.
theme_retina_images_image_scale_summary Returns HTML for a summary of an image scale effect.
theme_retina_images_style_preview Returns HTML for a preview of an image style.