<?php
// $Id: image_im_advanced.module,v 1.7.2.1 2010/08/03 17:43:00 sun Exp $

/**
 * Retrieve the settings array.
 */
function image_im_advanced_options() {
  $defaults = array(
    'jpeg_quality' => 75,
    'strip' => '150x150',
    'colorspace' => 'rgb',
    'density' => 1,
    'unsharp' => array(
      'radius' => 0.9,
      'amount' => 0,
    ),
    'profile' => array('path' => ''),
  );
  return variable_get('image_im_advanced_options', $defaults);
}

/**
 * Implementation of hook_form_alter().
 *
 * Add options to the Image toolkit settings form.
 */
function image_im_advanced_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'system_image_toolkit_settings' && 'imagemagick' == image_get_toolkit()) {
    $options = image_im_advanced_options();

    $form['image_im_advanced_options'] = array(
      '#type' => 'fieldset',
      '#title' => t('ImageMagick advanced options'),
      '#collapsible' => FALSE,
      '#description' => t("These settings let you control some of ImageMagick's more advanced options."),
      '#element_validate' => array('image_im_advanced_settings_validate'),
      '#tree' => TRUE,
    );
    $form['image_im_advanced_options']['jpeg_quality'] = array(
      '#type' => 'textfield',
      '#title' => t('JPEG quality'),
      '#size' => 10,
      '#maxlength' => 3,
      '#default_value' => $options['jpeg_quality'],
      '#field_suffix' => t('%'),
      '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files. <a href="@link">More information on -quality</a>.', array('@link' => 'http://www.imagemagick.org/script/command-line-options.php#quality')),
    );
    $form['image_im_advanced_options']['strip'] = array(
      '#type' => 'textfield',
      '#title' => t('Strip metadata from images at this size and below'),
      '#default_value' => $options['strip'],
      '#description' => t('You may choose to strip all metadata, such as camera information and color profiles, from the processed images in order to reduce their file size. Please choose at what maximum size you want images to be stripped of their metadata. Example: "150x150". Enter "0x0" to disable this feature. This option requires ImageMagick 6.0.0 or higher. <a href="@link">More information on -strip</a>.', array('@link' => 'http://www.imagemagick.org/script/command-line-options.php#strip')),
    );
    $form['image_im_advanced_options']['colorspace'] = array(
      '#type' => 'select',
      '#title' => t('Convert colorspace'),
      '#default_value' => $options['colorspace'],
      '#options' => array(0 => t('- None -'), 'RGB' => t('RGB'), 'GRAY' => t('Gray')),
      '#description' => t('This option lets you convert images to the specified colorspace. This will be overridden by the Color profile option, if used. <a href="@link">More information on -colorspace</a>.', array('@link' => 'http://www.imagemagick.org/script/command-line-options.php#colorspace')),
    );
    $form['image_im_advanced_options']['density'] = array(
      '#type' => 'checkbox',
      '#title' => t('Change image resolution to 72 ppi'),
      '#default_value' => $options['density'],
      '#description' => t('If checked, this option will set the print resolution of the image to 72 pixels per inch, which is suitable for web use. This does not affect the pixel size or quality of the image. <a href="@link">More information on -density</a>.', array('@link' => 'http://www.imagemagick.org/script/command-line-options.php#density')),
    );

    $form['image_im_advanced_options']['unsharp'] = array(
      '#type' => 'fieldset',
      '#title' => t('Sharpening filter'),
      '#collapsible' => TRUE,
      '#collapsed' => ($options['unsharp']['amount'] == 0),
      '#description' => t('The sharpness filter is used to regain some of the sharpness that is always lost when a digital photograph is scaled down. This is equivalent to the commonly used "Unsharp Mask" filter. It is important that these values are not set too high as it can easily make the images look artificial. <a href="@link">More information on -unsharp</a>.', array('@link' => 'http://www.imagemagick.org/script/command-line-options.php#unsharp')),
    );
    $form['image_im_advanced_options']['unsharp']['amount'] = array(
      '#type' => 'textfield',
      '#title' => t('Sharpness filter strength'),
      '#size' => 4,
      '#maxlength' => 3,
      '#default_value' => $options['unsharp']['amount'],
      '#field_suffix' => t('%'),
      '#description' => t('Apply this percentage of sharpness when scaling. 90 is recommended, although values higher than 100 are also valid. Set to 0 to disable this feature.'),
    );
    $form['image_im_advanced_options']['unsharp']['radius'] = array(
      '#type' => 'textfield',
      '#title' => t('Sharpness filter radius'),
      '#default_value' => $options['unsharp']['radius'],
      '#size' => 4,
      '#maxlength' => 4,
      '#description' => t('Use this pixel radius for the sharpness filter. 0.9 is recommended.'),
    );

    $form['image_im_advanced_options']['profile'] = array(
      '#type' => 'fieldset',
      '#title' => t('Color profile'),
      '#collapsible' => TRUE,
      '#collapsed' => empty($options['profile']['path']),
      '#description' => t('Processed images may be converted to a color profile specified here. This is especially important when working with images that use a wide-gamut color profile such as ColorMatch or Adobe RGB, which is often the case with professional photography. sRGB (which may be downloaded from <a href="http://www.color.org/profiles.html">ICC</a>) is recommended since it is likely to look good on most displays.<br />Note that this conversion is still useful even if you choose to strip all metadata from your images (see above). This is because the conversion happens first and changes the actual image data before the profile is stripped.'),
    );
    $form['image_im_advanced_options']['profile']['path'] = array(
      '#type' => 'textfield',
      '#title' => t('Path to color profile'),
      '#default_value' => $options['profile']['path'],
      '#description' => t('The path to a color profile file that all scaled down images will be converted to. Leave empty to disable.'),
    );

    // Move the buttons below our additions.
    $form['buttons']['#weight'] = 10;
  }
}

