You are here

imageapi_optimize.module in Image Optimize (or ImageAPI Optimize) 7

Image optimize functionalities.

File

imageapi_optimize.module
View source
<?php

/**
 * @file
 * Image optimize functionalities.
 */

/**
 * Implements hook_init().
 *
 * Abstract layer to all methods implemented by base toolkit.
 */
function imageapi_optimize_init() {
  $cache = cache_get('imageapi_optimize:methods');
  if (!$cache || empty($cache->data) && variable_get('imageapi_optimize_toolkit', '') != '') {
    $methods = _imageapi_optimize_get_methods();
  }
  else {
    $methods = $cache->data;
  }
  foreach ($methods as $method) {
    eval('function image_imageapi_optimize_' . $method . '($image) {
      $params = array_slice(func_get_args(), 1);
      return _imageapi_optimize_invoke("' . $method . '", $image, $params);
    }');
  }
}

/**
 * Implements hook_hook_info().
 */
function imageapi_optimize_hook_info() {
  $hooks = array();
  $hooks['imageapi_optimize_info'] = array(
    'group' => 'imageapi_optimize',
  );
  return $hooks;
}

/**
 * Implements hook_theme().
 */
function imageapi_optimize_theme() {
  $items = array();
  $items['imageapi_optimize_services_internal_form'] = array(
    'render element' => 'form',
    'file' => 'services/internal.inc',
  );
  return $items;
}

/**
 * Implements hook_menu().
 */
function imageapi_optimize_menu() {
  $items['admin/config/media/image-toolkit/imageapi_optimize/%'] = array(
    'title callback' => 'imageapi_optimize_internal_binary_settings_title',
    'title arguments' => array(
      5,
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'imageapi_optimize_internal_binary_settings',
      5,
    ),
    'access arguments' => array(
      'administer site configuration',
    ),
    'file' => 'services/internal.inc',
  );
  return $items;
}

/**
 * Implements hook_image_toolkits().
 */
function imageapi_optimize_image_toolkits() {
  return array(
    'imageapi_optimize' => array(
      'title' => t('ImageAPI Optimize'),
      'available' => TRUE,
    ),
  );
}

/**
 * Settings form callback for the image toolkit.
 */
function image_imageapi_optimize_settings() {

  // Get all defined services and binaries info definitions.
  $info = imageapi_optimize_info(TRUE);
  $form['imageapi_optimize_base_toolkit'] = array(
    '#type' => 'fieldset',
    '#title' => t('ImageAPI Optimize Base Toolkit'),
  );

  // Base toolkit settings.
  $toolkits = image_get_available_toolkits();
  unset($toolkits['imageapi_optimize']);
  $base_toolkit = variable_get('imageapi_optimize_toolkit', 'gd');
  $form['imageapi_optimize_base_toolkit']['imageapi_optimize_toolkit'] = array(
    '#type' => 'radios',
    '#title' => t('Base toolkit'),
    '#default_value' => $base_toolkit,
    '#options' => $toolkits,
    '#element_validate' => array(
      'imageapi_optimize_toolkit_element_validate',
    ),
  );
  $function = 'image_' . $base_toolkit . '_settings';
  if (function_exists($function)) {
    $return = $function();
    if (is_array($return)) {
      $form['imageapi_optimize_base_toolkit']['imageapi_optimize_toolkit_settings'] = array(
        '#type' => 'fieldset',
        '#title' => t('@toolkit Settings', array(
          '@toolkit' => $toolkits[$base_toolkit],
        )),
        '#collapsible' => TRUE,
        '#collapsed' => TRUE,
      ) + $return;
    }
  }

  // Services (3rd party and internal) settings.
  $form['imageapi_optimize_service'] = array(
    '#type' => 'fieldset',
    '#title' => t('ImageAPI Optimize Service'),
  );
  $form['imageapi_optimize_service']['imageapi_optimize_service'] = array(
    '#type' => 'radios',
    '#title' => t('Choose which optimization service to use'),
    '#default_value' => variable_get('imageapi_optimize_service', 'internal'),
    '#options' => array(),
  );
  uasort($info['services'], 'drupal_sort_weight');
  foreach ($info['services'] as $name => $service) {

    // Append this service to the available services.
    $form['imageapi_optimize_service']['imageapi_optimize_service']['#options'][$name] = $service['title'];
    if (isset($service['url'])) {
      $form['imageapi_optimize_service']['imageapi_optimize_service']['#options'][$name] = l($service['title'], $service['url']);
    }

    // Build service form if required.
    if (isset($service['callbacks']['form'])) {

      // Include services file if defined and available.
      if (isset($service['file'])) {
        include_once $service['file'];
      }
      $return = $service['callbacks']['form']($info);
      if (is_array($return)) {
        $form['imageapi_optimize_service']['imageapi_optimize_' . $name] = array(
          '#type' => 'fieldset',
          '#title' => t('@service Settings', array(
            '@service' => $service['title'],
          )),
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
          '#states' => array(
            'visible' => array(
              ':input[name="imageapi_optimize_service"]' => array(
                'value' => $name,
              ),
            ),
          ),
        ) + $return;
      }
    }
  }

  // Reloads methods because user may change toolkit.
  $form['#submit'][] = '_imageapi_optimize_get_methods';
  return $form;
}

