You are here

function simplecrop_field_widget_process in SimpleCrop 7

Element #process callback for the image_image field type.

Expands the image_image type to include the crop behavior.

1 string reference to 'simplecrop_field_widget_process'
simplecrop_field_widget_form in includes/simplecrop.field.inc
Implements hook_field_widget_form().

File

includes/simplecrop.field.inc, line 290
Contains information about field widget and related functions.

Code

function simplecrop_field_widget_process($element, &$form_state, $form) {

  // Get field instance settings.
  $instance = field_widget_instance($element, $form_state);
  $settings = $instance['widget']['settings']['simplecrop'];
  if (!empty($element['#file'])) {

    // Get file properties for better usability.
    $uri = $element['#file']->uri;
    $fid = $element['#file']->fid;

    // Ensure that image exists. Otherwise doesn't make sense to continue.
    if (!file_exists($uri)) {
      watchdog('simplecrop', 'Image path %uri does not exists. Simplecrop widget process has been aborted.', array(
        '%uri' => $uri,
      ), WATCHDOG_WARNING);
      return $element;
    }

    // Check if current image was initially loaded in the edit form.
    // If so - display widget according to configuration of the initial display setting.
    if (empty($form_state['simplecrop'][$fid]['display'])) {
      $form_state['simplecrop'][$fid]['display'] = $settings['initial_display'];
    }

    // Get current display of an image.
    $display = $form_state['simplecrop'][$fid]['display'];

    // Store parents of image to be able to fetch them later by parents array.
    $form_state['simplecrop'][$fid]['parents'] = $element['#parents'];

    // Get a current image info and keep its original resolution.
    $image_info = image_get_info($uri);

    // Make sure that image toolkit is installed on a server and available.
    // Otherwise no possibility to continue widget process.
    if (empty($image_info)) {
      watchdog('simplecrop', 'No image toolkit installed. Simplecrop widget process has been aborted.', array(), WATCHDOG_ERROR);
      return $element;
    }
    $original_width = $image_info['width'];
    $original_height = $image_info['height'];

    // If current form state already has info about this image crop,
    // then use that data.
    if (!empty($form_state['simplecrop'][$fid]['crop'])) {
      $crop_data = $form_state['simplecrop'][$fid]['crop'];
    }
    elseif ($crop = simplecrop_crop_load($uri)) {
      $form_state['simplecrop'][$fid]['crop'] = $crop_data = $crop->data;
    }
    $cropped_area = array();
    if (!empty($crop_data)) {

      // Define width and height of cropped area.
      $cropped_area['width'] = abs($crop_data['x'] - $crop_data['x2']);
      $cropped_area['height'] = abs($crop_data['y'] - $crop_data['y2']);
    }
    else {

      // No crop area, means that we keep original image resolution.
      $cropped_area['width'] = $original_width;
      $cropped_area['height'] = $original_height;
    }
    $cropped_area_original_width = $cropped_area['width'];

    // Downscale resolution of cropped area to width and height from settings.
    image_dimensions_scale($cropped_area, $settings['cropped']['scale']['width'], $settings['cropped']['scale']['height']);

    // Calculate difference between downscaled cropped area resolution and its original resolution.
    $scale_ratio = $cropped_area['width'] / $cropped_area_original_width;

    // Calculate resolution of cropped image that we need to display.
    // Scale ratio shows how much we need to downscale original resolution.
    $cropped_image_width = round($original_width * $scale_ratio);
    $cropped_image_height = round($original_height * $scale_ratio);
    $container_style = array(
      'width:' . $cropped_area['width'] . 'px;',
      'height:' . $cropped_area['height'] . 'px;',
    );

    // Calculate offset of crop area.
    $position_left = !empty($crop_data['x']) ? round($crop_data['x'] * $scale_ratio) : 0;
    $position_top = !empty($crop_data['y']) ? round($crop_data['y'] * $scale_ratio) : 0;

    // Set css offsets for cropped image, so for the user will be visible
    // only cropped area.
    $cropped_image_style = array(
      'left:' . -$position_left . 'px;',
      'top:' . -$position_top . 'px;',
    );

    // Container for cropped image.
    // Needed here to display only cropped area of image.
    $element['cropped_image'] = array(
      '#type' => 'container',
      '#attributes' => array(
        'style' => !empty($container_style) ? $container_style : array(),
      ),
    );

    // Show cropped image.
    $element['cropped_image']['image'] = array(
      '#theme' => 'image',
      '#width' => $cropped_image_width,
      '#height' => $cropped_image_height,
      '#attributes' => array(
        'style' => !empty($cropped_image_style) ? $cropped_image_style : array(),
      ),
      '#path' => $uri,
    );

    // If settings has scale behavior, then we need to downscale current image.
    if (!empty($settings['source']['scale']['width']) || !empty($settings['source']['scale']['height'])) {
      image_dimensions_scale($image_info, $settings['source']['scale']['width'], $settings['source']['scale']['height']);
    }

    // Display downscaled original image.
    // To this images we apply jCrop library.
    $element['source_image'] = array(
      '#theme' => 'image',
      '#width' => $image_info['width'],
      '#height' => $image_info['height'],
      '#path' => $uri,
    );

    // Adjust the Ajax settings so that on upload and remove of any individual
    // file, the entire group of file fields is updated together.
    $field = field_widget_field($element, $form_state);
    if ($field['cardinality'] != 1) {
      $parents = array_slice($element['#array_parents'], 0, -1);
      $path = 'simplecrop/ajax/' . implode('/', $parents) . '/' . $form['form_build_id']['#value'];
      $field_element = drupal_array_get_nested_value($form, $parents);
      $wrapper = $field_element['#id'] . '-ajax-wrapper';
    }
    else {
      $path = 'simplecrop/ajax/' . implode('/', $element['#parents']) . '/' . $form['form_build_id']['#value'];
      $wrapper = $element['upload_button']['#ajax']['wrapper'];
    }

    // Button that applies crop area and show cropped image.
    $element['display_reload'] = array(
      '#name' => implode('_', $element['#parents']) . '_display_reload',
      '#type' => 'submit',
      '#validate' => array(),
      '#submit' => array(
        'simplecrop_field_widget_change_display_submit',
      ),
      '#limit_validation_errors' => array(
        $element['#parents'],
      ),
      '#ajax' => array(
        'path' => $path,
        'wrapper' => $wrapper,
      ),
    );

    // Keep original size for later coordinates calculations.
    $element['original_size'] = array(
      '#type' => 'value',
      '#value' => array(
        'width' => $original_width,
        'height' => $original_height,
      ),
    );

    // Keep original size for later coordinates calculations.
    $element['scaled_size'] = array(
      '#type' => 'value',
      '#value' => array(
        'width' => $image_info['width'],
        'height' => $image_info['height'],
      ),
    );

    // We need to keep ratio between original image and scaled image.
    // We can calculate it using height or width values.
    $scale_ratio = (double) number_format($original_width / $image_info['width'], 3, '.', '');

    // We need to rescale min and max resolutions according to a new
    // scale ratio
    foreach (array(
      'min_area',
      'max_area',
    ) as $area) {
      foreach (array(
        'width',
        'height',
      ) as $side) {
        if (!empty($settings['crop'][$area][$side])) {
          $settings['crop'][$area][$side] = round($settings['crop'][$area][$side] / $scale_ratio);
        }
      }
    }

    // Collect js settings for image. They'll be used for jCrop processment.
    $js_settings = array();

    // Pick cropped area as a default selection area if user already defined his crop.
    if (!empty($crop_data)) {

      // We need to rescale coordinates according to a new scale ratio.
      foreach (array(
        'x',
        'y',
        'x2',
        'y2',
      ) as $name) {
        $crop_data[$name] = round($crop_data[$name] / $scale_ratio);
      }
      $js_settings['initial_area'] = $crop_data;
    }
    else {
      $js_settings['initial_area'] = _simplecrop_define_initial_crop_area($image_info['width'], $image_info['height'], $settings['crop']);
    }

    // Add resolution of scaled image to js settings.
    $js_settings['resolution'] = array(
      'width' => $image_info['width'],
      'height' => $image_info['height'],
    );

    // Add aspect ratio to a settings (if exists).
    if (!empty($settings['crop']['ratio']['width']) && !empty($settings['crop']['ratio']['height'])) {
      $js_settings['ratio'] = $settings['crop']['ratio']['width'] / $settings['crop']['ratio']['height'];
    }

    // Add settings for min and max crop area resolutions.
    foreach (array(
      'min_area',
      'max_area',
    ) as $area) {
      if (!empty($settings['crop'][$area]['width']) && !empty($settings['crop'][$area]['height'])) {
        $js_settings[$area] = array(
          $settings['crop'][$area]['width'],
          $settings['crop'][$area]['height'],
        );
      }
    }

    // Add js with image settings for jCrop plugin.
    // Avoid duplicated additions to js scope.
    $added_js =& drupal_static('simplecrop_added_js_settings');
    if (empty($added_js[$fid])) {
      drupal_add_js(array(
        'simpleCrop' => array(
          'images' => array(
            array(
              'fid' => $fid,
              'settings' => $js_settings,
            ),
          ),
          'reload' => $fid,
        ),
      ), 'setting');
      $added_js[$fid] = TRUE;
    }

    // Prepopulate default values for coordinate fields.
    foreach (array(
      'x',
      'y',
      'x2',
      'y2',
    ) as $name) {
      $element['data'][$name] = array(
        '#type' => 'hidden',
        '#default_value' => !empty($js_settings['initial_area'][$name]) ? $js_settings['initial_area'][$name] : 0,
        '#attributes' => array(
          'class' => array(
            $name,
          ),
        ),
      );
    }

    // Hide filename if admin wants so.
    if (!empty($settings['hide_filename']) && !empty($element['filename'])) {
      $element['filename']['#access'] = FALSE;
    }

    // Show and hide different widget fields depends on current display.
    _simplecrop_field_widget_switch_display($element, $display);

    // Theme widget using our internal theme function.
    $element['#theme'] = 'simplecrop_widget';

    // Add js and css for cropping.
    $element['#attached']['js'][] = drupal_get_path('module', 'simplecrop') . '/jquery.jcrop/js/jquery.Jcrop.min.js';
    $element['#attached']['css'][] = drupal_get_path('module', 'simplecrop') . '/jquery.jcrop/css/jquery.Jcrop.min.css';
    $element['#attached']['js'][] = drupal_get_path('module', 'simplecrop') . '/js/simplecrop.js';
    $element['#attached']['css'][] = drupal_get_path('module', 'simplecrop') . '/css/simplecrop.css';
  }

  // Add another submit handler to upload button.
  // We need this to store initial widget display after new image upload
  // in forms cache storage.
  if (!empty($element['upload_button'])) {
    $element['upload_button']['#submit'][] = 'simplecrop_file_field_submit';
  }
  return $element;
}