--- imagefield_crop.module	2011-07-14 22:08:13.000000000 +0100
+++ imagefield_crop.module.new	2011-08-04 12:48:13.610321082 +0100
@@ -1,468 +1,807 @@
-<?php
-
-/**
- * Implements hook_field_widget_info().
- */
-function imagefield_crop_field_widget_info() {
-  //dpm(__FUNCTION__);
-  return array(
-    'imagefield_crop_widget' => array(
-      'label' => t('Image with cropping'),
-      'field types' => array('image'),
-      'settings' => array(
-        'progress_indicator' => 'throbber',
-        'preview_image_style' => 'thumbnail',
-        'collapsible' => 2,
-        'resolution' => '200x150',
-        'enforce_ratio' => true,
-        'enforce_minimum' => true,
-        'croparea' => '500x500',
-      ),
-      'behaviors' => array(
-        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
-        'default value' => FIELD_BEHAVIOR_NONE,
-      ),
-    ),
-  );
-}
-
-/**
- * Implements hook_field_widget_settings_form().
- */
-function imagefield_crop_field_widget_settings_form($field, $instance) {
-  //dpm(__FUNCTION__);
-  $widget = $instance['widget'];
-  $settings = $widget['settings'];
-
-  // Use the image widget settings form.
-  $form = image_field_widget_settings_form($field, $instance);
-
-  $form['collapsible'] = array(
-    '#type' => 'radios',
-    '#title' => t('Collapsible behavior'),
-    '#options' => array(
-      1 => t('None.'),
-      2 => t('Collapsible, expanded by default.'),
-      3 => t('Collapsible, collapsed by default.'),
-    ),
-    '#default_value' => $settings['collapsible'],
-  );
-
-  // Resolution settings.
-  $resolution = explode('x', $settings['resolution']) + array('', '');
-  $form['resolution'] = array(
-    '#title' => t('The resolution to crop the image onto'),
-    '#element_validate' => array('_image_field_resolution_validate', '_imagefield_crop_widget_resolution_validate'),
-    '#theme_wrappers' => array('form_element'),
-    '#description' => t('The output resolution of the cropped image, expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 not to rescale after cropping. Note: output resolution must be defined in order to present a dynamic preview.'),
-  );
-  $form['resolution']['x'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $resolution[0],
-    '#size' => 5,
-    '#maxlength' => 5,
-    '#field_suffix' =>' x ',
-    '#theme_wrappers' => array(),
-  );
-  $form['resolution']['y'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $resolution[1],
-    '#size' => 5,
-    '#maxlength' => 5,
-    '#field_suffix' => ' ' . t('pixels'),
-    '#theme_wrappers' => array(),
-  );
-  $form['enforce_ratio'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enforce crop box ratio'),
-    '#default_value' => $settings['enforce_ratio'],
-    '#description' => t('Check this to force the ratio of the output on the crop box. NOTE: If you leave this unchecked but enforce an output resolution, the final image might be distorted'),
-    '#element_validate' => array('_imagefield_crop_widget_enforce_ratio_validate'),
-  );
-  $form['enforce_minimum'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Enforce minimum crop size based on the output size'),
-    '#default_value' => $settings['enforce_minimum'],
-    '#description' => t('Check this to force a minimum cropping selection equal to the output size. NOTE: If you leave this unchecked you might get zoomed pixels if the cropping area is smaller than the output resolution.'),
-    '#element_validate' => array('_imagefield_crop_widget_enforce_minimum_validate'),
-  );
-
-  // Crop area settings
-  $croparea = explode('x', $settings['croparea']) + array('', '');
-  $form['croparea'] = array(
-    '#title' => t('The resolution of the cropping area'),
-    '#element_validate' => array('_imagefield_crop_widget_croparea_validate'),
-    '#theme_wrappers' => array('form_element'),
-    '#description' => t('The resolution of the area used for the cropping of the image. Image will displayed at this resolution for cropping. Use WIDTHxHEIGHT format, empty or zero values are permitted, e.g. 500x will limit crop box to 500 pixels width.'),
-  );
-  $form['croparea']['x'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $croparea[0],
-    '#size' => 5,
-    '#maxlength' => 5,
-    '#field_suffix' => ' x ',
-    '#theme_wrappers' => array(),
-  );
-  $form['croparea']['y'] = array(
-    '#type' => 'textfield',
-    '#default_value' => $croparea[1],
-    '#size' => 5,
-    '#maxlength' => 5,
-    '#field_suffix' => ' ' . t('pixels'),
-    '#theme_wrappers' => array(),
-  );
-
-  return $form;
-}
-
-function _imagefield_crop_widget_resolution_validate($element, &$form_state) {
-  //dpm(__FUNCTION__);
-	$settings = $form_state['values']['instance']['widget']['settings'];
-  // _image_field_resolution_validate() does most of the validation
-  if ($settings['enforce_ratio'] && (empty($element['x']['#value']))) {
-    form_error($element, t('Target resolution must be defined as WIDTHxHEIGHT if resolution is to be enforced'));
-  }
-}
-
-function _imagefield_crop_widget_enforce_ratio_validate($element, &$form_state) {
-  //dpm(__FUNCTION__);
-	$settings = $form_state['values']['instance']['widget']['settings'];
-  if ($settings['resolution']['x'] && !$element['#value']) {
-    drupal_set_message(t('Output resolution is defined, but not enforced. Final images might be distroted'));
-  }
-}
-
-function _imagefield_crop_widget_enforce_minimum_validate($element, &$form_state) {
-  $settings = $form_state['values']['instance']['widget']['settings'];
-  $rw = ($settings['resolution']['x']) ? $settings['resolution']['x'] : 0;
-  $rh = ($settings['resolution']['y']) ? $settings['resolution']['y'] : 0;
-
-  if ($settings['enforce_minimum'] && 
-      (!is_numeric($rw) || intval($rw) != $rw || $rw <= 0 ||
-       !is_numeric($rh) || intval($rh) != $rh || $rh <= 0)) {
-    form_error($element, t('Target resolution must be defined as WIDTH_HEIGHT if minimum is to be enforced.'));
-  }
-}
-
-
-function _imagefield_crop_widget_croparea_validate($element, &$form_state) {
-  //dpm(__FUNCTION__);
-  foreach (array('x', 'y') as $dimension) {
-		$value = $element[$dimension]['#value'];
-    if (!empty($value) && !is_numeric($value)) {
-      form_error($element[$dimension], t('The @dimension value must be numeric.', array('@dimesion' => $dimension)));
-      return;
-    }
-  }
-  form_set_value($element, intval($element['x']['#value']) . 'x' . intval($element['y']['#value']), $form_state);
-}
-
-/**
- * Implements hook_field_widget_form().
- */
-function imagefield_crop_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
-  //dpm(__FUNCTION__);
-  $elements = image_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
-  foreach (element_children($elements) as $delta) {
-    // Add all extra functionality provided by the imagefield_crop widget.
-    $elements[$delta]['#process'][] = 'imagefield_crop_widget_process';
-
-    //dpm($elements[$delta]);
-    // Register our value callback
-    $elements[$delta]['#file_value_callbacks'][] = 'imagefield_crop_widget_value';
-
-  }
-  return $elements;
-}
-
-/**
- * An element #process callback for the imagefield_crop field type.
- */
-function imagefield_crop_widget_process($element, &$form_state, $form) {
-  //dpm(__FUNCTION__);
-  //  dpm(array(__FUNCTION__, $element));
-  $item = $element['#value'];
-  $item['fid'] = $element['fid']['#value'];
-
-  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
-
-  $settings = $instance['settings'];
-  $widget_settings = $instance['widget']['settings'];
-  $element['#theme'] = 'imagefield_crop_widget';
-  $element['#description'] = t('Click on the image and drag to mark how the image will be cropped');
-
-  $path = drupal_get_path('module', 'imagefield_crop');
-  $element['#attached']['js'][] = "$path/Jcrop/js/jquery.Jcrop.js";
-  // We must define Drupal.behaviors for ahah to work, even if there is no file
-  $element['#attached']['js'][] = "$path/imagefield_crop.js";
-  $element['#attached']['css'][] = "$path/Jcrop/css/jquery.Jcrop.css";
-
-  if ($element['#file']) {
-    $file_to_crop = _imagefield_crop_file_to_crop($element['#file']->fid);
-
-    $element['preview'] = array(
-      '#type' => 'markup',
-      '#file' => $file_to_crop, // This is used by the #process function
-      '#process' => array('imagefield_crop_widget_preview_process'),
-      '#theme' => 'imagefield_crop_preview',
-      '#markup' => theme('image', array(
-                           'path' => $element['#file']->uri,
-                           'getsize' => FALSE,
-                           'attributes' => array('class' => 'preview-existing'))),
-    );
-    $element['cropbox'] = array(
-      '#markup' => theme('image', array(
-          'path' => $file_to_crop->uri,
-          'attributes' => array(
-            'class' => 'cropbox',
-            'id' => $element['#id'] . '-cropbox'))),
-    );
-    $element['cropinfo'] = _imagefield_add_cropinfo_fields($element['#file']->fid);
-    list($res_w, $res_h) = explode('x', $widget_settings['resolution']);
-    list($crop_w, $crop_h) = explode('x', $widget_settings['croparea']);
-    $settings = array(
-      $element['#id'] => array(
-        'box' => array(
-          'ratio' => $res_h ? $widget_settings['enforce_ratio'] * $res_w/$res_h : 0,
-          'box_width' => $crop_w,
-          'box_height' => $crop_h,
-        ),
-        'minimum' => array(
-          'width'   => $widget_settings['enforce_minimum'] ? $res_w : NULL,
-          'height'  => $widget_settings['enforce_minimum'] ? $res_h : NULL,
-        ),
-        //'preview' => $preview_js,
-      ),
-    );
-    $element['#attached']['js'][] = array(
-      'data' => array('imagefield_crop' => $settings),
-      'type' => 'setting',
-      'scope' => 'header',
-      );
-  }
-  
-  // prepend submit handler to remove button
-  array_unshift($element['remove_button']['#submit'], 'imagefield_crop_widget_delete');
-  
-  return $element;
-}
-
-function _imagefield_add_cropinfo_fields($fid = NULL) {
-  $defaults = array(
-    'x'       => 0,
-    'y'       => 0,
-    'width'   => 50,
-    'height'  => 50,
-    'changed' => 0,
-  );
-  if($fid) {
-  	$crop_info = variable_get('imagefield_crop_info', array());
-  	if(isset($crop_info[$fid]) && !empty($crop_info[$fid])) {
-  		$defaults = array_merge($defaults,$crop_info[$fid]);
-  	}
-  }
-
-  foreach ($defaults as $name => $default) {
-    $element[$name] = array(
-      '#type' => 'hidden',
-      '#title' => $name,
-      '#attributes' => array('class' => array('edit-image-crop-'. $name)),
-      '#default_value' => $default,
-    );
-  }
-  return $element;
-}
-
-
-function imagefield_crop_widget_preview_process($element, &$form_state, $form) {
-  //dpm(__FUNCTION__);
-  $file = $element['#file'];
-  if ($file->fid == 0) {
-    return $element;
-  }
-  // The widget belongs to the parent, so we got to find it first
-  $parents = array_slice($element['#array_parents'], 0, -1);
-  $parent = drupal_array_get_nested_value($form, $parents);
-  $instance = field_widget_instance($parent, $form_state);
-  if ($instance['widget']['settings']['resolution']) {
-    list($width, $height) = explode('x', $instance['widget']['settings']['resolution']);
-  }
-
-  $image_info = image_get_info(drupal_realpath($file->uri));
-  $settings = array(
-    $parent['#id'] => array(
-      'preview' => array(
-        'orig_width' => $image_info['width'],
-        'orig_height' => $image_info['height'],
-        'width' => (integer)$width,
-        'height' => (integer)$height,
-      ),
-    ),
-  );
-
-  $element['#attached']['js'][] = array(
-    'data' => array('imagefield_crop' => $settings),
-    'type' => 'setting',
-    'scope' => 'header',
-  );
-  $element['#imagefield_crop'] = array (
-    '#file' => $element['#file'],
-    '#width' => $width,
-    '#height' => $height,
-    '#path' => file_create_url($file->uri),
-    );
-  return $element;
-}
-
-/**
- * value callback
- *
- * Registered by imagefield_crop_field_widget_form()
- */
-function imagefield_crop_widget_value(&$element, &$input, $form_state) {
-  // set $input['fid'] and that will be the value of the element
-  if (!empty($input['fid']) && $input['cropinfo']['changed']) {
-
-    // get crop and scale info
-    $crop = $input['cropinfo'];
-    $instance = field_widget_instance($element, $form_state);
-    if ($instance['widget']['settings']['resolution']) {
-      list($scale['width'], $scale['height']) = explode('x', $instance['widget']['settings']['resolution']);
-    }
-
-    $src = file_load($input['fid']);
-    $file_to_crop = _imagefield_crop_file_to_crop($src->fid);
-    // Copy the original aside, for future cropping
-    if ($file_to_crop->fid == $src->fid &&
-        $orig_uri = file_unmanaged_copy($src->uri, $src->uri)) {
-      $orig = clone $src;
-      $orig->fid = 0;
-      $orig->uri = $orig_uri;
-      $orig->filename = basename($orig_uri);
-      $orig->status = 1;
-      $orig = file_save($orig);
-      file_usage_add($orig, 'imagefield_crop', 'file', $src->fid);
-    }
-    // do the crop. @todo check for errors
-    // This worked in D6, doesn't work in D7
-    // // Save crop data to the database
-    // $src->imagefield_crop = array('crop' => $crop);
-    // file_save($src);
-    
-    if(_imagefield_crop_resize(drupal_realpath($file_to_crop->uri), $crop, $scale, drupal_realpath($src->uri))) {
-		  // insert crop info for this image in imagefield_crop_info variable
-		  $crop_info = variable_get('imagefield_crop_info', array());
-		  unset($crop['changed']);
-		  $crop_info[$src->fid] = $crop;
-		  variable_set('imagefield_crop_info', $crop_info);
-      // Remove cached versions of the cropped image.
-      image_path_flush($src->uri);
-		}
-    
-  }
-}
-
-function imagefield_crop_widget_delete($form, &$form_state) {
-	$parents = array_slice($form_state['triggering_element']['#array_parents'], 0, -1);
-  $element = drupal_array_get_nested_value($form_state['values'], $parents);
-	$orig = _imagefield_crop_file_to_crop($element['fid']);
-	if($orig->fid != $element['fid']) {
-		file_usage_delete($orig, 'imagefield_crop');
-		file_delete($orig);
-	  $crop_info = variable_get('imagefield_crop_info', array());
-	  unset($crop_info[$element['fid']]);
-	  variable_set('imagefield_crop_info', $crop_info);
-	}
-}
-
-/*********************/
-/* Theming functions */
-/*********************/
-
-/**
- * Implements hook_theme().
- */
-function imagefield_crop_theme() {
-  return array(
-    'imagefield_crop_widget' => array(
-      'render element' => 'element'),
-    'imagefield_crop_preview' => array(
-      'render element' => 'element',
-    ),
-  );
-}
-
-function theme_imagefield_crop_widget($variables) {
-  //dpm(__FUNCTION__);
-  $element = $variables['element'];
-  $output = '';
-  $output .= '<div class="imagefield-crop-widget form-managed-file clearfix">';
-
-  //$output .= '<pre>' . print_r($element['#attached'],1) . '</pre>';
-  if (isset($element['preview'])) {
-    $output .= '<div class="imagefield-crop-preview">';
-    $output .= drupal_render($element['preview']);
-    $output .= '</div>';
-  }
-  if (isset($element['cropbox'])) {
-    $output .= '<div class="imagefield-crop-cropbox">';
-    $output .= drupal_render($element['cropbox']);
-    $output .= '</div>';
-  }
-  $output .= '</div>';
-  $output .= drupal_render_children($element);
-  return $output;
-}
-
-function theme_imagefield_crop_preview($variables) {
-  //dpm(__FUNCTION__);
-  $info = $variables['element']['#imagefield_crop'];
-  $output = '<div class="jcrop-preview-wrapper" style="width:'. $info['#width'] .'px;height:'. $info['#height'] .'px;overflow:hidden;">';
-  $output .= $variables['element']['#markup'];
-  $output .= theme('image', array('path' => $info['#path'], 'alt' => 'jcrop-preview', 'attributes' => array('class' => 'jcrop-preview', 'style' => 'display:none')));
-  $output .= '</div>';
-  return $output;
-}
-
-/*********************/
-/* Internal functions */
-/*********************/
-
-/**
- * Crop the image and resize it
- */
-function _imagefield_crop_resize($src, $crop = NULL, $scale = NULL, $dst = NULL) {
-  //dpm(__FUNCTION__);
-  $image = image_load($src);
-  if ($image) {
-    $result = TRUE;
-    if ($crop) {
-      $result = $result && image_crop($image, $crop['x'], $crop['y'], $crop['width'], $crop['height']);
-    }
-
-    if ($scale) {
-      $result = $result && image_scale_and_crop($image, $scale['width'], $scale['height']);
-    }
-
-    $result = $result && image_save($image, $dst ? $dst : $src);
-    return $result;
-  }
-
-  return FALSE;
-}
-
-function _imagefield_crop_file_to_crop($fid) {
-  // Try to find the original file for this image
-  $result = db_select('file_usage', 'fu')
-    ->fields('fu', array('fid'))
-    ->condition('module', 'imagefield_crop')
-    ->condition('type', 'file')
-    ->condition('id', $fid)
-    ->condition('count', 0, '>')
-    ->range(0,1)
-    ->execute();
-  if ($row = $result->fetch()) {
-    $fid = $row->fid;
-  }
-  return file_load($fid);
-}
+<?php
+
+/**
+ * Implements hook_field_info().
+ */
+function imagefield_crop_field_info() {
+  return array(
+    'imagefield_crop' => array(
+      'label' => t('Image cropped'),
+      'description' => t('This field stores the ID of an image file as an integer value.'),
+      'settings' => array(
+        'uri_scheme' => variable_get('file_default_scheme', 'public'),
+        'default_image' => 0,
+      ),
+      'instance_settings' => array(
+        'file_extensions' => 'png gif jpg jpeg',
+        'file_directory' => '',
+        'max_filesize' => '',
+        'alt_field' => 0,
+        'title_field' => 0,
+        'max_resolution' => '',
+        'min_resolution' => '',
+      ),
+      'default_widget' => 'imagefield_crop_widget',
+      'default_formatter' => 'image',
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function imagefield_crop_menu() {
+  $items = array();
+  
+  $items['admin/config/media/imagefield-crop'] = array(
+    'title' => t('Imagefield Crop settings'),
+    'description' => t('Provides various settings that can be changed for Imagefield Crop module'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('imagefield_crop_settings_form'),
+    'access arguments' => array('access content'),
+  );
+  
+  return $items;
+}
+
+/**
+ * Implements hook_form().
+ */
+function imagefield_crop_settings_form() {
+  $form = array();
+  
+  $form['imagefield_crop_hide_preview'] = array(
+    '#title' => t('Disable the preview pane.'),
+    '#description' => t('Disable the preview pane on an image field.'),
+    '#type' => 'checkbox',
+    '#default_value' => variable_get('imagefield_crop_hide_preview', 0),
+  );
+  
+  return system_settings_form($form);
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function imagefield_crop_field_settings_form($field, $instance) {
+  return image_field_settings_form($field, $instance);
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function imagefield_crop_field_instance_settings_form($field, $instance) {
+  return image_field_instance_settings_form($field, $instance);
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function imagefield_crop_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+  file_field_load($entity_type, $entities, $field, $instances, $langcode, $items, $age);
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function imagefield_crop_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  image_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_presave().
+ */
+function imagefield_crop_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  file_field_presave($entity_type, $entity, $field, $instance, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function imagefield_crop_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  file_field_insert($entity_type, $entity, $field, $instance, $langcode, $items);
+  foreach ($items as &$item) {
+    $scale = NULL;
+    if (!empty($instance['widget']['settings']['resolution'])) {
+      // Set scale
+      list($scale['width'], $scale['height']) = explode('x', $instance['widget']['settings']['resolution']);
+    }
+    $src = file_load($item['fid']);
+    if ($src) {
+      $orig = imagefield_crop_create_copy($src);
+      file_usage_add($orig, 'imagefield_crop', 'file', $src->fid);
+      _imagefield_crop_resize(drupal_realpath($orig->uri), $item, $scale, drupal_realpath($src->uri));
+      file_save($src);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function imagefield_crop_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+  // On new revisions, all files are considered to be a new usage and no
+  // deletion of previous file usages are necessary.
+  $scale = NULL;
+  if ($instance['widget']['settings']['resolution']) {
+    list($scale['width'], $scale['height']) = explode('x', $instance['widget']['settings']['resolution']);
+  }
+  // Create a bare-bones entity so that we can load its previous values.
+  $original = entity_create_stub_entity($entity_type, array($id, $vid, $bundle));
+  field_attach_load($entity_type, array($id => $original), FIELD_LOAD_CURRENT, array('field_id' => $field['id']));
+
+  $original_items = array();
+  if (!empty($original->{$field['field_name']}[$langcode])) {
+    foreach ($original->{$field['field_name']}[$langcode] as $original_item) {
+      $original_items[$original_item['fid']] = $original_item;
+    }
+  }
+
+  if (!empty($entity->revision)) {
+    foreach ($items as &$item) {
+      $file = file_load($item['fid']);
+      if (isset($item['cropbox_changed']) && $item['cropbox_changed']) {
+        // If fid isn't in the original id's, saved in the previous revision,
+        // then we its new file, and we need to
+        if (!in_array($item['fid'], array_keys($original_items))) {
+          $new_source_file = imagefield_crop_create_copy($file);
+          file_usage_add($new_source_file, 'imagefield_crop', 'file', $file->fid);
+          file_usage_add($file, 'file', $entity_type, $id);
+          // Prevent up-scaling if file is smaller then cropping area
+          _imagefield_crop_resize(drupal_realpath($new_source_file->uri), $item, $scale, drupal_realpath($file->uri));
+          file_save($file);
+        }
+        else {
+          $file_to_crop = _imagefield_crop_file_to_crop($file->fid);
+          $new_file = imagefield_crop_create_copy($file);
+          _imagefield_crop_resize(drupal_realpath($file_to_crop->uri), $item, $scale, drupal_realpath($new_file->uri));
+          file_usage_add($file_to_crop, 'imagefield_crop', 'file', $new_file->fid);
+          file_usage_add($new_file, 'file', $entity_type, $id);
+          file_save($new_file);
+          $item['fid'] = $new_file->fid;
+        }
+      }
+      else {
+        $file_to_crop = _imagefield_crop_file_to_crop($file->fid);
+        file_usage_add($file_to_crop, 'imagefield_crop', 'file', $file->fid);
+        file_usage_add($file, 'file', $entity_type, $id);
+      }
+      image_path_flush($file->uri);
+    }
+    return;
+  }
+
+  $current_fids = array();
+  foreach($items as $item) {
+    $current_fids[] = $item['fid'];
+    // Update files if cropping area was changed or new file has been uploaded.
+    if (isset($item['cropbox_changed']) && $item['cropbox_changed']) {
+      $file = file_load($item['fid']);
+      // Process new files
+      if (!in_array($item['fid'], array_keys($original_items))) {
+        $new_source_file = imagefield_crop_create_copy($file);
+        file_usage_add($new_source_file, 'imagefield_crop', 'file', $file->fid);
+        file_usage_add($file, 'file', $entity_type, $id);
+        _imagefield_crop_resize(drupal_realpath($new_source_file->uri), $item, $scale, drupal_realpath($file->uri));
+        file_save($file);
+      }
+      // Recropp image.
+      else {
+        $file_to_crop = _imagefield_crop_file_to_crop($file->fid);
+        _imagefield_crop_resize(drupal_realpath($file_to_crop->uri), $item, $scale, drupal_realpath($file->uri));
+        file_save($file);
+      }
+      image_path_flush($file->uri);
+    }
+  }
+
+  //Delete old files if any
+  foreach($original_items as $orig_fid => $original_item) {
+    if (!in_array($orig_fid, $current_fids)) {
+      // Decrement the file usage count by 1 and delete the file if possible.
+      file_field_delete_file($original_item, $field, $entity_type, $id);
+      $source_file = _imagefield_crop_file_to_crop($original_item['fid']);
+      if ($source_file) {
+        file_usage_delete($source_file, 'imagefield_crop', 'file', $original_item['fid']);
+        file_delete($source_file);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_delete().
+ */
+function imagefield_crop_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+  // Delete all file usages within this entity.
+  foreach(imagefield_crop_files_usage_list_by_entity($entity_type, $id) as $fid => $usage) {
+    $file = file_load($fid);
+    file_field_delete_file($file, $field, $entity_type, $id, 0);
+    $orig_file = _imagefield_crop_file_to_crop($fid);
+    if ($orig_file && $orig_file->fid != $fid) {
+      file_usage_delete($orig_file, 'imagefield_crop', NULL, NULL, 0);
+      file_delete($orig_file);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_delete_revision().
+ */
+function imagefield_crop_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach ($items as $delta => $item) {
+    // Decrement the file usage count by 1 and delete the file if possible.
+    if (file_field_delete_file($item, $field, $entity_type, $id)) {
+      $orig_file = _imagefield_crop_file_to_crop($item['fid']);
+      if ($orig_file && $orig_file->fid != $item['fid']) {
+        file_usage_delete($orig_file, 'imagefield_crop', 'file', $item['fid']);
+        file_delete($orig_file);
+      }
+      $items[$delta] = NULL;
+    }
+  }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function imagefield_crop_field_is_empty($item, $field) {
+  return file_field_is_empty($item, $field);
+}
+
+/**
+ * Implements hook__crop_field_formatter_info_alter().
+ */
+function imagefield_crop_field_formatter_info_alter(&$info) {
+  // Let a new field type re-use an existing formatter.
+  $info['image']['field types'][] = 'imagefield_crop';
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function imagefield_crop_field_widget_info() {
+  return array(
+    'imagefield_crop_widget' => array(
+      'label' => t('Image with cropping'),
+      'field types' => array('imagefield_crop'),
+      'settings' => array(
+        'progress_indicator' => 'throbber',
+        'preview_image_style' => 'thumbnail',
+        'collapsible' => 2,
+        'resolution' => '200x150',
+        'validate_resolution' => 0,
+        'enforce_ratio' => true,
+        'custom_ratio' => '',
+        'enforce_minimum' => true,
+        'croparea' => '500x500',
+      ),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+        'default value' => FIELD_BEHAVIOR_NONE,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function imagefield_crop_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'];
+
+  // Use the image widget settings form.
+  $form = image_field_widget_settings_form($field, $instance);
+
+  $form['collapsible'] = array(
+    '#type' => 'radios',
+    '#title' => t('Collapsible behavior'),
+    '#options' => array(
+      1 => t('None.'),
+      2 => t('Collapsible, expanded by default.'),
+      3 => t('Collapsible, collapsed by default.'),
+    ),
+    '#default_value' => $settings['collapsible'],
+  );
+
+  // Resolution settings.
+  $resolution = explode('x', $settings['resolution']) + array('', '');
+  $form['resolution'] = array(
+    '#title' => t('The resolution to crop the image onto'),
+    '#element_validate' => array('_image_field_resolution_validate'),
+    '#theme_wrappers' => array('form_element'),
+    '#description' => t('The output resolution of the cropped image, expressed as WIDTHxHEIGHT (e.g. 640x480). Leave blank to skip rescale after cropping. Note: output resolution must be defined in order to present a dynamic preview.'),
+  );
+  $form['resolution']['x'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $resolution[0],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' x ',
+    '#theme_wrappers' => array(),
+  );
+  $form['resolution']['y'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $resolution[1],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' ' . t('pixels'),
+    '#theme_wrappers' => array(),
+  );
+  $form['validate_resolution'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Validate minimum resolution'),
+    '#default_value' => $settings['validate_resolution'],
+    '#description' => t('If output resolution is set, but validation is disabled then images with smaller dimensions won\'t be cropped.'),
+    '#states' => array(
+      'invisible' => array(
+        'input[name="instance[widget][settings][resolution][x]"]' => array('value' => ''),
+        'input[name="instance[widget][settings][resolution][y]"]' => array('value' => ''),
+      ),
+    )
+  );
+  $form['enforce_ratio'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enforce crop box ratio'),
+    '#default_value' => $settings['enforce_ratio'],
+    '#description' => t('Check this to force the ratio of the output on the crop box. NOTE: If you leave this unchecked but enforce an output resolution, the final image might be distorted'),
+    '#element_validate' => array('_imagefield_crop_widget_enforce_ratio_validate'),
+  );
+
+  $custom_ratio = explode('x', $settings['custom_ratio']) + array('', '');
+  $form['custom_ratio'] = array(
+    '#type' => 'container',
+    '#title' => t('Custom ratio'),
+    '#element_validate' => array('_image_field_resolution_validate', '_imagefield_crop_widget_custom_ratio_validate'),
+    '#theme_wrappers' => array('form_element'),
+    '#description' => t('Ratio for crop area. For example 4:3 or 16:9 as width to height.'),
+    '#markup' => '',
+    '#states' => array(
+      'visible' => array(
+        'input[name="instance[widget][settings][resolution][x]"]' => array('value' => ''),
+        'input[name="instance[widget][settings][resolution][y]"]' => array('value' => ''),
+        'input[name="instance[widget][settings][enforce_ratio]"]' => array('checked' => TRUE),
+      ),
+    )
+  );
+  $form['custom_ratio']['x'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $custom_ratio[0],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' x ',
+    '#theme_wrappers' => array(),
+  );
+  $form['custom_ratio']['y'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $custom_ratio[1],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' ' . t('pixels'),
+    '#theme_wrappers' => array(),
+  );
+  $form['enforce_minimum'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enforce minimum crop size based on the output size'),
+    '#default_value' => $settings['enforce_minimum'],
+    '#description' => t('Check this to force a minimum cropping selection equal to the output size. NOTE: If you leave this unchecked you might get zoomed pixels if the cropping area is smaller than the output resolution.'),
+    '#element_validate' => array('_imagefield_crop_widget_enforce_minimum_validate'),
+  );
+
+  // Crop area settings
+  $croparea = explode('x', $settings['croparea']) + array('', '');
+  $form['croparea'] = array(
+    '#title' => t('The resolution of the cropping area'),
+    '#element_validate' => array('_imagefield_crop_widget_croparea_validate'),
+    '#theme_wrappers' => array('form_element'),
+    '#description' => t('The resolution of the area used for the cropping of the image. Image will displayed at this resolution for cropping. Use WIDTHxHEIGHT format, empty or zero values are permitted, e.g. 500x will limit crop box to 500 pixels width.'),
+  );
+  $form['croparea']['x'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $croparea[0],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' x ',
+    '#theme_wrappers' => array(),
+  );
+  $form['croparea']['y'] = array(
+    '#type' => 'textfield',
+    '#default_value' => $croparea[1],
+    '#size' => 5,
+    '#maxlength' => 5,
+    '#field_suffix' => ' ' . t('pixels'),
+    '#theme_wrappers' => array(),
+  );
+
+  return $form;
+}
+
+function _imagefield_crop_widget_custom_ratio_validate($element, &$form_state) {
+  $settings = $form_state['values']['instance']['widget']['settings'];
+  // _image_field_resolution_validate() does most of the validation
+  // If enforce ratio is checked and resolution is not, then check for custom ratio.
+  if ($settings['enforce_ratio'] && empty($settings['resolution']) && empty($element['x']['#value'])) {
+    form_error($element, t('<em>Custom ratio</em> must be defined as WIDTH:HEIGHT if <em>Enforce crop box ratio</em> is set and output resolution is not defined'));
+  }
+}
+
+function _imagefield_crop_widget_enforce_ratio_validate($element, &$form_state) {
+  $settings = $form_state['values']['instance']['widget']['settings'];
+  if (!empty($settings['resolution']) && !$element['#value']) {
+    drupal_set_message(t('Output resolution is defined, but not enforced. Final images might be distroted'));
+  }
+}
+
+function _imagefield_crop_widget_enforce_minimum_validate($element, &$form_state) {
+  $settings = $form_state['values']['instance']['widget']['settings'];
+  if (is_array($settings['resolution'])) {
+    $rw = ($settings['resolution']['x']) ? $settings['resolution']['x'] : 0;
+    $rh = ($settings['resolution']['y']) ? $settings['resolution']['y'] : 0;
+  }
+  else {
+    list($rw, $rh) = !empty($settings['resolution']) ? explode('x', $settings['resolution']) : array(0, 0);
+  }
+
+  if ($settings['enforce_minimum'] &&
+      (!is_numeric($rw) || intval($rw) != $rw || $rw <= 0 ||
+       !is_numeric($rh) || intval($rh) != $rh || $rh <= 0)) {
+    form_error($element, t('Target resolution must be defined as WIDTH_HEIGHT if minimum is to be enforced.'));
+  }
+}
+
+function _imagefield_crop_widget_croparea_validate($element, &$form_state) {
+  foreach (array('x', 'y') as $dimension) {
+    $value = $element[$dimension]['#value'];
+    if (!empty($value) && !is_numeric($value)) {
+      form_error($element[$dimension], t('The @dimension value must be numeric.', array('@dimesion' => $dimension)));
+      return;
+    }
+  }
+  form_set_value($element, intval($element['x']['#value']) . 'x' . intval($element['y']['#value']), $form_state);
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function imagefield_crop_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $elements = image_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
+  foreach (element_children($elements) as $delta) {
+    $elements[$delta]['#value_callback'] = 'imagefield_crop_value_callback';
+    // Add all extra functionality provided by the imagefield_crop widget.
+    $elements[$delta]['#process'][] = 'imagefield_crop_widget_process';
+    $elements[$delta]['#upload_validators']['imagefield_crop_upload_validate'] = array($field, $instance);
+  }
+  return $elements;
+}
+
+/**
+ * An element #process callback for the imagefield_crop field type.
+ */
+function imagefield_crop_widget_process($element, &$form_state, $form) {
+  $item = $element['#value'];
+  $item['fid'] = $element['fid']['#value'];
+
+  $instance = $form_state['field'][$element['#field_name']][$element['#language']]['instance'];
+
+  $settings = $instance['settings'];
+  $widget_settings = $instance['widget']['settings'];
+  $element['#theme'] = 'imagefield_crop_widget';
+  $element['#description'] = t('Click on the image and drag to mark how the image will be cropped');
+
+  $path = drupal_get_path('module', 'imagefield_crop');
+  $element['#attached']['js'][] = "$path/Jcrop/js/jquery.Jcrop.js";
+  // We must define Drupal.behaviors for ahah to work, even if there is no file
+  $element['#attached']['js'][] = "$path/imagefield_crop.js";
+  $element['#attached']['css'][] = "$path/Jcrop/css/jquery.Jcrop.css";
+
+  if ($element['#file']) {
+    $file_to_crop = _imagefield_crop_file_to_crop($element['#file']->fid);
+    if (!empty($widget_settings['resolution'])) {
+      $element['preview'] = array(
+        '#type' => 'markup',
+        '#file' => $file_to_crop, // This is used by the #process function
+        '#process' => array('imagefield_crop_widget_preview_process'),
+        '#theme' => 'imagefield_crop_preview',
+        '#markup' => theme('image', array(
+          'path' => $element['#file']->uri,
+          'getsize' => FALSE,
+          'attributes' => array('class' => 'preview-existing'))
+        ),
+      );
+    }
+    else {
+      unset($element['preview']);
+    }
+    $element['cropbox'] = array(
+      '#markup' => theme('image', array(
+        'path' => $file_to_crop->uri,
+        'attributes' => array(
+          'class' => 'cropbox',
+          'id' => $element['#id'] . '-cropbox'))),
+    );
+    // Get image info to find out dimensions.
+    $image_info = image_get_info(drupal_realpath($file_to_crop->uri));
+    // if ratio is set, then set default cropping area to this size.
+    // else set maximum allowed size, using image dimensions. Js will handle the rest and appropriate size will be set.
+    if ($widget_settings['enforce_ratio'] && !empty($widget_settings['resolution'])) {
+      list($crop_area_width, $crop_area_height) = explode('x', $widget_settings['resolution']);
+    }
+    else {
+      list($crop_area_width, $crop_area_height) = array($image_info['width'], $image_info['height']);
+    }
+    $element['cropbox_x'] = array(
+      '#type' => 'hidden',
+      '#attributes' => array('class' => array('edit-image-crop-x')),
+      '#default_value' => isset($item['cropbox_x']) ? $item['cropbox_x'] : 0,
+    );
+    $element['cropbox_y'] = array(
+      '#type' => 'hidden',
+      '#attributes' => array('class' => array('edit-image-crop-y')),
+      '#default_value' => isset($item['cropbox_y']) ? $item['cropbox_y'] : 0,
+    );
+    $element['cropbox_height'] = array(
+      '#type' => 'hidden',
+      '#attributes' => array('class' => array('edit-image-crop-height')),
+      '#default_value' => isset($item['cropbox_height']) ? $item['cropbox_height'] : $crop_area_height,
+    );
+    $element['cropbox_width'] = array(
+      '#type' => 'hidden',
+      '#attributes' => array('class' => array('edit-image-crop-width')),
+      '#default_value' => isset($item['cropbox_width']) ? $item['cropbox_width'] : $crop_area_width,
+    );
+    $element['cropbox_changed'] = array(
+      '#type' => 'hidden',
+      '#attributes' => array('class' => array('edit-image-crop-changed')),
+      '#default_value' => isset($item['cropbox_changed']) ? $item['cropbox_changed'] : 0,
+    );
+
+    list($res_w, $res_h) = !empty($widget_settings['resolution']) ? explode('x', $widget_settings['resolution']) : array(0, 0);
+    list($crop_w, $crop_h) = explode('x', $widget_settings['croparea']);
+
+    $ratio = NULL;
+    // Enforce ratio is set
+    if ($widget_settings['enforce_ratio']) {
+      // If resolution is set, then calculate ratio from output resolution
+      // else use values set in custom ratio fields.
+      list($custom_ration_w, $custom_ration_h) = !empty($widget_settings['resolution']) ? explode('x', $widget_settings['resolution']) : explode('x', $widget_settings['custom_ratio']);
+      $ratio = $custom_ration_w / $custom_ration_h;
+    }
+    $settings = array(
+      $element['#id'] => array(
+        'box' => array(
+          'ratio' => isset($ratio) ? $ratio : 0,
+          'box_width' => $crop_w,
+          'box_height' => $crop_h,
+        ),
+        'minimum' => array(
+          'width' => $widget_settings['enforce_minimum'] ? $res_w : NULL,
+          'height' => $widget_settings['enforce_minimum'] ? $res_h : NULL,
+        ),
+      ),
+    );
+    $element['#attached']['js'][] = array(
+      'data' => array('imagefield_crop' => $settings),
+      'type' => 'setting',
+      'scope' => 'header',
+    );
+  }
+
+  return $element;
+}
+
+function imagefield_crop_widget_preview_process($element, &$form_state, $form) {
+  $file = $element['#file'];
+  if ($file->fid == 0) {
+    return $element;
+  }
+  // The widget belongs to the parent, so we got to find it first
+  $parents = array_slice($element['#array_parents'], 0, -1);
+  $parent = drupal_array_get_nested_value($form, $parents);
+  $instance = field_widget_instance($parent, $form_state);
+  list($width, $height) = !empty($instance['widget']['settings']['resolution']) ? explode('x', $instance['widget']['settings']['resolution']) : array(0, 0);
+
+  $image_info = image_get_info(drupal_realpath($file->uri));
+  $settings = array(
+    $parent['#id'] => array(
+      'preview' => array(
+        'orig_width' => $image_info['width'],
+        'orig_height' => $image_info['height'],
+        'width' => (integer)$width,
+        'height' => (integer)$height,
+      ),
+    ),
+  );
+
+  $element['#attached']['js'][] = array(
+    'data' => array('imagefield_crop' => $settings),
+    'type' => 'setting',
+    'scope' => 'header',
+  );
+  $element['#imagefield_crop'] = array(
+    '#file' => $element['#file'],
+    '#width' => $width,
+    '#height' => $height,
+    '#path' => file_create_url($file->uri),
+  );
+  return $element;
+}
+
+/*********************/
+/* Theming functions */
+/*********************/
+
+/**
+ * Implements hook_theme().
+ */
+function imagefield_crop_theme() {
+  return array(
+    'imagefield_crop_widget' => array(
+      'render element' => 'element'),
+    'imagefield_crop_preview' => array(
+      'render element' => 'element',
+    ),
+  );
+}
+
+function theme_imagefield_crop_widget($variables) {
+  $element = $variables['element'];
+  $output = '';
+  $output .= '<div class="imagefield-crop-widget form-managed-file clearfix">';
+
+  if (isset($element['preview'])) {
+    $output .= '<div class="imagefield-crop-preview">';
+    $output .= drupal_render($element['preview']);
+    $output .= '</div>';
+  }
+  if (isset($element['cropbox'])) {
+    $output .= '<div class="imagefield-crop-cropbox">';
+    $output .= drupal_render($element['cropbox']);
+    $output .= '</div>';
+  }
+  $output .= '</div>';
+  $output .= drupal_render_children($element);
+  return $output;
+}
+
+function theme_imagefield_crop_preview($variables) {
+  if(variable_get('imagefield_crop_hide_preview', 0) != 1) {
+    $info = $variables['element']['#imagefield_crop'];
+    $output = '<div class="jcrop-preview-wrapper" style="width:' . $info['#width'] . 'px;height:' . $info['#height'] . 'px;overflow:hidden;">';
+    $output .= $variables['element']['#markup'];
+    $output .= theme('image', array('path' => $info['#path'], 'alt' => 'jcrop-preview', 'attributes' => array('class' => 'jcrop-preview', 'style' => 'display:none')));
+    $output .= '</div>';
+    return $output;
+  }
+}
+
+/*********************/
+/* Internal functions */
+/*********************/
+
+/**
+ * Crop the image and resize it
+ */
+function _imagefield_crop_resize($src, $input = NULL, $scale = NULL, $dst = NULL) {
+  $image = image_load($src);
+  if ($image) {
+    $result = TRUE;
+    if ($input) {
+      $result = $result && image_crop($image, $input['cropbox_x'], $input['cropbox_y'], $input['cropbox_width'], $input['cropbox_height']);
+    }
+
+    if ($scale && $scale['width'] < $input['cropbox_width'] && $scale['height'] < $input['cropbox_height']) {
+      $result = $result && image_scale_and_crop($image, $scale['width'], $scale['height']);
+    }
+
+    $result = $result && image_save($image, $dst ? $dst : $src);
+    return $result;
+  }
+
+  return FALSE;
+}
+
+function _imagefield_crop_file_to_crop($fid) {
+  // Try to find the original file for this image
+  $source_fid = db_select('file_usage', 'fu')
+    ->fields('fu', array('fid'))
+    ->condition('module', 'imagefield_crop')
+    ->condition('type', 'file')
+    ->condition('id', $fid)
+    ->condition('count', 0, '>')
+    ->range(0, 1)
+    ->execute()
+    ->fetchField();
+  if ($source_fid) {
+    return file_load($source_fid);
+  }
+  return file_load($fid);
+}
+
+/**
+ * Returns file usages by entity.
+ */
+function imagefield_crop_files_usage_list_by_entity($entity_type, $entity_id) {
+  $result = db_select('file_usage', 'f')
+    ->fields('f', array('fid', 'module', 'type', 'id', 'count'))
+    ->condition('type', $entity_type)
+    ->condition('id', $entity_id)
+    ->condition('count', 0, '>')
+    ->execute();
+  $references = array();
+  foreach ($result as $usage) {
+    $references[$usage->fid] = $usage;
+  }
+  return $references;
+}
+
+/**
+ * Element value callback. Used to set crop area to image size, if image is smaller then
+ * output resolution, but validation isn't enabled.
+ * @param $element
+ * @param bool $input
+ * @param $form_state
+ * @return array|bool
+ */
+function imagefield_crop_value_callback($element, $input = FALSE, $form_state) {
+  // We depend on the managed file element to handle uploads.
+  $return = file_field_widget_value($element, $input, $form_state);
+  if ($input) {
+    if ($input['fid'] == 0 && $return['fid']) {
+      $return['cropbox_changed'] = 1;
+    }
+    $instance = field_widget_instance($element, $form_state);
+    $widget_settings = $instance['widget']['settings'];
+    if ($input['fid'] && $widget_settings['enforce_ratio'] && !empty($widget_settings['resolution'])) {
+      $file = file_load($input['fid']);
+      if ($file) {
+        $image_info = image_get_info(drupal_realpath($file->uri));
+        $return['cropbox_x'] = $input['cropbox_x'] < 0 ? 0 : $input['cropbox_x'];
+        $return['cropbox_y'] = $input['cropbox_y'] < 0 ? 0 : $input['cropbox_y'];
+        $return['cropbox_width'] = $input['cropbox_width'] > $image_info['width'] ? $image_info['width'] : $input['cropbox_width'];
+        $return['cropbox_height'] = $input['cropbox_height'] > $image_info['height'] ? $image_info['height'] : $input['cropbox_height'];
+      }
+    }
+  }
+
+  return $return;
+}
+
+/**
+ * Validate function for images to be cropped.
+ * Returns an error if output resolution for field is set, but file is smaller.
+ * @param $file
+ * @param $field
+ * @param $instance
+ * @return array
+ */
+function imagefield_crop_upload_validate($file, $field, $instance) {
+  $errors = array();
+  $widget_settings = $instance['widget']['settings'];
+  $info = image_get_info($file->uri);
+  if ($info && $widget_settings['validate_resolution'] && $widget_settings['enforce_ratio'] && !empty($widget_settings['resolution'])) {
+    list($width, $height) = explode('x', $widget_settings['resolution']);
+      if ($info['width'] < $width || $info['height'] < $height) {
+        $errors[] = t('The image is too small; the minimum dimensions are %dimensions pixels.', array('%dimensions' => $widget_settings['resolution']));
+      }
+  }
+  return $errors;
+}
+
+/**
+ * Creates a copy of the file.
+ * @param $file
+ * @return stdClass
+ */
+function imagefield_crop_create_copy($file) {
+  $new_uri = file_unmanaged_copy($file->uri, $file->uri);
+  $new_file = clone $file;
+  $new_file->fid = 0;
+  $new_file->status = FILE_STATUS_PERMANENT;
+  $new_file->uri = $new_uri;
+  $new_file->filename = basename($new_uri);
+  return file_save($new_file);
+}
\ No newline at end of file
