manualcrop.helpers.inc in Manual Crop 7
Helper functions for the Manual Crop module.
File
manualcrop.helpers.incView source
<?php
/**
* @file
* Helper functions for the Manual Crop module.
*/
/**
* Returns an array of supported widget types or checks if a type is supported.
*
* @param $widget_type
* If set, this function will return a boolean indicating if $widget_type
* is supported.
* @param $settings
* Only include widgets that support these setting(s).
*
* @return
* Array of widget types.
*/
function manualcrop_supported_widgets($widget_type = NULL, $settings = array()) {
$widgets =& drupal_static(__FUNCTION__);
if (!isset($widgets)) {
// Collect information about the supported widgets.
$widgets = module_invoke_all('manualcrop_supported_widgets');
drupal_alter('manualcrop_supported_widgets', $widgets);
}
// Make sure $settings contains only valid entries.
if (!empty($settings)) {
if (!is_array($settings)) {
$settings = array(
$settings,
);
}
$widget_settings = manualcrop_manualcrop_supported_widgets();
$widget_settings = $widget_settings['image_image'];
$settings = array_intersect($settings, $widget_settings);
}
if (empty($settings)) {
// No settings required.
$result = array_keys($widgets);
}
else {
// Filter all widgets that don't support the required settings.
$result = array();
foreach ($widgets as $name => $widget_settings) {
if (!count(array_diff($settings, $widget_settings))) {
$result[] = $name;
}
}
}
if (!empty($widget_type)) {
return in_array($widget_type, $result);
}
else {
return $result;
}
}
/**
* Returns the default widget settings.
*
* @return
* Array of default widget settings.
*/
function manualcrop_default_widget_settings() {
$defaults = array(
// Enable Manual Crop?
'manualcrop_enable' => FALSE,
// Enable keyboard shortcuts?
'manualcrop_keyboard' => TRUE,
// Show a list of thubnails instead of a selection list or button?
'manualcrop_thumblist' => FALSE,
// Enable inline cropping?
'manualcrop_inline_crop' => FALSE,
// Show the crop info (width, height...)?
'manualcrop_crop_info' => TRUE,
// Automatically update the preview image?
'manualcrop_instant_preview' => TRUE,
// Open the crop tool after uploading?
'manualcrop_instant_crop' => FALSE,
// Show a default crop area when opening an uncropped image?
'manualcrop_default_crop_area' => TRUE,
// Maximize the default crop area?
'manualcrop_maximize_default_crop_area' => FALSE,
// Exclude or include the selected styles?
'manualcrop_styles_mode' => 'include',
// List of selected styles.
'manualcrop_styles_list' => array(),
// List of required crop selections.
'manualcrop_require_cropping' => array(),
);
if (module_exists('insert')) {
// Filter all styles without a Manual Crop effect?
$defaults['manualcrop_filter_insert'] = TRUE;
}
return $defaults;
}
/**
* Get the list of required image styles from the widget settings.
*
* @param $settings
* Widget settings array.
*
* @return
* List of required image styles.
*/
function manualcrop_instance_required_styles($settings) {
// Make sure to exclude unavailable styles.
if (!empty($settings['manualcrop_require_cropping'])) {
if ($settings['manualcrop_styles_mode'] == 'include' && !empty($settings['manualcrop_styles_list'])) {
return array_intersect($settings['manualcrop_require_cropping'], $settings['manualcrop_styles_list']);
}
elseif ($settings['manualcrop_styles_mode'] == 'exclude') {
return array_diff($settings['manualcrop_require_cropping'], $settings['manualcrop_styles_list']);
}
}
return array();
}
/**
* Add a croptool to the form element. This extends the FAPI widget or simply adds
* a new form item to enable cropping in a regular form.
*
* @param $form
* The form array.
* @param $form_state
* The form state array.
* @param $element
* Form element to be processed. It's preferred to use the form array for
* none-FAPI fields.
* @param $file
* The file object.
* @param $settings
* Used to pass-in (additional) widget settings, these settings will
* override the instance settings.
* @param $instance
* Field instance array.
* @param $preview
* Name of the preview element.
*
* @return
* Returns TRUE if a croptool has been added, FALSE otherwise.
*/
function manualcrop_croptool_process(&$form, &$form_state, &$element, $file, $settings = array(), $instance = NULL, $preview = 'preview') {
static $processed_forms;
if (_manualcrop_supported_file($file) && user_access('use manualcrop') && ($styles = manualcrop_styles_with_crop())) {
// Merge-in the instance or default settings.
if (is_array($instance)) {
$settings += $instance['widget']['settings'];
}
else {
$settings += manualcrop_default_widget_settings();
}
// Exclude or include styles.
if (!empty($settings['manualcrop_styles_list'])) {
if ($settings['manualcrop_styles_mode'] == 'include') {
$styles = array_intersect_key($styles, $settings['manualcrop_styles_list']);
}
else {
$styles = array_diff_key($styles, $settings['manualcrop_styles_list']);
}
if (empty($styles)) {
// Leave if all styles were filtered.
return FALSE;
}
}
// Required image styles.
$required = manualcrop_instance_required_styles($settings);
// Make sure the build id exists.
if (!isset($form['#build_id'])) {
$form['#build_id'] = 'form-' . drupal_random_key();
}
// Reset the data array.
if (!isset($processed_forms[$form['#build_id']])) {
$processed_forms[$form['#build_id']] = $form['#build_id'];
$form_state['manualcrop_data'] = array();
}
// Get the container and item reference.
if (is_array($instance)) {
// A FAPI field instance has been passed, so $element is the container
// and $element['#value'] can be used for storing data.
$container =& $element;
$value =& $element['#value'];
}
else {
// The FAPI is not used, we'll create a manualcrop container as parent
// for all manualcrop enabled files.
if (!isset($element['manualcrop'])) {
$element['manualcrop'] = array(
'#tree' => TRUE,
);
}
// Create a file specific container.
$element['manualcrop']['file_' . $file->fid] = array(
'#type' => 'value',
'#default_value' => array(),
'#element_validate' => array(
'manualcrop_croptool_validate',
),
'#parents' => array(
'manualcrop',
'file_' . $file->fid,
),
);
// Link to the newly created container and item.
$container =& $element['manualcrop']['file_' . $file->fid];
$value =& $container['#default_value'];
}
// Alter the preview element if it exists and the thumblist option isn't enabled.
if (empty($settings['manualcrop_thumblist']) && isset($preview) && isset($element[$preview])) {
$element[$preview] += array(
'#prefix' => '',
'#suffix' => '',
);
$element[$preview]['#prefix'] = '<div class="manualcrop-preview manualcrop-preview-' . $file->fid . '"><div class="manualcrop-preview-cropped"></div>' . $element[$preview]['#prefix'];
$element[$preview]['#suffix'] .= '</div>';
}
// Save some image data to improve processing.
$image = image_get_info($file->uri);
$form_state['manualcrop_data']['images'][$file->fid] = array(
'uri' => $file->uri,
'filename' => $file->filename,
'width' => $image['width'],
'height' => $image['height'],
'element_parents' => $container['#parents'],
'required_styles' => $required,
);
// Get the crop selections for this file.
$submitted = isset($form_state['inline_entity_form']) ? FALSE : $form_state['submitted'];
if (!$submitted && !isset($value['manualcrop_selections'])) {
$value['manualcrop_selections'] = array();
foreach (manualcrop_load_crop_selection($file->uri) as $data) {
$value['manualcrop_selections'][$data->style_name] = $data->x . '|' . $data->y . '|' . $data->width . '|' . $data->height;
}
}
// Add the dependencies and croptool.
$js_identifier = _manualcrop_js_identifier(is_array($instance) ? $instance : $file);
_manualcrop_attach_dependencies($element, $form_state, $js_identifier, $settings);
_manualcrop_add_croptool($container, $value, $form_state, $file->fid, $js_identifier, $styles, $required, $settings);
return TRUE;
}
return FALSE;
}
/**
* Adds the #after_build entry to a media element.
*
* @param $element
* The element to alter.
*
* @return
* TRUE if the element was altered, FALSE otherwise.
*/
function _manualcrop_media_element_add_after_build(&$element) {
if (isset($element['#media_options']['global']) && isset($element['#entity_type']) && isset($element['#bundle'])) {
$element['#after_build'][] = 'manualcrop_media_element_after_build';
return TRUE;
}
return FALSE;
}
/**
* Get the unique javascript crop settings identifier.
*
* @param $data
* Field instance array (preferred) or file object.
*
* @return
* Unique javascript crop settings identifier.
*/
function _manualcrop_js_identifier($data) {
if (is_array($data) && !empty($data['field_name'])) {
return drupal_clean_css_identifier($data['field_name']);
}
elseif (is_object($data) && isset($data->fid)) {
return 'manualcrop-file-' . $data->fid;
}
else {
return 'manualcrop-' . md5(serialize($data));
}
}
/**
* Attach the required croptool dependencies (files and settings).
*
* @param $element
* The form element.
* @param $form_state,
* The form state array.
* @param $js_identifier
* Unique javascript crop settings identifier.
* @param $settings
* Widget settings.
*/
function _manualcrop_attach_dependencies(&$element, $form_state, $js_identifier, $settings = array()) {
// Attach the required files.
_manualcrop_attach_files($element);
$added[$js_identifier] = $form_state['rebuild'];
// Generate image style settings.
$styles =& drupal_static(__FUNCTION__);
if (!is_array($styles)) {
$styles = array();
foreach (manualcrop_styles_with_crop() as $style_name => $data) {
$styles[$style_name] = array(
'effect' => $data['effect']['name'],
'data' => $data['effect']['data'],
'label' => $data['label'],
);
}
}
// Attach the element settings.
$element['#attached']['js'][] = array(
'data' => array(
'manualcrop' => array(
'styles' => $styles,
'elements' => array(
$js_identifier => array(
'keyboard' => !empty($settings['manualcrop_keyboard']),
'required' => manualcrop_instance_required_styles($settings),
'instantCrop' => !empty($settings['manualcrop_instant_crop']),
'defaultCropArea' => !empty($settings['manualcrop_default_crop_area']),
'maximizeDefaultCropArea' => !empty($settings['manualcrop_maximize_default_crop_area']),
),
),
),
),
'type' => 'setting',
);
}
/**
* Attach the required css, javascript and libraries.
*
* @param $element
* The form element on which the files should be attached. Use to NULL
* to invoke the Internet Explorer lazy loading css fix.
*/
function _manualcrop_attach_files(&$element = NULL) {
$ie = !empty($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== FALSE;
if ($ie || $element) {
$path = drupal_get_path('module', 'manualcrop');
if ($ie) {
// IE has some issues with the lazy loading of css files, so we preload
// anything that contains CSS. See http://drupal.org/node/1071818 for more info.
drupal_add_css($path . '/manualcrop.css');
libraries_load('jquery.imgareaselect');
}
if ($element) {
$element['#attached']['css'][] = $path . '/manualcrop.css';
$element['#attached']['js'][] = $path . '/manualcrop.js';
$element['#attached']['libraries_load'][] = array(
'jquery.imgareaselect',
);
$element['#attached']['libraries_load'][] = array(
'jquery.imagesloaded',
);
}
}
}
/**
* Add the actual croptool to a form element.
*
* @param $element
* The form element to add the croptool to.
* @param $value
* The element value storage.
* @param $form_state
* The form state array.
* @param $fid
* The file id.
* @param $js_identifier
* Unique javascript crop settings identifier.
* @param $styles
* Info of the active image styles, keyed by name.
* @param $required
* Array of required image styles.
* @param $settings
* Widget settings.
*/
function _manualcrop_add_croptool(&$element, $value, &$form_state, $fid, $js_identifier, $styles, $required = array(), $settings = array()) {
// Get the fileinfo.
$file_info = $form_state['manualcrop_data']['images'][$fid];
// Overlay or inline cropping.
if (!empty($settings['manualcrop_inline_crop'])) {
$crop_type = 'inline';
}
else {
$crop_type = 'overlay';
}
// Add a css class
$element['#attributes']['class'][] = 'manualcrop-file-' . $fid . '-holder';
// Original image for cropping.
$element['manualcrop_' . $crop_type] = array(
'#theme' => 'manualcrop_croptool_' . $crop_type,
'#attributes' => array(
'id' => array(
'manualcrop-' . $crop_type . '-' . $fid,
),
'class' => array(
'manualcrop-' . $crop_type,
'element-hidden',
),
),
'#image' => array(
'path' => $file_info['uri'],
'alt' => $file_info['filename'],
'width' => $file_info['width'],
'height' => $file_info['height'],
'attributes' => array(
'class' => array(
'manualcrop-image',
),
),
),
'#crop_info' => !empty($settings['manualcrop_crop_info']),
'#instant_preview' => !empty($settings['manualcrop_instant_preview']),
);
// Image style options.
$style_options = array(
'' => t('Select a style to crop'),
);
// Hidden fields to save the crop selection, one for each image style.
foreach ($styles as $style_name => $info) {
$element['manualcrop_selections'][$style_name] = array(
'#type' => 'hidden',
'#default_value' => isset($value['manualcrop_selections'][$style_name]) ? $value['manualcrop_selections'][$style_name] : '',
'#attributes' => array(
'id' => 'manualcrop-area-' . $fid . '-' . $style_name,
'class' => array(
'manualcrop-cropdata',
),
'onchange' => 'ManualCrop.selectionStored(this, ' . $fid . ', \'' . $style_name . '\');',
),
);
$style_options[$style_name] = $info['label'];
}
// Default form element options.
$defaults = array(
'#weight' => isset($element['title']['#weight']) ? $element['title']['#weight'] : 1,
);
// Element to open the croptool.
if (!empty($settings['manualcrop_thumblist'])) {
// Thumbnail list, each image style is transformed in a clickable thumbnail.
array_shift($style_options);
foreach ($style_options as $style_name => $style_clean_name) {
$prefix = '<span class="manualcrop-preview manualcrop-preview-' . $fid . ' manualcrop-preview-' . $fid . '-' . $style_name . '"><span class="manualcrop-preview-cropped"></span>';
$suffix = '</span>';
$style_options[$style_name] = theme('manualcrop_thumblist_image', array(
'style' => $style_clean_name,
'image' => $prefix . theme('image_style', array(
'path' => $file_info['uri'],
'alt' => $file_info['filename'],
'width' => $file_info['width'],
'height' => $file_info['height'],
'style_name' => $style_name,
)) . $suffix,
'attributes' => array(
'class' => array_merge(array(
'manualcrop-style-thumb',
'manualcrop-style-thumb-' . $fid,
'manualcrop-style-thumb-' . $fid . '-' . $style_name,
'manualcrop-style-preview-' . $fid,
'manualcrop-style-preview-' . $fid . '-' . $style_name,
), in_array($style_name, $required) ? array(
'manualcrop-style-required',
) : array()),
'href' => 'javascript:void(0);',
'onmousedown' => "ManualCrop.showCroptool('" . $js_identifier . "', '" . $style_name . "', " . $fid . ");",
'onclick' => 'return false;',
),
));
}
$element['manualcrop_style'] = array_merge($defaults, array(
'#markup' => theme('manualcrop_thumblist', array(
'attributes' => array(
'class' => array(
'manualcrop-thumblist',
'manualcrop-thumblist-' . $fid,
),
),
'images' => $style_options,
)),
));
}
elseif (count($style_options) == 2) {
// Only one style, display a button.
end($style_options);
$style_name = key($style_options);
$element['manualcrop_style'] = array_merge($defaults, array(
'#type' => 'button',
'#value' => t('Crop'),
'#attributes' => array(
'class' => array_merge(array(
'manualcrop-style-button',
'manualcrop-style-button-' . $fid,
), in_array($style_name, $required) ? array(
'manualcrop-style-required',
) : array()),
'onmousedown' => "ManualCrop.showCroptool('" . $js_identifier . "', '" . $style_name . "', " . $fid . ");",
'onclick' => 'return false;',
),
'#prefix' => '<div class="manualcrop-style-button-holder">',
'#suffix' => '</div>',
));
}
else {
// Style selection list.
$element['manualcrop_style'] = array_merge($defaults, array(
'#type' => 'select',
'#title' => t('Manual Crop'),
'#description' => t('Select the image style to crop, the corresponding cropping tool will open.'),
'#options' => $style_options,
'#multiple' => FALSE,
'#attributes' => array(
'class' => array(
'manualcrop-identifier-' . $js_identifier,
'manualcrop-style-select',
'manualcrop-style-select-' . $fid,
),
'onchange' => "ManualCrop.showCroptool('" . $js_identifier . "', this, " . $fid . ");",
),
));
}
// The FAPI widget can have a alt and/or title field, increase their weight.
if (isset($element['alt']['#weight'])) {
$element['alt']['#weight']++;
}
if (isset($element['title']['#weight'])) {
$element['title']['#weight']++;
}
}
/**
* Add the crop functionality to the File Entity form.
*
* @param $form
* Complete form array.
* @param $form_state
* Form state array.
* @param $instance_info
* Field instance info, this array should contain 3 keys: entity_type, bundle
* and field_name.
*/
function _manualcrop_process_file_entity_form(&$form, &$form_state, $instance_info) {
// Check if a field instance was specified and get its settings.
if (!empty($instance_info['entity_type']) && !empty($instance_info['bundle']) && !empty($instance_info['field_name'])) {
$instance = field_info_instance($instance_info['entity_type'], $instance_info['field_name'], $instance_info['bundle']);
if (!empty($instance)) {
$settings = $instance['widget']['settings'];
}
}
// No valid fields instance specified, use the File Entity settings.
if (!isset($settings)) {
$settings = variable_get('manualcrop_file_entity_settings_' . $form['#entity']->type, manualcrop_default_widget_settings());
}
// Add the croptool if Manual Crop has been enabled.
if (!empty($settings['manualcrop_enable'])) {
manualcrop_croptool_process($form, $form_state, $form, $form['#entity'], $settings);
// Add the submit handler. Sometimes we have to add it to the action button
// and sometimes we have to add it to the general #submit, based on whether
// or not the submit button already has a handler.
if (!empty($form['actions']['submit']['#submit'])) {
$form['actions']['submit']['#submit'][] = 'manualcrop_croptool_submit';
}
else {
$form['#submit'][] = 'manualcrop_croptool_submit';
}
}
}
/**
* Save the Manual Crop data for a file.
*
* @param $file
* The file entity being saved for.
* @param $data
* The data as it is to be written, keyed by style name.
*/
function manualcrop_save_crop_data($file, $data) {
// If file_entity_revisions isn't enabled, use 0.
$vid = isset($file->vid) ? $file->vid : 0;
// Delete the existing data.
db_delete('manualcrop')
->condition('fid', $file->fid)
->condition('vid', $vid)
->condition('style_name', array_keys($data))
->execute();
// Save the new crop selections.
foreach ($data as $style_name => $selection) {
if ($selection) {
$record = array_merge($selection, array(
'fid' => $file->fid,
'vid' => $vid,
'style_name' => $style_name,
));
drupal_write_record('manualcrop', $record);
}
}
}
/**
* Gets the crop area for an image.
*
* @param $file
* Path to an image file.
* @param $style_name
* Image style machine name, leave empty for all styles.
*
* @return
* When $style_name is set, a single crop selection will be returned. Otherwise
* the result is an array of crop selection objects keyed by style name.
* Each object contains following items:
* - "style_name": The machine name of the image style this cropping area applies on.
* - "x": An integer representing the top left corner's x-position in pixels.
* - "y": An integer representing the top left corner's y-position in pixels.
* - "width": An integer representing the width in pixels.
* - "height": An integer representing the height in pixels.
*/
function manualcrop_load_crop_selection($file, $style_name = NULL) {
$query = db_select('manualcrop', 'mc');
$use_revisions = module_exists('file_entity_revisions');
if ($use_revisions) {
$query
->join('file_managed_revisions', 'r', 'mc.vid = r.vid AND r.uri = :uri', array(
':uri' => $file,
));
}
else {
$query
->join('file_managed', 'f', 'mc.fid = f.fid');
$query
->condition('f.uri', $file);
}
$query
->fields('mc', array(
'x',
'y',
'width',
'height',
'style_name',
));
if (isset($style_name)) {
$query
->condition('mc.style_name', $style_name);
if ($use_revisions) {
// Order by file revision ID descending to use the most recent Manual
// Crop settings associated with the provided file URI.
$query
->orderBy('r.vid', 'DESC');
$query
->range(0, 1);
}
return $query
->execute()
->fetchObject();
}
else {
if ($use_revisions) {
// The fetchAllAssoc() call below will use the last result found by this
// query for each style name, so order it by file revision ID ascending
// to use the most recent Manual Crop settings associated with the
// provided file URL for each style.
$query
->orderBy('r.vid', 'ASC');
}
return $query
->execute()
->fetchAllAssoc('style_name');
}
}
/**
* Returns the styles that have crop settings.
*
* @param $include_reuse
* Set to TRUE to include styles with a Manual Crop reuse effect.
* @param $exclude_arg
* Exclude the style that is set as a menu argument on this index.
* @param $return_label
* Set to TRUE to return the label instead of an array.
*
* @return
* If $label is set to TRUE, this function will return an array of style labels
* keyed by style name. Otherwise an array of crop-enabled styles will be
* returned. This array is also keyed by style name and each element in this
* array is also an array with 2 elements:
* - "label": Human readable style label.
* - "effect": Manual Crop effect data.
*/
function manualcrop_styles_with_crop($include_reuse = FALSE, $exclude_arg = NULL, $return_label = FALSE) {
$hascrop =& drupal_static(__FUNCTION__);
if (!is_array($hascrop)) {
$hascrop = array(
array(),
array(),
);
foreach (image_styles() as $style_name => $style) {
if (!empty($style['effects'])) {
// Check if the first effect is a Manual Crop cropping effect.
$effect = reset($style['effects']);
if (_manualcrop_is_own_effect($effect)) {
$label = _manualcrop_image_style_label($style);
$hascrop[1][$style_name] = array(
'label' => $label,
'effect' => $effect,
);
if (_manualcrop_is_own_effect($effect, TRUE)) {
$hascrop[0][$style_name] = array(
'label' => $label,
'effect' => $effect,
);
}
}
}
}
}
// With or without reuse effects.
$styles = $hascrop[(int) $include_reuse];
// Exclude a style by menu arument.
if (!is_null($exclude_arg)) {
$exclude_arg = arg($exclude_arg);
if (isset($styles[$exclude_arg])) {
unset($styles[$exclude_arg]);
}
}
// Only the labels should be returned.
if ($return_label) {
foreach ($styles as $style_name => $style) {
$styles[$style_name] = $style['label'];
}
}
return $styles;
}
/**
* Transform a style name into a more readable variant.
*
* @param $style
* Image style info array or style name.
*
* @return
* Cleaned-up image style name.
*/
function _manualcrop_image_style_label($style) {
global $language;
static $custom_strings;
// Get the image style info.
if (!is_array($style)) {
$styles = image_styles();
if (isset($styles[$style])) {
$style = $styles[$style];
}
else {
// Normally we shouldn't be here...
$style = array(
'name' => $style,
);
}
}
// The label is only available in Drupal 7.23 and up.
if (isset($style['label'])) {
return $style['label'];
}
else {
$style_name = $style['name'];
$langcode = isset($language->language) ? $language->language : 'en';
// Load custom string for overriding.
if (!isset($custom_strings[$langcode])) {
$custom_strings[$langcode] = variable_get('locale_custom_strings_' . $langcode, array());
}
// Get the human readable name from the custom strings or make it ourself.
if (isset($custom_strings[$langcode]['']['image-style-' . $style_name])) {
return $custom_strings[$langcode]['']['image-style-' . $style_name];
}
else {
return ucwords(str_replace('_', ' ', $style_name));
}
}
}
/**
* Checks if the effect is a Manual Crop effect.
*
* @param $effect
* Image style effect information array.
* @param $crop_effect
* Set to TRUE to require a cropping effect; set to FALSE to require
* a reuse effect. Defaults to NULL, which ignores effect type.
*
* @return
* TRUE if this is a Manual Crop (cropping/reuse) effect, FALSE otherwise.
*/
function _manualcrop_is_own_effect($effect, $crop_effect = NULL) {
if ($effect['module'] == 'manualcrop') {
if (is_null($crop_effect)) {
return TRUE;
}
return $crop_effect ^ in_array($effect['name'], array(
'manualcrop_reuse',
'manualcrop_auto_reuse',
));
}
return FALSE;
}
/**
* Get the image style name that should be used when processing the auto reuse effect.
*
* @param $file
* Path to an image file.
* @param $data
* Auto reuse effect data.
*
* @return
* Image style name that can be reused or FALSE if no crop selection was found.
*/
function _manualcrop_get_auto_reuse_style_name($file, $data) {
// Get the crop selections.
$crop = manualcrop_load_crop_selection($file);
if ($crop) {
if (!empty($data['style_priority'])) {
// Get a list of existing crop styles (keys) ordered by priority.
$styles = array_flip($data['style_priority']) + $crop;
$crop = array_intersect_key($styles, $crop);
}
// Return the first crop selection style name.
reset($crop);
return key($crop);
}
return FALSE;
}
/**
* Adds a cache control parameter to the image URI so the image will be reloaded
* if the crop selection was changed since it was last feched by the browser.
*
* @param $style_name
* Image style name.
* @param $path
* The absolute URL where the styled image can be downloaded.
*
* @return
* The altered image URL or NULL if the URL wasn't changed.
*/
function _manualcrop_add_cache_control($style_name, $url) {
// Is cache control enabled?
if (variable_get('manualcrop_cache_control', TRUE)) {
$styles = manualcrop_styles_with_crop(TRUE);
// Does this image style have a Manual Crop effect?
if (isset($styles[$style_name])) {
$cache_key = 'manualcrop:' . md5($url);
// Attempt to load the HTTP cache-controller from cache.
if ($cached_url = cache_get($cache_key)) {
return $cached_url->data;
}
// Get the image path from the URL.
$match = '/styles/' . $style_name . '/';
$path = parse_url($url, PHP_URL_PATH);
$path = drupal_substr($path, strrpos($path, $match) + drupal_strlen($match));
$path = explode('/', $path);
// Build the local image URI.
$scheme = array_shift($path);
$target = implode('/', $path);
$image_uri = $scheme . '://' . urldecode($target);
// Get the image effect.
$effect = $styles[$style_name]['effect'];
if (_manualcrop_is_own_effect($effect, FALSE)) {
unset($style_name);
switch ($effect['name']) {
case 'manualcrop_reuse':
// Use the reuse style to load the crop selection.
if (!empty($effect['data']['reuse_crop_style'])) {
$style_name = $effect['data']['reuse_crop_style'];
}
break;
case 'manualcrop_auto_reuse':
// Get the first applied crop selection.
if ($crop = manualcrop_load_crop_selection($image_uri)) {
$crop = reset($crop);
}
break;
}
}
// Load the crop selection.
if (isset($style_name)) {
$crop = manualcrop_load_crop_selection($image_uri, $style_name);
}
// Add the cache controller and cache the new URL.
if (!empty($crop)) {
$url .= (strpos($url, '?') ? '&' : '?') . 'c=' . md5($crop->x . '|' . $crop->y . '|' . $crop->width . '|' . $crop->height);
cache_set($cache_key, $url);
return $url;
}
}
}
return NULL;
}
/**
* Update or remove a style name in all Manual Crop field widgets.
*
* @param $style_name
* Current image style name.
* @param $new_style_name
* New image style name if renamed, a NULL value will remove the style from the settings.
*/
function _manualcrop_update_style_name_in_field_widget($style_name, $new_style_name = NULL) {
foreach (field_info_fields() as $field) {
if ($field['module'] == 'image') {
foreach ($field['bundles'] as $entity_type => $bundles) {
foreach ($bundles as $bundle) {
// Check each instance for processing.
$instance = field_info_instance($entity_type, $field['field_name'], $bundle);
$settings =& $instance['widget']['settings'];
if (manualcrop_supported_widgets($instance['widget']['type']) && (!empty($settings['manualcrop_require_cropping']) || !empty($settings['manualcrop_styles_list']))) {
$list = array();
// Add all existing settings to the list.
if (!empty($settings['manualcrop_require_cropping'])) {
$list['manualcrop_require_cropping'] =& $settings['manualcrop_require_cropping'];
}
if (!empty($settings['manualcrop_styles_list'])) {
$list['manualcrop_styles_list'] =& $settings['manualcrop_styles_list'];
}
// Process all settings.
foreach ($list as $key => &$item) {
if (isset($item[$style_name])) {
if (!is_null($new_style_name)) {
$item[$new_style_name] = $new_style_name;
}
unset($item[$style_name]);
}
else {
// Not processed, so remove it from the list.
unset($list[$key]);
}
}
if (!empty($list)) {
// Settings where updated, save the instance.
field_update_instance($instance);
}
}
}
}
}
}
}
/**
* Update or remove a style name in all Manual Crop reuse image effects.
*
* @param $style_name
* Current image style name.
* @param $new_style_name
* New image style name if renamed, a NULL value will remove the effect from the style.
*/
function _manualcrop_update_style_name_in_image_effect($style_name, $new_style_name = NULL) {
foreach (image_styles() as $style) {
if (!empty($style['effects'])) {
// Check if the first effect is a Manual Crop effect.
$effect = reset($style['effects']);
// Check if this is a Manual Crop reuse effect.
if (_manualcrop_is_own_effect($effect)) {
$data = $effect['data'];
$key = isset($data['reuse_crop_style']) ? 'reuse_crop_style' : 'fallback_style';
// Only update if needed.
if (isset($data[$key]) && $data[$key] == $style_name) {
if (is_null($new_style_name) && $effect['name'] == 'manualcrop_reuse') {
// The reuse effect requires an image style.
image_effect_delete($effect);
}
else {
$effect['data'][$key] = $new_style_name;
image_effect_save($effect);
}
}
}
}
}
}
/**
* Determine if a file supports cropping.
*
* @param $file
* The file object.
*
* @return
* TRUE if the file support cropping, FALSE otherwise.
*/
function _manualcrop_supported_file($file) {
if (empty($file->filemime)) {
return FALSE;
}
return strpos($file->filemime, 'image') === 0;
}
Functions
Name | Description |
---|---|
manualcrop_croptool_process | Add a croptool to the form element. This extends the FAPI widget or simply adds a new form item to enable cropping in a regular form. |
manualcrop_default_widget_settings | Returns the default widget settings. |
manualcrop_instance_required_styles | Get the list of required image styles from the widget settings. |
manualcrop_load_crop_selection | Gets the crop area for an image. |
manualcrop_save_crop_data | Save the Manual Crop data for a file. |
manualcrop_styles_with_crop | Returns the styles that have crop settings. |
manualcrop_supported_widgets | Returns an array of supported widget types or checks if a type is supported. |
_manualcrop_add_cache_control | Adds a cache control parameter to the image URI so the image will be reloaded if the crop selection was changed since it was last feched by the browser. |
_manualcrop_add_croptool | Add the actual croptool to a form element. |
_manualcrop_attach_dependencies | Attach the required croptool dependencies (files and settings). |
_manualcrop_attach_files | Attach the required css, javascript and libraries. |
_manualcrop_get_auto_reuse_style_name | Get the image style name that should be used when processing the auto reuse effect. |
_manualcrop_image_style_label | Transform a style name into a more readable variant. |
_manualcrop_is_own_effect | Checks if the effect is a Manual Crop effect. |
_manualcrop_js_identifier | Get the unique javascript crop settings identifier. |
_manualcrop_media_element_add_after_build | Adds the #after_build entry to a media element. |
_manualcrop_process_file_entity_form | Add the crop functionality to the File Entity form. |
_manualcrop_supported_file | Determine if a file supports cropping. |
_manualcrop_update_style_name_in_field_widget | Update or remove a style name in all Manual Crop field widgets. |
_manualcrop_update_style_name_in_image_effect | Update or remove a style name in all Manual Crop reuse image effects. |