/**
 * Validate settings form.
 */
function image_im_advanced_settings_validate($element, &$form_state) {
  $options = $form_state['values']['image_im_advanced_options'];

  // Check that the JPEG quality is a valid number.
  if (!is_numeric($options['jpeg_quality']) || $options['jpeg_quality'] < 1 || $options['jpeg_quality'] > 100) {
    form_set_error('image_im_advanced_options][jpeg_quality', t('The JPEG quality must be a positive number between 1 and 100.'));
  }

  // Check that the strip dimensions are valid.
  if (!preg_match('/^\d+x\d+$/', $options['strip'])) {
    form_set_error('image_im_advanced_options][strip', t('The strip metadata threshold must be specified in the form <em>NxN</em>. Example: <em>150x150</em>.'));
  }

  // Check the unsharp mask values.
  if (!empty($options['unsharp']['amount'])) {
    if (!is_numeric($options['unsharp']['amount']) || $options['unsharp']['amount'] < 0) {
      form_set_error('image_im_advanced_options][unsharp][amount', t('The sharpness amount must be specified as a positive number.'));
    }
    if (!is_numeric($options['unsharp']['radius']) || $options['unsharp']['radius'] < 0) {
      form_set_error('image_im_advanced_options][unsharp][radius', t('The sharpness radius must be specified as a positive value.'));
    }
  }

  // Check that if the color profile is provided that it's a readable file.
  if (!empty($options['profile']['path']) && (!file_exists($options['profile']['path']) || !is_readable($options['profile']['path']))) {
    form_set_error('image_im_advanced_options][profile][path', t('The ICC profile could not be read.'));
  }
}

/**
 * Implementation of hook_imagemagick_alter().
 */
function image_im_advanced_imagemagick_alter($op, $filepath, &$args) {
  $options = image_im_advanced_options();
  $image = image_get_info($filepath);

  switch ($op) {
    case 'resize':
      // Examine the 'resize' argument to determine the new target size.
      $size = preg_replace('/[^\d]*(\d+x\d+)[^\d]*/', '$1', $args['resize']);
      list($width, $height) = explode('x', $size);

      // Add sharpening filter.
      if ($options['unsharp']['amount'] && $options['unsharp']['radius']) {
        // 0.7 and 0.02 are reasonable values for Sigma and Threshold.
        $args['unsharp'] = '-unsharp ' . $options['unsharp']['radius'] . 'x0.7+' . round($options['unsharp']['amount'] / 100, 2) . '+0.02';
      }
      break;

    case 'crop':
      // Examine the 'crop' argument to determine the new target size.
      $size = preg_replace('/[^\d]*(\d+x\d+)[^\d]*/', '$1', $args['crop']);
      list($width, $height) = explode('x', $size);
      break;

    case 'rotate':
      // For lack of a better guess, use the current image size.
      $width = $image['width'];
      $height = $image['height'];
      break;
  }

  // Convert to specified color profile.
  if (!empty($options['profile']['path']) && is_readable($options['profile']['path'])) {
    $args['profile'] = '-profile ' . $options['profile']['path'];
  }

  // Assign a color space. Skip this if a color profile has been provided,
  // as it will be more accurate.
  if ($options['colorspace'] && !isset($args['profile'])) {
    $args['colorspace'] = ' -colorspace ' . $options['colorspace'];
  }

  // Determine if the -strip parameter should be used.
  list($strip_width, $strip_height) = explode('x', $options['strip']);
  if ((int) $width <= (int) $strip_width && (int) $height <= (int) $strip_height) {
    $args['strip'] = '-strip';
  }

  // Set JPEG quality.
  if ($image['mime_type'] == 'image/jpeg') {
    if (empty($args['quality']) && $options['jpeg_quality']) {
      $args['quality'] = '-quality ' . $options['jpeg_quality'];
    }
  }

  // Change image density (this doesn't affect the image dimensions/resolution).
  if ($options['density']) {
    $args['density'] = '-density 72 -units PixelsPerInch';
  }
}