/**
 * Validation callback for Base toolkit field.
 */
function imageapi_optimize_toolkit_element_validate($element) {
  if ($element['#value'] == 'imageapi_optimize') {
    form_set_error($element['#name'], t('You must select a different toolkit from ImageAPI Optimize itself.'));
  }
}

/**
 * Load callback for the imageapi_optimize image toolkit.
 */
function image_imageapi_optimize_load($image) {
  return _imageapi_optimize_invoke('load', $image);
}

/**
 * Save callback for the imageapi_optimize image toolkit.
 */
function image_imageapi_optimize_save($image, $dst) {
  $scheme = file_uri_scheme($dst);

  // Work around lack of stream wrapper support.
  // Taken from image_gd_save().
  if ($scheme && file_stream_wrapper_valid_scheme($scheme)) {

    // If destination is not local, save image to temporary local file.
    $local_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_LOCAL);
    if (!isset($local_wrappers[$scheme])) {
      $permanent_destination = $dst;
      $dst = drupal_tempnam('temporary://', 'imageapi_optimize_');
    }

    // Convert stream wrapper URI to normal path.
    $dst = drupal_realpath($dst);
  }
  if (_imageapi_optimize_invoke('save', $image, array(
    $dst,
  ))) {
    $success = _imageapi_optimize_optimize($image, $dst);

    // Move temporary local file to remote destination.
    if (isset($permanent_destination)) {
      $success = (bool) file_unmanaged_move($dst, $permanent_destination, FILE_EXISTS_REPLACE) && $success;
    }
    return $success;
  }
  return FALSE;
}

/**
 * Helper. Based on image_toolkit_invoke()
 */
function _imageapi_optimize_invoke($method, $image, array $params = array()) {
  $function = 'image_' . variable_get('imageapi_optimize_toolkit', '') . '_' . $method;
  if (function_exists($function)) {
    array_unshift($params, $image);
    return call_user_func_array($function, $params);
  }
  return FALSE;
}

/**
 * Optimizes image with external commands.
 */
function _imageapi_optimize_optimize($image, $dst) {
  $info = imageapi_optimize_info();
  $service = variable_get('imageapi_optimize_service', 'internal');
  if (isset($info['services'][$service])) {
    $service = $info['services'][$service];
    if (isset($service['file'])) {
      include_once $service['file'];
    }
    $service['callbacks']['process']($image, $dst);
  }

  // If optimize service fails, there is no problem. Original image is saved.
  return TRUE;
}

/**
 * Load all defined services and binaries info definitions.
 */
function imageapi_optimize_info($reset = FALSE) {
  $cache = cache_get('imageapi_optimize:info');
  if (!$cache || $reset) {
    $info = module_invoke_all('imageapi_optimize_info');
    drupal_alter('imageapi_optimize_info', $info);

    // Process and validate all defined info.
    foreach ($info as $type => &$types) {
      foreach ($types as $name => &$data) {

        // Set defaults.
        $data += array(
          'callbacks' => array(),
          'weight' => 0,
        );
        $data['callbacks'] += array(
          'process' => 'imageapi_optimize_' . $type . '_' . $name,
        );

        // Add form callback if undefined yet available.
        if (!isset($data['callbacks']['form'])) {
          $function = 'imageapi_optimize_' . $type . '_' . $name . '_form';
          if (function_exists($function)) {
            $data['callbacks']['form'] = $function;
          }
        }

        // Set user defined binaries weight if available.
        if ('binaries' == $type) {
          $settings = variable_get('imageapi_optimize_' . $name, array());
          $data['weight'] = isset($settings['weight']) ? $settings['weight'] : $data['weight'];
          if (empty($data['settings'])) {
            $data['settings'] = array();
          }
        }

        // Validate info.
        $error = '';
        if (!isset($data['title'])) {
          $error .= t('Title not set.') . '<br />';
        }
        foreach ($data['callbacks'] as $callback) {
          if (!function_exists($callback)) {
            $error .= t('Function !callback does not exist.', array(
              '!callback' => $callback,
            )) . '<br />';
          }
        }
        if (isset($data['file']) && !file_exists($data['file'])) {
          $error .= t('File @file does not exist.', array(
            '@file' => $data['file'],
          )) . '<br />';
        }
        if (!empty($error)) {
          unset($info[$type][$name]);
          watchdog('imageapi_optimize', $error);
        }
      }

      // Sort by weight.
      uasort($info[$type], 'drupal_sort_weight');
    }

    // Cache the info to reduce future load times.
    cache_set('imageapi_optimize:info', $info);
    return $info;
  }
  return $cache->data;
}

/**
 * Gets all implemented methods by ImageAPI and contrib modules.
 *
 * This function takes a dozens of miliseconds CPU times.
 */
function _imageapi_optimize_get_methods() {

  // The list of toolkits might not loaded yet. We call this function to get
  // toolkits in separate .inc files eventually included.
  image_get_available_toolkits();
  $funcs = get_defined_functions();
  $methods = array();
  $prefix = 'image_' . variable_get('imageapi_optimize_toolkit', '') . '_';
  foreach ($funcs['user'] as $func) {
    if (strpos($func, $prefix) === 0) {
      $method = substr($func, strlen($prefix));
      if (!in_array($method, array(
        'load',
        'save',
        'settings',
      ))) {
        $methods[] = $method;
      }
    }
  }
  cache_set('imageapi_optimize:methods', $methods);
  watchdog('imageapi', 'Refresh ImageAPI methods');
  return $methods;
}

Functions

Namesort descending Description
imageapi_optimize_hook_info Implements hook_hook_info().
imageapi_optimize_image_toolkits Implements hook_image_toolkits().
imageapi_optimize_info Load all defined services and binaries info definitions.
imageapi_optimize_init Implements hook_init().
imageapi_optimize_menu Implements hook_menu().
imageapi_optimize_theme Implements hook_theme().
imageapi_optimize_toolkit_element_validate Validation callback for Base toolkit field.
image_imageapi_optimize_load Load callback for the imageapi_optimize image toolkit.
image_imageapi_optimize_save Save callback for the imageapi_optimize image toolkit.
image_imageapi_optimize_settings Settings form callback for the image toolkit.
_imageapi_optimize_get_methods Gets all implemented methods by ImageAPI and contrib modules.
_imageapi_optimize_invoke Helper. Based on image_toolkit_invoke()
_imageapi_optimize_optimize Optimizes image with external commands.