summaryrefslogtreecommitdiff
path: root/kolab.org/www/drupal-7.26/modules/image
diff options
context:
space:
mode:
Diffstat (limited to 'kolab.org/www/drupal-7.26/modules/image')
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image-rtl.css11
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.admin.css60
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.admin.inc925
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.api.php200
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.css14
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.effects.inc314
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.field.inc642
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.info14
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.install522
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.module1393
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/image.test1865
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/sample.pngbin0 -> 168110 bytes
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.info13
-rw-r--r--kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.module50
14 files changed, 6023 insertions, 0 deletions
diff --git a/kolab.org/www/drupal-7.26/modules/image/image-rtl.css b/kolab.org/www/drupal-7.26/modules/image/image-rtl.css
new file mode 100644
index 0000000..2a7a855
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image-rtl.css
@@ -0,0 +1,11 @@
+
+/**
+ * Image upload widget.
+ */
+div.image-preview {
+ float: right;
+ padding: 0 0 10px 10px;
+}
+div.image-widget-data {
+ float: right;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.admin.css b/kolab.org/www/drupal-7.26/modules/image/image.admin.css
new file mode 100644
index 0000000..3115c8d
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.admin.css
@@ -0,0 +1,60 @@
+
+/**
+ * Image style configuration pages.
+ */
+div.image-style-new,
+div.image-style-new div {
+ display: inline;
+}
+div.image-style-preview div.preview-image-wrapper {
+ float: left;
+ padding-bottom: 2em;
+ text-align: center;
+ top: 50%;
+ width: 48%;
+}
+div.image-style-preview div.preview-image {
+ margin: auto;
+ position: relative;
+}
+div.image-style-preview div.preview-image div.width {
+ border: 1px solid #666;
+ border-top: none;
+ height: 2px;
+ left: -1px;
+ bottom: -6px;
+ position: absolute;
+}
+div.image-style-preview div.preview-image div.width span {
+ position: relative;
+ top: 4px;
+}
+div.image-style-preview div.preview-image div.height {
+ border: 1px solid #666;
+ border-left: none;
+ position: absolute;
+ right: -6px;
+ top: -1px;
+ width: 2px;
+}
+div.image-style-preview div.preview-image div.height span {
+ height: 2em;
+ left: 10px;
+ margin-top: -1em;
+ position: absolute;
+ top: 50%;
+}
+
+/**
+ * Image anchor element.
+ */
+table.image-anchor {
+ width: auto;
+}
+table.image-anchor tr.even,
+table.image-anchor tr.odd {
+ background: none;
+}
+table.image-anchor td {
+ border: 1px solid #CCC;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.admin.inc b/kolab.org/www/drupal-7.26/modules/image/image.admin.inc
new file mode 100644
index 0000000..7e62621
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.admin.inc
@@ -0,0 +1,925 @@
+<?php
+
+/**
+ * @file
+ * Administration pages for image settings.
+ */
+
+/**
+ * Menu callback; Listing of all current image styles.
+ */
+function image_style_list() {
+ $page = array();
+
+ $styles = image_styles();
+ $page['image_style_list'] = array(
+ '#markup' => theme('image_style_list', array('styles' => $styles)),
+ '#attached' => array(
+ 'css' => array(drupal_get_path('module', 'image') . '/image.admin.css' => array()),
+ ),
+ );
+
+ return $page;
+
+}
+
+/**
+ * Form builder; Edit an image style name and effects order.
+ *
+ * @param $form_state
+ * An associative array containing the current state of the form.
+ * @param $style
+ * An image style array.
+ * @ingroup forms
+ * @see image_style_form_submit()
+ */
+function image_style_form($form, &$form_state, $style) {
+ $title = t('Edit %name style', array('%name' => $style['label']));
+ drupal_set_title($title, PASS_THROUGH);
+
+ // Adjust this form for styles that must be overridden to edit.
+ $editable = (bool) ($style['storage'] & IMAGE_STORAGE_EDITABLE);
+
+ if (!$editable && empty($form_state['input'])) {
+ drupal_set_message(t('This image style is currently being provided by a module. Click the "Override defaults" button to change its settings.'), 'warning');
+ }
+
+ $form_state['image_style'] = $style;
+ $form['#tree'] = TRUE;
+ $form['#attached']['css'][drupal_get_path('module', 'image') . '/image.admin.css'] = array();
+
+ // Show the thumbnail preview.
+ $form['preview'] = array(
+ '#type' => 'item',
+ '#title' => t('Preview'),
+ '#markup' => theme('image_style_preview', array('style' => $style)),
+ );
+
+ // Show the Image Style label.
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Image style name'),
+ '#default_value' => $style['label'],
+ '#disabled' => !$editable,
+ '#required' => TRUE,
+ );
+
+ // Allow the name of the style to be changed, unless this style is
+ // provided by a module's hook_default_image_styles().
+ $form['name'] = array(
+ '#type' => 'machine_name',
+ '#size' => '64',
+ '#default_value' => $style['name'],
+ '#disabled' => !$editable,
+ '#description' => t('The name is used in URLs for generated images. Use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
+ '#required' => TRUE,
+ '#machine_name' => array(
+ 'exists' => 'image_style_load',
+ 'source' => array('label'),
+ 'replace_pattern' => '[^0-9a-z_\-]',
+ 'error' => t('Please only use lowercase alphanumeric characters, underscores (_), and hyphens (-) for style names.'),
+ ),
+ );
+
+ // Build the list of existing image effects for this image style.
+ $form['effects'] = array(
+ '#theme' => 'image_style_effects',
+ );
+ foreach ($style['effects'] as $key => $effect) {
+ $form['effects'][$key]['#weight'] = isset($form_state['input']['effects']) ? $form_state['input']['effects'][$key]['weight'] : NULL;
+ $form['effects'][$key]['label'] = array(
+ '#markup' => $effect['label'],
+ );
+ $form['effects'][$key]['summary'] = array(
+ '#markup' => isset($effect['summary theme']) ? theme($effect['summary theme'], array('data' => $effect['data'])) : '',
+ );
+ $form['effects'][$key]['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight for @title', array('@title' => $effect['label'])),
+ '#title_display' => 'invisible',
+ '#default_value' => $effect['weight'],
+ '#access' => $editable,
+ );
+
+ // Only attempt to display these fields for editable styles as the 'ieid'
+ // key is not set for styles defined in code.
+ if ($editable) {
+ $form['effects'][$key]['configure'] = array(
+ '#type' => 'link',
+ '#title' => t('edit'),
+ '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $effect['ieid'],
+ '#access' => $editable && isset($effect['form callback']),
+ );
+ $form['effects'][$key]['remove'] = array(
+ '#type' => 'link',
+ '#title' => t('delete'),
+ '#href' => 'admin/config/media/image-styles/edit/' . $style['name'] . '/effects/' . $effect['ieid'] . '/delete',
+ '#access' => $editable,
+ );
+ }
+ }
+
+ // Build the new image effect addition form and add it to the effect list.
+ $new_effect_options = array();
+ foreach (image_effect_definitions() as $effect => $definition) {
+ $new_effect_options[$effect] = check_plain($definition['label']);
+ }
+ $form['effects']['new'] = array(
+ '#tree' => FALSE,
+ '#weight' => isset($form_state['input']['weight']) ? $form_state['input']['weight'] : NULL,
+ '#access' => $editable,
+ );
+ $form['effects']['new']['new'] = array(
+ '#type' => 'select',
+ '#title' => t('Effect'),
+ '#title_display' => 'invisible',
+ '#options' => $new_effect_options,
+ '#empty_option' => t('Select a new effect'),
+ );
+ $form['effects']['new']['weight'] = array(
+ '#type' => 'weight',
+ '#title' => t('Weight for new effect'),
+ '#title_display' => 'invisible',
+ '#default_value' => count($form['effects']) - 1,
+ );
+ $form['effects']['new']['add'] = array(
+ '#type' => 'submit',
+ '#value' => t('Add'),
+ '#validate' => array('image_style_form_add_validate'),
+ '#submit' => array('image_style_form_submit', 'image_style_form_add_submit'),
+ );
+
+ // Show the Override or Submit button for this style.
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['override'] = array(
+ '#type' => 'submit',
+ '#value' => t('Override defaults'),
+ '#validate' => array(),
+ '#submit' => array('image_style_form_override_submit'),
+ '#access' => !$editable,
+ );
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Update style'),
+ '#access' => $editable,
+ );
+
+ return $form;
+}
+
+/**
+ * Validate handler for adding a new image effect to an image style.
+ */
+function image_style_form_add_validate($form, &$form_state) {
+ if (!$form_state['values']['new']) {
+ form_error($form['effects']['new']['new'], t('Select an effect to add.'));
+ }
+}
+
+/**
+ * Submit handler for adding a new image effect to an image style.
+ */
+function image_style_form_add_submit($form, &$form_state) {
+ $style = $form_state['image_style'];
+ // Check if this field has any configuration options.
+ $effect = image_effect_definition_load($form_state['values']['new']);
+
+ // Load the configuration form for this option.
+ if (isset($effect['form callback'])) {
+ $path = 'admin/config/media/image-styles/edit/' . $form_state['image_style']['name'] . '/add/' . $form_state['values']['new'];
+ $form_state['redirect'] = array($path, array('query' => array('weight' => $form_state['values']['weight'])));
+ }
+ // If there's no form, immediately add the image effect.
+ else {
+ $effect['isid'] = $style['isid'];
+ $effect['weight'] = $form_state['values']['weight'];
+ image_effect_save($effect);
+ drupal_set_message(t('The image effect was successfully applied.'));
+ }
+}
+
+/**
+ * Submit handler for overriding a module-defined style.
+ */
+function image_style_form_override_submit($form, &$form_state) {
+ drupal_set_message(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $form_state['image_style']['label'])));
+ image_default_style_save($form_state['image_style']);
+}
+
+/**
+ * Submit handler for saving an image style.
+ */
+function image_style_form_submit($form, &$form_state) {
+ // Update the image style.
+ $style = $form_state['image_style'];
+ $style['name'] = $form_state['values']['name'];
+ $style['label'] = $form_state['values']['label'];
+
+ // Update image effect weights.
+ if (!empty($form_state['values']['effects'])) {
+ foreach ($form_state['values']['effects'] as $ieid => $effect_data) {
+ if (isset($style['effects'][$ieid])) {
+ $effect = $style['effects'][$ieid];
+ $effect['weight'] = $effect_data['weight'];
+ image_effect_save($effect);
+ }
+ }
+ }
+
+ image_style_save($style);
+ if ($form_state['values']['op'] == t('Update style')) {
+ drupal_set_message(t('Changes to the style have been saved.'));
+ }
+ $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
+}
+
+/**
+ * Form builder; Form for adding a new image style.
+ *
+ * @ingroup forms
+ * @see image_style_add_form_submit()
+ */
+function image_style_add_form($form, &$form_state) {
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Style name'),
+ '#default_value' => '',
+ '#required' => TRUE,
+ );
+ $form['name'] = array(
+ '#type' => 'machine_name',
+ '#description' => t('The name is used in URLs for generated images. Use only lowercase alphanumeric characters, underscores (_), and hyphens (-).'),
+ '#size' => '64',
+ '#required' => TRUE,
+ '#machine_name' => array(
+ 'exists' => 'image_style_load',
+ 'source' => array('label'),
+ 'replace_pattern' => '[^0-9a-z_\-]',
+ 'error' => t('Please only use lowercase alphanumeric characters, underscores (_), and hyphens (-) for style names.'),
+ ),
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Create new style'),
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler for adding a new image style.
+ */
+function image_style_add_form_submit($form, &$form_state) {
+ $style = array(
+ 'name' => $form_state['values']['name'],
+ 'label' => $form_state['values']['label'],
+ );
+ $style = image_style_save($style);
+ drupal_set_message(t('Style %name was created.', array('%name' => $style['label'])));
+ $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
+}
+
+/**
+ * Element validate function to ensure unique, URL safe style names.
+ *
+ * This function is no longer used in Drupal core since image style names are
+ * now validated using #machine_name functionality. It is kept for backwards
+ * compatibility (since non-core modules may be using it) and will be removed
+ * in Drupal 8.
+ */
+function image_style_name_validate($element, $form_state) {
+ // Check for duplicates.
+ $styles = image_styles();
+ if (isset($styles[$element['#value']]) && (!isset($form_state['image_style']['isid']) || $styles[$element['#value']]['isid'] != $form_state['image_style']['isid'])) {
+ form_set_error($element['#name'], t('The image style name %name is already in use.', array('%name' => $element['#value'])));
+ }
+
+ // Check for illegal characters in image style names.
+ if (preg_match('/[^0-9a-z_\-]/', $element['#value'])) {
+ form_set_error($element['#name'], t('Please only use lowercase alphanumeric characters, underscores (_), and hyphens (-) for style names.'));
+ }
+}
+
+/**
+ * Form builder; Form for deleting an image style.
+ *
+ * @param $style
+ * An image style array.
+ *
+ * @ingroup forms
+ * @see image_style_delete_form_submit()
+ */
+function image_style_delete_form($form, &$form_state, $style) {
+ $form_state['image_style'] = $style;
+
+ $replacement_styles = array_diff_key(image_style_options(TRUE, PASS_THROUGH), array($style['name'] => ''));
+ $form['replacement'] = array(
+ '#title' => t('Replacement style'),
+ '#type' => 'select',
+ '#options' => $replacement_styles,
+ '#empty_option' => t('No replacement, just delete'),
+ );
+
+ return confirm_form(
+ $form,
+ t('Optionally select a style before deleting %style', array('%style' => $style['label'])),
+ 'admin/config/media/image-styles',
+ t('If this style is in use on the site, you may select another style to replace it. All images that have been generated for this style will be permanently deleted.'),
+ t('Delete'), t('Cancel')
+ );
+}
+
+/**
+ * Submit handler to delete an image style.
+ */
+function image_style_delete_form_submit($form, &$form_state) {
+ $style = $form_state['image_style'];
+
+ image_style_delete($style, $form_state['values']['replacement']);
+ drupal_set_message(t('Style %name was deleted.', array('%name' => $style['label'])));
+ $form_state['redirect'] = 'admin/config/media/image-styles';
+}
+
+/**
+ * Confirmation form to revert a database style to its default.
+ */
+function image_style_revert_form($form, &$form_state, $style) {
+ $form_state['image_style'] = $style;
+
+ return confirm_form(
+ $form,
+ t('Revert the %style style?', array('%style' => $style['label'])),
+ 'admin/config/media/image-styles',
+ t('Reverting this style will delete the customized settings and restore the defaults provided by the @module module.', array('@module' => $style['module'])),
+ t('Revert'), t('Cancel')
+ );
+}
+
+/**
+ * Submit handler to convert an overridden style to its default.
+ */
+function image_style_revert_form_submit($form, &$form_state) {
+ drupal_set_message(t('The %style style has been reverted to its defaults.', array('%style' => $form_state['image_style']['label'])));
+ image_default_style_revert($form_state['image_style']);
+ $form_state['redirect'] = 'admin/config/media/image-styles';
+}
+
+/**
+ * Form builder; Form for adding and editing image effects.
+ *
+ * This form is used universally for editing all image effects. Each effect adds
+ * its own custom section to the form by calling the form function specified in
+ * hook_image_effects().
+ *
+ * @param $form_state
+ * An associative array containing the current state of the form.
+ * @param $style
+ * An image style array.
+ * @param $effect
+ * An image effect array.
+ *
+ * @ingroup forms
+ * @see hook_image_effects()
+ * @see image_effects()
+ * @see image_resize_form()
+ * @see image_scale_form()
+ * @see image_rotate_form()
+ * @see image_crop_form()
+ * @see image_effect_form_submit()
+ */
+function image_effect_form($form, &$form_state, $style, $effect) {
+ if (!empty($effect['data'])) {
+ $title = t('Edit %label effect', array('%label' => $effect['label']));
+ }
+ else{
+ $title = t('Add %label effect', array('%label' => $effect['label']));
+ }
+ drupal_set_title($title, PASS_THROUGH);
+
+ $form_state['image_style'] = $style;
+ $form_state['image_effect'] = $effect;
+
+ // If no configuration for this image effect, return to the image style page.
+ if (!isset($effect['form callback'])) {
+ drupal_goto('admin/config/media/image-styles/edit/' . $style['name']);
+ }
+
+ $form['#tree'] = TRUE;
+ $form['#attached']['css'][drupal_get_path('module', 'image') . '/image.admin.css'] = array();
+ if (function_exists($effect['form callback'])) {
+ $form['data'] = call_user_func($effect['form callback'], $effect['data']);
+ }
+
+ // Check the URL for a weight, then the image effect, otherwise use default.
+ $form['weight'] = array(
+ '#type' => 'hidden',
+ '#value' => isset($_GET['weight']) ? intval($_GET['weight']) : (isset($effect['weight']) ? $effect['weight'] : count($style['effects'])),
+ );
+
+ $form['actions'] = array('#tree' => FALSE, '#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => isset($effect['ieid']) ? t('Update effect') : t('Add effect'),
+ );
+ $form['actions']['cancel'] = array(
+ '#type' => 'link',
+ '#title' => t('Cancel'),
+ '#href' => 'admin/config/media/image-styles/edit/' . $style['name'],
+ );
+
+ return $form;
+}
+
+/**
+ * Submit handler for updating an image effect.
+ */
+function image_effect_form_submit($form, &$form_state) {
+ $style = $form_state['image_style'];
+ $effect = array_merge($form_state['image_effect'], $form_state['values']);
+ $effect['isid'] = $style['isid'];
+ image_effect_save($effect);
+ drupal_set_message(t('The image effect was successfully applied.'));
+ $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
+}
+
+/**
+ * Form builder; Form for deleting an image effect.
+ *
+ * @param $style
+ * Name of the image style from which the image effect will be removed.
+ * @param $effect
+ * Name of the image effect to remove.
+ * @ingroup forms
+ * @see image_effect_delete_form_submit()
+ */
+function image_effect_delete_form($form, &$form_state, $style, $effect) {
+ $form_state['image_style'] = $style;
+ $form_state['image_effect'] = $effect;
+
+ $question = t('Are you sure you want to delete the @effect effect from the %style style?', array('%style' => $style['label'], '@effect' => $effect['label']));
+ return confirm_form($form, $question, 'admin/config/media/image-styles/edit/' . $style['name'], '', t('Delete'));
+}
+
+/**
+ * Submit handler to delete an image effect.
+ */
+function image_effect_delete_form_submit($form, &$form_state) {
+ $style = $form_state['image_style'];
+ $effect = $form_state['image_effect'];
+
+ image_effect_delete($effect);
+ drupal_set_message(t('The image effect %name has been deleted.', array('%name' => $effect['label'])));
+ $form_state['redirect'] = 'admin/config/media/image-styles/edit/' . $style['name'];
+}
+
+/**
+ * Element validate handler to ensure an integer pixel value.
+ *
+ * The property #allow_negative = TRUE may be set to allow negative integers.
+ */
+function image_effect_integer_validate($element, &$form_state) {
+ $value = empty($element['#allow_negative']) ? $element['#value'] : preg_replace('/^-/', '', $element['#value']);
+ if ($element['#value'] != '' && (!is_numeric($value) || intval($value) <= 0)) {
+ if (empty($element['#allow_negative'])) {
+ form_error($element, t('!name must be an integer.', array('!name' => $element['#title'])));
+ }
+ else {
+ form_error($element, t('!name must be a positive integer.', array('!name' => $element['#title'])));
+ }
+ }
+}
+
+/**
+ * Element validate handler to ensure a hexadecimal color value.
+ */
+function image_effect_color_validate($element, &$form_state) {
+ if ($element['#value'] != '') {
+ $hex_value = preg_replace('/^#/', '', $element['#value']);
+ if (!preg_match('/^#[0-9A-F]{3}([0-9A-F]{3})?$/', $element['#value'])) {
+ form_error($element, t('!name must be a hexadecimal color value.', array('!name' => $element['#title'])));
+ }
+ }
+}
+
+/**
+ * Element validate handler to ensure that either a height or a width is
+ * specified.
+ */
+function image_effect_scale_validate($element, &$form_state) {
+ if (empty($element['width']['#value']) && empty($element['height']['#value'])) {
+ form_error($element, t('Width and height can not both be blank.'));
+ }
+}
+
+/**
+ * Form structure for the image resize form.
+ *
+ * Note that this is not a complete form, it only contains the portion of the
+ * form for configuring the resize options. Therefore it does not not need to
+ * include metadata about the effect, nor a submit button.
+ *
+ * @param $data
+ * The current configuration for this resize effect.
+ */
+function image_resize_form($data) {
+ $form['width'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Width'),
+ '#default_value' => isset($data['width']) ? $data['width'] : '',
+ '#field_suffix' => ' ' . t('pixels'),
+ '#required' => TRUE,
+ '#size' => 10,
+ '#element_validate' => array('image_effect_integer_validate'),
+ '#allow_negative' => FALSE,
+ );
+ $form['height'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Height'),
+ '#default_value' => isset($data['height']) ? $data['height'] : '',
+ '#field_suffix' => ' ' . t('pixels'),
+ '#required' => TRUE,
+ '#size' => 10,
+ '#element_validate' => array('image_effect_integer_validate'),
+ '#allow_negative' => FALSE,
+ );
+ return $form;
+}
+
+/**
+ * Form structure for the image scale form.
+ *
+ * Note that this is not a complete form, it only contains the portion of the
+ * form for configuring the scale options. Therefore it does not not need to
+ * include metadata about the effect, nor a submit button.
+ *
+ * @param $data
+ * The current configuration for this scale effect.
+ */
+function image_scale_form($data) {
+ $form = image_resize_form($data);
+ $form['#element_validate'] = array('image_effect_scale_validate');
+ $form['width']['#required'] = FALSE;
+ $form['height']['#required'] = FALSE;
+ $form['upscale'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => (isset($data['upscale'])) ? $data['upscale'] : 0,
+ '#title' => t('Allow Upscaling'),
+ '#description' => t('Let scale make images larger than their original size'),
+ );
+ return $form;
+}
+
+/**
+ * Form structure for the image crop form.
+ *
+ * Note that this is not a complete form, it only contains the portion of the
+ * form for configuring the crop options. Therefore it does not not need to
+ * include metadata about the effect, nor a submit button.
+ *
+ * @param $data
+ * The current configuration for this crop effect.
+ */
+function image_crop_form($data) {
+ $data += array(
+ 'width' => '',
+ 'height' => '',
+ 'anchor' => 'center-center',
+ );
+
+ $form = image_resize_form($data);
+ $form['anchor'] = array(
+ '#type' => 'radios',
+ '#title' => t('Anchor'),
+ '#options' => array(
+ 'left-top' => t('Top') . ' ' . t('Left'),
+ 'center-top' => t('Top') . ' ' . t('Center'),
+ 'right-top' => t('Top') . ' ' . t('Right'),
+ 'left-center' => t('Center') . ' ' . t('Left'),
+ 'center-center' => t('Center'),
+ 'right-center' => t('Center') . ' ' . t('Right'),
+ 'left-bottom' => t('Bottom') . ' ' . t('Left'),
+ 'center-bottom' => t('Bottom') . ' ' . t('Center'),
+ 'right-bottom' => t('Bottom') . ' ' . t('Right'),
+ ),
+ '#theme' => 'image_anchor',
+ '#default_value' => $data['anchor'],
+ '#description' => t('The part of the image that will be retained during the crop.'),
+ );
+
+ return $form;
+}
+
+/**
+ * Form structure for the image rotate form.
+ *
+ * Note that this is not a complete form, it only contains the portion of the
+ * form for configuring the rotate options. Therefore it does not not need to
+ * include metadata about the effect, nor a submit button.
+ *
+ * @param $data
+ * The current configuration for this rotate effect.
+ */
+function image_rotate_form($data) {
+ $form['degrees'] = array(
+ '#type' => 'textfield',
+ '#default_value' => (isset($data['degrees'])) ? $data['degrees'] : 0,
+ '#title' => t('Rotation angle'),
+ '#description' => t('The number of degrees the image should be rotated. Positive numbers are clockwise, negative are counter-clockwise.'),
+ '#field_suffix' => '&deg;',
+ '#required' => TRUE,
+ '#size' => 6,
+ '#maxlength' => 4,
+ '#element_validate' => array('image_effect_integer_validate'),
+ '#allow_negative' => TRUE,
+ );
+ $form['bgcolor'] = array(
+ '#type' => 'textfield',
+ '#default_value' => (isset($data['bgcolor'])) ? $data['bgcolor'] : '#FFFFFF',
+ '#title' => t('Background color'),
+ '#description' => t('The background color to use for exposed areas of the image. Use web-style hex colors (#FFFFFF for white, #000000 for black). Leave blank for transparency on image types that support it.'),
+ '#size' => 7,
+ '#maxlength' => 7,
+ '#element_validate' => array('image_effect_color_validate'),
+ );
+ $form['random'] = array(
+ '#type' => 'checkbox',
+ '#default_value' => (isset($data['random'])) ? $data['random'] : 0,
+ '#title' => t('Randomize'),
+ '#description' => t('Randomize the rotation angle for each image. The angle specified above is used as a maximum.'),
+ );
+ return $form;
+}
+
+/**
+ * Returns HTML for the page containing the list of image styles.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - styles: An array of all the image styles returned by image_get_styles().
+ *
+ * @see image_get_styles()
+ * @ingroup themeable
+ */
+function theme_image_style_list($variables) {
+ $styles = $variables['styles'];
+
+ $header = array(t('Style name'), t('Settings'), array('data' => t('Operations'), 'colspan' => 3));
+ $rows = array();
+ foreach ($styles as $style) {
+ $row = array();
+ $row[] = l($style['label'], 'admin/config/media/image-styles/edit/' . $style['name']);
+ $link_attributes = array(
+ 'attributes' => array(
+ 'class' => array('image-style-link'),
+ ),
+ );
+ if ($style['storage'] == IMAGE_STORAGE_NORMAL) {
+ $row[] = t('Custom');
+ $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
+ $row[] = l(t('delete'), 'admin/config/media/image-styles/delete/' . $style['name'], $link_attributes);
+ }
+ elseif ($style['storage'] == IMAGE_STORAGE_OVERRIDE) {
+ $row[] = t('Overridden');
+ $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
+ $row[] = l(t('revert'), 'admin/config/media/image-styles/revert/' . $style['name'], $link_attributes);
+ }
+ else {
+ $row[] = t('Default');
+ $row[] = l(t('edit'), 'admin/config/media/image-styles/edit/' . $style['name'], $link_attributes);
+ $row[] = '';
+ }
+ $rows[] = $row;
+ }
+
+ if (empty($rows)) {
+ $rows[] = array(array(
+ 'colspan' => 4,
+ 'data' => t('There are currently no styles. <a href="!url">Add a new one</a>.', array('!url' => url('admin/config/media/image-styles/add'))),
+ ));
+ }
+
+ return theme('table', array('header' => $header, 'rows' => $rows));
+}
+
+/**
+ * Returns HTML for a listing of the effects within a specific image style.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - form: A render element representing the form.
+ *
+ * @ingroup themeable
+ */
+function theme_image_style_effects($variables) {
+ $form = $variables['form'];
+
+ $rows = array();
+
+ foreach (element_children($form) as $key) {
+ $row = array();
+ $form[$key]['weight']['#attributes']['class'] = array('image-effect-order-weight');
+ if (is_numeric($key)) {
+ $summary = drupal_render($form[$key]['summary']);
+ $row[] = drupal_render($form[$key]['label']) . (empty($summary) ? '' : ' ' . $summary);
+ $row[] = drupal_render($form[$key]['weight']);
+ $row[] = drupal_render($form[$key]['configure']);
+ $row[] = drupal_render($form[$key]['remove']);
+ }
+ else {
+ // Add the row for adding a new image effect.
+ $row[] = '<div class="image-style-new">' . drupal_render($form['new']['new']) . drupal_render($form['new']['add']) . '</div>';
+ $row[] = drupal_render($form['new']['weight']);
+ $row[] = array('data' => '', 'colspan' => 2);
+ }
+
+ if (!isset($form[$key]['#access']) || $form[$key]['#access']) {
+ $rows[] = array(
+ 'data' => $row,
+ 'class' => !empty($form[$key]['weight']['#access']) || $key == 'new' ? array('draggable') : array(),
+ );
+ }
+ }
+
+ $header = array(
+ t('Effect'),
+ t('Weight'),
+ array('data' => t('Operations'), 'colspan' => 2),
+ );
+
+ if (count($rows) == 1 && $form['new']['#access']) {
+ array_unshift($rows, array(array(
+ 'data' => t('There are currently no effects in this style. Add one by selecting an option below.'),
+ 'colspan' => 4,
+ )));
+ }
+
+ $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'image-style-effects')));
+ drupal_add_tabledrag('image-style-effects', 'order', 'sibling', 'image-effect-order-weight');
+ return $output;
+}
+
+/**
+ * Returns HTML for a preview of an image style.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - style: The image style array being previewed.
+ *
+ * @ingroup themeable
+ */
+function theme_image_style_preview($variables) {
+ $style = $variables['style'];
+
+ $sample_image = variable_get('image_style_preview_image', drupal_get_path('module', 'image') . '/sample.png');
+ $sample_width = 160;
+ $sample_height = 160;
+
+ // Set up original file information.
+ $original_path = $sample_image;
+ $original_image = image_get_info($original_path);
+ if ($original_image['width'] > $original_image['height']) {
+ $original_width = min($original_image['width'], $sample_width);
+ $original_height = round($original_width / $original_image['width'] * $original_image['height']);
+ }
+ else {
+ $original_height = min($original_image['height'], $sample_height);
+ $original_width = round($original_height / $original_image['height'] * $original_image['width']);
+ }
+ $original_attributes = array_intersect_key($original_image, array('width' => '', 'height' => ''));
+ $original_attributes['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;';
+
+ // Set up preview file information.
+ $preview_file = image_style_path($style['name'], $original_path);
+ if (!file_exists($preview_file)) {
+ image_style_create_derivative($style, $original_path, $preview_file);
+ }
+ $preview_image = image_get_info($preview_file);
+ if ($preview_image['width'] > $preview_image['height']) {
+ $preview_width = min($preview_image['width'], $sample_width);
+ $preview_height = round($preview_width / $preview_image['width'] * $preview_image['height']);
+ }
+ else {
+ $preview_height = min($preview_image['height'], $sample_height);
+ $preview_width = round($preview_height / $preview_image['height'] * $preview_image['width']);
+ }
+ $preview_attributes = array_intersect_key($preview_image, array('width' => '', 'height' => ''));
+ $preview_attributes['style'] = 'width: ' . $preview_width . 'px; height: ' . $preview_height . 'px;';
+
+ // In the previews, timestamps are added to prevent caching of images.
+ $output = '<div class="image-style-preview preview clearfix">';
+
+ // Build the preview of the original image.
+ $original_url = file_create_url($original_path);
+ $output .= '<div class="preview-image-wrapper">';
+ $output .= t('original') . ' (' . l(t('view actual size'), $original_url) . ')';
+ $output .= '<div class="preview-image original-image" style="' . $original_attributes['style'] . '">';
+ $output .= '<a href="' . $original_url . '">' . theme('image', array('path' => $original_path, 'alt' => t('Sample original image'), 'title' => '', 'attributes' => $original_attributes)) . '</a>';
+ $output .= '<div class="height" style="height: ' . $original_height . 'px"><span>' . $original_image['height'] . 'px</span></div>';
+ $output .= '<div class="width" style="width: ' . $original_width . 'px"><span>' . $original_image['width'] . 'px</span></div>';
+ $output .= '</div>'; // End preview-image.
+ $output .= '</div>'; // End preview-image-wrapper.
+
+ // Build the preview of the image style.
+ $preview_url = file_create_url($preview_file) . '?cache_bypass=' . REQUEST_TIME;
+ $output .= '<div class="preview-image-wrapper">';
+ $output .= check_plain($style['label']) . ' (' . l(t('view actual size'), file_create_url($preview_file) . '?' . time()) . ')';
+ $output .= '<div class="preview-image modified-image" style="' . $preview_attributes['style'] . '">';
+ $output .= '<a href="' . file_create_url($preview_file) . '?' . time() . '">' . theme('image', array('path' => $preview_url, 'alt' => t('Sample modified image'), 'title' => '', 'attributes' => $preview_attributes)) . '</a>';
+ $output .= '<div class="height" style="height: ' . $preview_height . 'px"><span>' . $preview_image['height'] . 'px</span></div>';
+ $output .= '<div class="width" style="width: ' . $preview_width . 'px"><span>' . $preview_image['width'] . 'px</span></div>';
+ $output .= '</div>'; // End preview-image.
+ $output .= '</div>'; // End preview-image-wrapper.
+
+ $output .= '</div>'; // End image-style-preview.
+
+ return $output;
+}
+
+/**
+ * Returns HTML for a 3x3 grid of checkboxes for image anchors.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - element: A render element containing radio buttons.
+ *
+ * @ingroup themeable
+ */
+function theme_image_anchor($variables) {
+ $element = $variables['element'];
+
+ $rows = array();
+ $row = array();
+ foreach (element_children($element) as $n => $key) {
+ $element[$key]['#attributes']['title'] = $element[$key]['#title'];
+ unset($element[$key]['#title']);
+ $row[] = drupal_render($element[$key]);
+ if ($n % 3 == 3 - 1) {
+ $rows[] = $row;
+ $row = array();
+ }
+ }
+
+ return theme('table', array('header' => array(), 'rows' => $rows, 'attributes' => array('class' => array('image-anchor'))));
+}
+
+/**
+ * Returns HTML for a summary of an image resize effect.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - data: The current configuration for this resize effect.
+ *
+ * @ingroup themeable
+ */
+function theme_image_resize_summary($variables) {
+ $data = $variables['data'];
+
+ if ($data['width'] && $data['height']) {
+ return check_plain($data['width']) . 'x' . check_plain($data['height']);
+ }
+ else {
+ return ($data['width']) ? t('width @width', array('@width' => $data['width'])) : t('height @height', array('@height' => $data['height']));
+ }
+}
+
+/**
+ * Returns HTML for a summary of an image scale effect.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - data: The current configuration for this scale effect.
+ *
+ * @ingroup themeable
+ */
+function theme_image_scale_summary($variables) {
+ $data = $variables['data'];
+ return theme('image_resize_summary', array('data' => $data)) . ' ' . ($data['upscale'] ? '(' . t('upscaling allowed') . ')' : '');
+}
+
+/**
+ * Returns HTML for a summary of an image crop effect.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - data: The current configuration for this crop effect.
+ *
+ * @ingroup themeable
+ */
+function theme_image_crop_summary($variables) {
+ return theme('image_resize_summary', $variables);
+}
+
+/**
+ * Returns HTML for a summary of an image rotate effect.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - data: The current configuration for this rotate effect.
+ *
+ * @ingroup themeable
+ */
+function theme_image_rotate_summary($variables) {
+ $data = $variables['data'];
+ return ($data['random']) ? t('random between -@degrees&deg and @degrees&deg', array('@degrees' => str_replace('-', '', $data['degrees']))) : t('@degrees&deg', array('@degrees' => $data['degrees']));
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.api.php b/kolab.org/www/drupal-7.26/modules/image/image.api.php
new file mode 100644
index 0000000..8115116
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.api.php
@@ -0,0 +1,200 @@
+<?php
+
+/**
+ * @file
+ * Hooks related to image styles and effects.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Define information about image effects provided by a module.
+ *
+ * This hook enables modules to define image manipulation effects for use with
+ * an image style.
+ *
+ * @return
+ * An array of image effects. This array is keyed on the machine-readable
+ * effect name. Each effect is defined as an associative array containing the
+ * following items:
+ * - "label": The human-readable name of the effect.
+ * - "effect callback": The function to call to perform this image effect.
+ * - "dimensions passthrough": (optional) Set this item if the effect doesn't
+ * change the dimensions of the image.
+ * - "dimensions callback": (optional) The function to call to transform
+ * dimensions for this effect.
+ * - "help": (optional) A brief description of the effect that will be shown
+ * when adding or configuring this image effect.
+ * - "form callback": (optional) The name of a function that will return a
+ * $form array providing a configuration form for this image effect.
+ * - "summary theme": (optional) The name of a theme function that will output
+ * a summary of this image effect's configuration.
+ *
+ * @see hook_image_effect_info_alter()
+ */
+function hook_image_effect_info() {
+ $effects = array();
+
+ $effects['mymodule_resize'] = array(
+ 'label' => t('Resize'),
+ 'help' => t('Resize an image to an exact set of dimensions, ignoring aspect ratio.'),
+ 'effect callback' => 'mymodule_resize_effect',
+ 'dimensions callback' => 'mymodule_resize_dimensions',
+ 'form callback' => 'mymodule_resize_form',
+ 'summary theme' => 'mymodule_resize_summary',
+ );
+
+ return $effects;
+}
+
+/**
+ * Alter the information provided in hook_image_effect_info().
+ *
+ * @param $effects
+ * The array of image effects, keyed on the machine-readable effect name.
+ *
+ * @see hook_image_effect_info()
+ */
+function hook_image_effect_info_alter(&$effects) {
+ // Override the Image module's crop effect with more options.
+ $effects['image_crop']['effect callback'] = 'mymodule_crop_effect';
+ $effects['image_crop']['dimensions callback'] = 'mymodule_crop_dimensions';
+ $effects['image_crop']['form callback'] = 'mymodule_crop_form';
+}
+
+/**
+ * Respond to image style updating.
+ *
+ * This hook enables modules to update settings that might be affected by
+ * changes to an image. For example, updating a module specific variable to
+ * reflect a change in the image style's name.
+ *
+ * @param $style
+ * The image style array that is being updated.
+ */
+function hook_image_style_save($style) {
+ // If a module defines an image style and that style is renamed by the user
+ // the module should update any references to that style.
+ if (isset($style['old_name']) && $style['old_name'] == variable_get('mymodule_image_style', '')) {
+ variable_set('mymodule_image_style', $style['name']);
+ }
+}
+
+/**
+ * Respond to image style deletion.
+ *
+ * This hook enables modules to update settings when a image style is being
+ * deleted. If a style is deleted, a replacement name may be specified in
+ * $style['name'] and the style being deleted will be specified in
+ * $style['old_name'].
+ *
+ * @param $style
+ * The image style array that being deleted.
+ */
+function hook_image_style_delete($style) {
+ // Administrators can choose an optional replacement style when deleting.
+ // Update the modules style variable accordingly.
+ if (isset($style['old_name']) && $style['old_name'] == variable_get('mymodule_image_style', '')) {
+ variable_set('mymodule_image_style', $style['name']);
+ }
+}
+
+/**
+ * Respond to image style flushing.
+ *
+ * This hook enables modules to take effect when a style is being flushed (all
+ * images are being deleted from the server and regenerated). Any
+ * module-specific caches that contain information related to the style should
+ * be cleared using this hook. This hook is called whenever a style is updated,
+ * deleted, or any effect associated with the style is update or deleted.
+ *
+ * @param $style
+ * The image style array that is being flushed.
+ */
+function hook_image_style_flush($style) {
+ // Empty cached data that contains information about the style.
+ cache_clear_all('*', 'cache_mymodule', TRUE);
+}
+
+/**
+ * Modify any image styles provided by other modules or the user.
+ *
+ * This hook allows modules to modify, add, or remove image styles. This may
+ * be useful to modify default styles provided by other modules or enforce
+ * that a specific effect is always enabled on a style. Note that modifications
+ * to these styles may negatively affect the user experience, such as if an
+ * effect is added to a style through this hook, the user may attempt to remove
+ * the effect but it will be immediately be re-added.
+ *
+ * The best use of this hook is usually to modify default styles, which are not
+ * editable by the user until they are overridden, so such interface
+ * contradictions will not occur. This hook can target default (or user) styles
+ * by checking the $style['storage'] property.
+ *
+ * If your module needs to provide a new style (rather than modify an existing
+ * one) use hook_image_default_styles() instead.
+ *
+ * @see hook_image_default_styles()
+ */
+function hook_image_styles_alter(&$styles) {
+ // Check that we only affect a default style.
+ if ($styles['thumbnail']['storage'] == IMAGE_STORAGE_DEFAULT) {
+ // Add an additional effect to the thumbnail style.
+ $styles['thumbnail']['effects'][] = array(
+ 'name' => 'image_desaturate',
+ 'data' => array(),
+ 'weight' => 1,
+ 'effect callback' => 'image_desaturate_effect',
+ );
+ }
+}
+
+/**
+ * Provide module-based image styles for reuse throughout Drupal.
+ *
+ * This hook allows your module to provide image styles. This may be useful if
+ * you require images to fit within exact dimensions. Note that you should
+ * attempt to re-use the default styles provided by Image module whenever
+ * possible, rather than creating image styles that are specific to your module.
+ * Image provides the styles "thumbnail", "medium", and "large".
+ *
+ * You may use this hook to more easily manage your site's changes by moving
+ * existing image styles from the database to a custom module. Note however that
+ * moving image styles to code instead storing them in the database has a
+ * negligible effect on performance, since custom image styles are loaded
+ * from the database all at once. Even if all styles are pulled from modules,
+ * Image module will still perform the same queries to check the database for
+ * any custom styles.
+ *
+ * @return
+ * An array of image styles, keyed by the style name.
+ * @see image_image_default_styles()
+ */
+function hook_image_default_styles() {
+ $styles = array();
+
+ $styles['mymodule_preview'] = array(
+ 'label' => 'My module preview',
+ 'effects' => array(
+ array(
+ 'name' => 'image_scale',
+ 'data' => array('width' => 400, 'height' => 400, 'upscale' => 1),
+ 'weight' => 0,
+ ),
+ array(
+ 'name' => 'image_desaturate',
+ 'data' => array(),
+ 'weight' => 1,
+ ),
+ ),
+ );
+
+ return $styles;
+}
+
+ /**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.css b/kolab.org/www/drupal-7.26/modules/image/image.css
new file mode 100644
index 0000000..7db307b
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.css
@@ -0,0 +1,14 @@
+
+/**
+ * Image upload widget.
+ */
+div.image-preview {
+ float: left; /* LTR */
+ padding: 0 10px 10px 0; /* LTR */
+}
+div.image-widget-data {
+ float: left; /* LTR */
+}
+div.image-widget-data input.text-field {
+ width: auto;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.effects.inc b/kolab.org/www/drupal-7.26/modules/image/image.effects.inc
new file mode 100644
index 0000000..35a6a74
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.effects.inc
@@ -0,0 +1,314 @@
+<?php
+
+/**
+ * @file
+ * Functions needed to execute image effects provided by Image module.
+ */
+
+/**
+ * Implements hook_image_effect_info().
+ */
+function image_image_effect_info() {
+ $effects = array(
+ 'image_resize' => array(
+ 'label' => t('Resize'),
+ 'help' => t('Resizing will make images an exact set of dimensions. This may cause images to be stretched or shrunk disproportionately.'),
+ 'effect callback' => 'image_resize_effect',
+ 'dimensions callback' => 'image_resize_dimensions',
+ 'form callback' => 'image_resize_form',
+ 'summary theme' => 'image_resize_summary',
+ ),
+ 'image_scale' => array(
+ 'label' => t('Scale'),
+ 'help' => t('Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.'),
+ 'effect callback' => 'image_scale_effect',
+ 'dimensions callback' => 'image_scale_dimensions',
+ 'form callback' => 'image_scale_form',
+ 'summary theme' => 'image_scale_summary',
+ ),
+ 'image_scale_and_crop' => array(
+ 'label' => t('Scale and crop'),
+ 'help' => t('Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.'),
+ 'effect callback' => 'image_scale_and_crop_effect',
+ 'dimensions callback' => 'image_resize_dimensions',
+ 'form callback' => 'image_resize_form',
+ 'summary theme' => 'image_resize_summary',
+ ),
+ 'image_crop' => array(
+ 'label' => t('Crop'),
+ 'help' => t('Cropping will remove portions of an image to make it the specified dimensions.'),
+ 'effect callback' => 'image_crop_effect',
+ 'dimensions callback' => 'image_resize_dimensions',
+ 'form callback' => 'image_crop_form',
+ 'summary theme' => 'image_crop_summary',
+ ),
+ 'image_desaturate' => array(
+ 'label' => t('Desaturate'),
+ 'help' => t('Desaturate converts an image to grayscale.'),
+ 'effect callback' => 'image_desaturate_effect',
+ 'dimensions passthrough' => TRUE,
+ ),
+ 'image_rotate' => array(
+ 'label' => t('Rotate'),
+ 'help' => t('Rotating an image may cause the dimensions of an image to increase to fit the diagonal.'),
+ 'effect callback' => 'image_rotate_effect',
+ 'dimensions callback' => 'image_rotate_dimensions',
+ 'form callback' => 'image_rotate_form',
+ 'summary theme' => 'image_rotate_summary',
+ ),
+ );
+
+ return $effects;
+}
+
+/**
+ * Image effect callback; Resize an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the resize effect with the
+ * following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ *
+ * @return
+ * TRUE on success. FALSE on failure to resize image.
+ *
+ * @see image_resize()
+ */
+function image_resize_effect(&$image, $data) {
+ if (!image_resize($image, $data['width'], $data['height'])) {
+ watchdog('image', 'Image resize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image dimensions callback; Resize.
+ *
+ * @param $dimensions
+ * Dimensions to be modified - an array with components width and height, in
+ * pixels.
+ * @param $data
+ * An array of attributes to use when performing the resize effect with the
+ * following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ */
+function image_resize_dimensions(array &$dimensions, array $data) {
+ // The new image will have the exact dimensions defined for the effect.
+ $dimensions['width'] = $data['width'];
+ $dimensions['height'] = $data['height'];
+}
+
+/**
+ * Image effect callback; Scale an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the scale effect with the
+ * following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ * - "upscale": A boolean indicating that the image should be upscaled if the
+ * dimensions are larger than the original image.
+ *
+ * @return
+ * TRUE on success. FALSE on failure to scale image.
+ *
+ * @see image_scale()
+ */
+function image_scale_effect(&$image, $data) {
+ // Set sane default values.
+ $data += array(
+ 'width' => NULL,
+ 'height' => NULL,
+ 'upscale' => FALSE,
+ );
+
+ if (!image_scale($image, $data['width'], $data['height'], $data['upscale'])) {
+ watchdog('image', 'Image scale failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image dimensions callback; Scale.
+ *
+ * @param $dimensions
+ * Dimensions to be modified - an array with components width and height, in
+ * pixels.
+ * @param $data
+ * An array of attributes to use when performing the scale effect with the
+ * following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ * - "upscale": A boolean indicating that the image should be upscaled if the
+ * dimensions are larger than the original image.
+ */
+function image_scale_dimensions(array &$dimensions, array $data) {
+ if ($dimensions['width'] && $dimensions['height']) {
+ image_dimensions_scale($dimensions, $data['width'], $data['height'], $data['upscale']);
+ }
+}
+
+/**
+ * Image effect callback; Crop an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the crop effect with the
+ * following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ * - "anchor": A string describing where the crop should originate in the form
+ * of "XOFFSET-YOFFSET". XOFFSET is either a number of pixels or
+ * "left", "center", "right" and YOFFSET is either a number of pixels or
+ * "top", "center", "bottom".
+ * @return
+ * TRUE on success. FALSE on failure to crop image.
+ * @see image_crop()
+ */
+function image_crop_effect(&$image, $data) {
+ // Set sane default values.
+ $data += array(
+ 'anchor' => 'center-center',
+ );
+
+ list($x, $y) = explode('-', $data['anchor']);
+ $x = image_filter_keyword($x, $image->info['width'], $data['width']);
+ $y = image_filter_keyword($y, $image->info['height'], $data['height']);
+ if (!image_crop($image, $x, $y, $data['width'], $data['height'])) {
+ watchdog('image', 'Image crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image effect callback; Scale and crop an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the scale and crop effect
+ * with the following items:
+ * - "width": An integer representing the desired width in pixels.
+ * - "height": An integer representing the desired height in pixels.
+ * @return
+ * TRUE on success. FALSE on failure to scale and crop image.
+ * @see image_scale_and_crop()
+ */
+function image_scale_and_crop_effect(&$image, $data) {
+ if (!image_scale_and_crop($image, $data['width'], $data['height'])) {
+ watchdog('image', 'Image scale and crop failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image effect callback; Desaturate (grayscale) an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the desaturate effect.
+ * @return
+ * TRUE on success. FALSE on failure to desaturate image.
+ * @see image_desaturate()
+ */
+function image_desaturate_effect(&$image, $data) {
+ if (!image_desaturate($image)) {
+ watchdog('image', 'Image desaturate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image effect callback; Rotate an image resource.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array of attributes to use when performing the rotate effect containing
+ * the following items:
+ * - "degrees": The number of (clockwise) degrees to rotate the image.
+ * - "random": A boolean indicating that a random rotation angle should be
+ * used for this image. The angle specified in "degrees" is used as a
+ * positive and negative maximum.
+ * - "bgcolor": The background color to use for exposed areas of the image.
+ * Use web-style hex colors (#FFFFFF for white, #000000 for black). Leave
+ * blank for transparency on image types that support it.
+ * @return
+ * TRUE on success. FALSE on failure to rotate image.
+ * @see image_rotate().
+ */
+function image_rotate_effect(&$image, $data) {
+ // Set sane default values.
+ $data += array(
+ 'degrees' => 0,
+ 'bgcolor' => NULL,
+ 'random' => FALSE,
+ );
+
+ // Convert short #FFF syntax to full #FFFFFF syntax.
+ if (strlen($data['bgcolor']) == 4) {
+ $c = $data['bgcolor'];
+ $data['bgcolor'] = $c[0] . $c[1] . $c[1] . $c[2] . $c[2] . $c[3] . $c[3];
+ }
+
+ // Convert #FFFFFF syntax to hexadecimal colors.
+ if ($data['bgcolor'] != '') {
+ $data['bgcolor'] = hexdec(str_replace('#', '0x', $data['bgcolor']));
+ }
+ else {
+ $data['bgcolor'] = NULL;
+ }
+
+ if (!empty($data['random'])) {
+ $degrees = abs((float) $data['degrees']);
+ $data['degrees'] = rand(-1 * $degrees, $degrees);
+ }
+
+ if (!image_rotate($image, $data['degrees'], $data['bgcolor'])) {
+ watchdog('image', 'Image rotate failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array('%toolkit' => $image->toolkit, '%path' => $image->source, '%mimetype' => $image->info['mime_type'], '%dimensions' => $image->info['width'] . 'x' . $image->info['height']), WATCHDOG_ERROR);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * Image dimensions callback; Rotate.
+ *
+ * @param $dimensions
+ * Dimensions to be modified - an array with components width and height, in
+ * pixels.
+ * @param $data
+ * An array of attributes to use when performing the rotate effect containing
+ * the following items:
+ * - "degrees": The number of (clockwise) degrees to rotate the image.
+ * - "random": A boolean indicating that a random rotation angle should be
+ * used for this image. The angle specified in "degrees" is used as a
+ * positive and negative maximum.
+ */
+function image_rotate_dimensions(array &$dimensions, array $data) {
+ // If the rotate is not random and the angle is a multiple of 90 degrees,
+ // then the new dimensions can be determined.
+ if (!$data['random'] && ((int) ($data['degrees']) == $data['degrees']) && ($data['degrees'] % 90 == 0)) {
+ if ($data['degrees'] % 180 != 0) {
+ $temp = $dimensions['width'];
+ $dimensions['width'] = $dimensions['height'];
+ $dimensions['height'] = $temp;
+ }
+ }
+ else {
+ $dimensions['width'] = $dimensions['height'] = NULL;
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.field.inc b/kolab.org/www/drupal-7.26/modules/image/image.field.inc
new file mode 100644
index 0000000..6d1867c
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.field.inc
@@ -0,0 +1,642 @@
+<?php
+
+/**
+ * @file
+ * Implement an image field, based on the file module's file field.
+ */
+
+/**
+ * Implements hook_field_info().
+ */
+function image_field_info() {
+ return array(
+ 'image' => array(
+ 'label' => t('Image'),
+ '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_image' => 0,
+ ),
+ 'default_widget' => 'image_image',
+ 'default_formatter' => 'image',
+ ),
+ );
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function image_field_settings_form($field, $instance) {
+ $defaults = field_info_field_settings($field['type']);
+ $settings = array_merge($defaults, $field['settings']);
+
+ $scheme_options = array();
+ foreach (file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE) as $scheme => $stream_wrapper) {
+ $scheme_options[$scheme] = $stream_wrapper['name'];
+ }
+ $form['uri_scheme'] = array(
+ '#type' => 'radios',
+ '#title' => t('Upload destination'),
+ '#options' => $scheme_options,
+ '#default_value' => $settings['uri_scheme'],
+ '#description' => t('Select where the final files should be stored. Private file storage has significantly more overhead than public files, but allows restricted access to files within this field.'),
+ );
+
+ // When the user sets the scheme on the UI, even for the first time, it's
+ // updating a field because fields are created on the "Manage fields"
+ // page. So image_field_update_field() can handle this change.
+ $form['default_image'] = array(
+ '#title' => t('Default image'),
+ '#type' => 'managed_file',
+ '#description' => t('If no image is uploaded, this image will be shown on display.'),
+ '#default_value' => $field['settings']['default_image'],
+ '#upload_location' => $settings['uri_scheme'] . '://default_images/',
+ );
+
+ return $form;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function image_field_instance_settings_form($field, $instance) {
+ $settings = $instance['settings'];
+
+ // Use the file field instance settings form as a basis.
+ $form = file_field_instance_settings_form($field, $instance);
+
+ // Add maximum and minimum resolution settings.
+ $max_resolution = explode('x', $settings['max_resolution']) + array('', '');
+ $form['max_resolution'] = array(
+ '#type' => 'item',
+ '#title' => t('Maximum image resolution'),
+ '#element_validate' => array('_image_field_resolution_validate'),
+ '#weight' => 4.1,
+ '#field_prefix' => '<div class="container-inline">',
+ '#field_suffix' => '</div>',
+ '#description' => t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Leave blank for no restriction. If a larger image is uploaded, it will be resized to reflect the given width and height. Resizing images on upload will cause the loss of <a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format">EXIF data</a> in the image.'),
+ );
+ $form['max_resolution']['x'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Maximum width'),
+ '#title_display' => 'invisible',
+ '#default_value' => $max_resolution[0],
+ '#size' => 5,
+ '#maxlength' => 5,
+ '#field_suffix' => ' x ',
+ );
+ $form['max_resolution']['y'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Maximum height'),
+ '#title_display' => 'invisible',
+ '#default_value' => $max_resolution[1],
+ '#size' => 5,
+ '#maxlength' => 5,
+ '#field_suffix' => ' ' . t('pixels'),
+ );
+
+ $min_resolution = explode('x', $settings['min_resolution']) + array('', '');
+ $form['min_resolution'] = array(
+ '#type' => 'item',
+ '#title' => t('Minimum image resolution'),
+ '#element_validate' => array('_image_field_resolution_validate'),
+ '#weight' => 4.2,
+ '#field_prefix' => '<div class="container-inline">',
+ '#field_suffix' => '</div>',
+ '#description' => t('The minimum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Leave blank for no restriction. If a smaller image is uploaded, it will be rejected.'),
+ );
+ $form['min_resolution']['x'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Minimum width'),
+ '#title_display' => 'invisible',
+ '#default_value' => $min_resolution[0],
+ '#size' => 5,
+ '#maxlength' => 5,
+ '#field_suffix' => ' x ',
+ );
+ $form['min_resolution']['y'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Minimum height'),
+ '#title_display' => 'invisible',
+ '#default_value' => $min_resolution[1],
+ '#size' => 5,
+ '#maxlength' => 5,
+ '#field_suffix' => ' ' . t('pixels'),
+ );
+
+ // Remove the description option.
+ unset($form['description_field']);
+
+ // Add title and alt configuration options.
+ $form['alt_field'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable <em>Alt</em> field'),
+ '#default_value' => $settings['alt_field'],
+ '#description' => t('The alt attribute may be used by search engines, screen readers, and when the image cannot be loaded.'),
+ '#weight' => 10,
+ );
+ $form['title_field'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Enable <em>Title</em> field'),
+ '#default_value' => $settings['title_field'],
+ '#description' => t('The title attribute is used as a tooltip when the mouse hovers over the image.'),
+ '#weight' => 11,
+ );
+
+ // Add the default image to the instance.
+ $form['default_image'] = array(
+ '#title' => t('Default image'),
+ '#type' => 'managed_file',
+ '#description' => t("If no image is uploaded, this image will be shown on display and will override the field's default image."),
+ '#default_value' => $settings['default_image'],
+ '#upload_location' => $field['settings']['uri_scheme'] . '://default_images/',
+ );
+
+ return $form;
+}
+
+/**
+ * Element validate function for resolution fields.
+ */
+function _image_field_resolution_validate($element, &$form_state) {
+ if (!empty($element['x']['#value']) || !empty($element['y']['#value'])) {
+ foreach (array('x', 'y') as $dimension) {
+ $value = $element[$dimension]['#value'];
+ if (!is_numeric($value)) {
+ form_error($element[$dimension], t('Height and width values must be numeric.'));
+ return;
+ }
+ if (intval($value) == 0) {
+ form_error($element[$dimension], t('Both a height and width value must be specified in the !name field.', array('!name' => $element['#title'])));
+ return;
+ }
+ }
+ form_set_value($element, intval($element['x']['#value']) . 'x' . intval($element['y']['#value']), $form_state);
+ }
+ else {
+ form_set_value($element, '', $form_state);
+ }
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function image_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 image_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+ // If there are no files specified at all, use the default.
+ foreach ($entities as $id => $entity) {
+ if (empty($items[$id])) {
+ $fid = 0;
+ // Use the default for the instance if one is available.
+ if (!empty($instances[$id]['settings']['default_image'])) {
+ $fid = $instances[$id]['settings']['default_image'];
+ }
+ // Otherwise, use the default for the field.
+ elseif (!empty($field['settings']['default_image'])) {
+ $fid = $field['settings']['default_image'];
+ }
+
+ // Add the default image if one is found.
+ if ($fid && ($file = file_load($fid))) {
+ $items[$id][0] = (array) $file + array(
+ 'is_default' => TRUE,
+ 'alt' => '',
+ 'title' => '',
+ );
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_field_presave().
+ */
+function image_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ file_field_presave($entity_type, $entity, $field, $instance, $langcode, $items);
+
+ // Determine the dimensions if necessary.
+ foreach ($items as &$item) {
+ if (!isset($item['width']) || !isset($item['height'])) {
+ $info = image_get_info(file_load($item['fid'])->uri);
+
+ if (is_array($info)) {
+ $item['width'] = $info['width'];
+ $item['height'] = $info['height'];
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function image_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ file_field_insert($entity_type, $entity, $field, $instance, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function image_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ file_field_update($entity_type, $entity, $field, $instance, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_delete().
+ */
+function image_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ file_field_delete($entity_type, $entity, $field, $instance, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_delete_revision().
+ */
+function image_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
+ file_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, $items);
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function image_field_is_empty($item, $field) {
+ return file_field_is_empty($item, $field);
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function image_field_widget_info() {
+ return array(
+ 'image_image' => array(
+ 'label' => t('Image'),
+ 'field types' => array('image'),
+ 'settings' => array(
+ 'progress_indicator' => 'throbber',
+ 'preview_image_style' => 'thumbnail',
+ ),
+ 'behaviors' => array(
+ 'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+ 'default value' => FIELD_BEHAVIOR_NONE,
+ ),
+ ),
+ );
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function image_field_widget_settings_form($field, $instance) {
+ $widget = $instance['widget'];
+ $settings = $widget['settings'];
+
+ // Use the file widget settings form.
+ $form = file_field_widget_settings_form($field, $instance);
+
+ $form['preview_image_style'] = array(
+ '#title' => t('Preview image style'),
+ '#type' => 'select',
+ '#options' => image_style_options(FALSE, PASS_THROUGH),
+ '#empty_option' => '<' . t('no preview') . '>',
+ '#default_value' => $settings['preview_image_style'],
+ '#description' => t('The preview image will be shown while editing the content.'),
+ '#weight' => 15,
+ );
+
+ return $form;
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function image_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+
+ // Add display_field setting to field because file_field_widget_form() assumes it is set.
+ $field['settings']['display_field'] = 0;
+
+ $elements = file_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
+ $settings = $instance['settings'];
+
+ foreach (element_children($elements) as $delta) {
+ // Add upload resolution validation.
+ if ($settings['max_resolution'] || $settings['min_resolution']) {
+ $elements[$delta]['#upload_validators']['file_validate_image_resolution'] = array($settings['max_resolution'], $settings['min_resolution']);
+ }
+
+ // If not using custom extension validation, ensure this is an image.
+ $supported_extensions = array('png', 'gif', 'jpg', 'jpeg');
+ $extensions = isset($elements[$delta]['#upload_validators']['file_validate_extensions'][0]) ? $elements[$delta]['#upload_validators']['file_validate_extensions'][0] : implode(' ', $supported_extensions);
+ $extensions = array_intersect(explode(' ', $extensions), $supported_extensions);
+ $elements[$delta]['#upload_validators']['file_validate_extensions'][0] = implode(' ', $extensions);
+
+ // Add all extra functionality provided by the image widget.
+ $elements[$delta]['#process'][] = 'image_field_widget_process';
+ }
+
+ if ($field['cardinality'] == 1) {
+ // If there's only one field, return it as delta 0.
+ if (empty($elements[0]['#default_value']['fid'])) {
+ $elements[0]['#description'] = theme('file_upload_help', array('description' => field_filter_xss($instance['description']), 'upload_validators' => $elements[0]['#upload_validators']));
+ }
+ }
+ else {
+ $elements['#file_upload_description'] = theme('file_upload_help', array('upload_validators' => $elements[0]['#upload_validators']));
+ }
+ return $elements;
+}
+
+/**
+ * An element #process callback for the image_image field type.
+ *
+ * Expands the image_image type to include the alt and title fields.
+ */
+function image_field_widget_process($element, &$form_state, $form) {
+ $item = $element['#value'];
+ $item['fid'] = $element['fid']['#value'];
+
+ $instance = field_widget_instance($element, $form_state);
+
+ $settings = $instance['settings'];
+ $widget_settings = $instance['widget']['settings'];
+
+ $element['#theme'] = 'image_widget';
+ $element['#attached']['css'][] = drupal_get_path('module', 'image') . '/image.css';
+
+ // Add the image preview.
+ if ($element['#file'] && $widget_settings['preview_image_style']) {
+ $variables = array(
+ 'style_name' => $widget_settings['preview_image_style'],
+ 'path' => $element['#file']->uri,
+ );
+
+ // Determine image dimensions.
+ if (isset($element['#value']['width']) && isset($element['#value']['height'])) {
+ $variables['width'] = $element['#value']['width'];
+ $variables['height'] = $element['#value']['height'];
+ }
+ else {
+ $info = image_get_info($element['#file']->uri);
+
+ if (is_array($info)) {
+ $variables['width'] = $info['width'];
+ $variables['height'] = $info['height'];
+ }
+ else {
+ $variables['width'] = $variables['height'] = NULL;
+ }
+ }
+
+ $element['preview'] = array(
+ '#type' => 'markup',
+ '#markup' => theme('image_style', $variables),
+ );
+
+ // Store the dimensions in the form so the file doesn't have to be accessed
+ // again. This is important for remote files.
+ $element['width'] = array(
+ '#type' => 'hidden',
+ '#value' => $variables['width'],
+ );
+ $element['height'] = array(
+ '#type' => 'hidden',
+ '#value' => $variables['height'],
+ );
+ }
+
+ // Add the additional alt and title fields.
+ $element['alt'] = array(
+ '#title' => t('Alternate text'),
+ '#type' => 'textfield',
+ '#default_value' => isset($item['alt']) ? $item['alt'] : '',
+ '#description' => t('This text will be used by screen readers, search engines, or when the image cannot be loaded.'),
+ // @see http://www.gawds.org/show.php?contentid=28
+ '#maxlength' => 512,
+ '#weight' => -2,
+ '#access' => (bool) $item['fid'] && $settings['alt_field'],
+ );
+ $element['title'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Title'),
+ '#default_value' => isset($item['title']) ? $item['title'] : '',
+ '#description' => t('The title is used as a tool tip when the user hovers the mouse over the image.'),
+ '#maxlength' => 1024,
+ '#weight' => -1,
+ '#access' => (bool) $item['fid'] && $settings['title_field'],
+ );
+
+ return $element;
+}
+
+/**
+ * Returns HTML for an image field widget.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - element: A render element representing the image field widget.
+ *
+ * @ingroup themeable
+ */
+function theme_image_widget($variables) {
+ $element = $variables['element'];
+ $output = '';
+ $output .= '<div class="image-widget form-managed-file clearfix">';
+
+ if (isset($element['preview'])) {
+ $output .= '<div class="image-preview">';
+ $output .= drupal_render($element['preview']);
+ $output .= '</div>';
+ }
+
+ $output .= '<div class="image-widget-data">';
+ if ($element['fid']['#value'] != 0) {
+ $element['filename']['#markup'] .= ' <span class="file-size">(' . format_size($element['#file']->filesize) . ')</span> ';
+ }
+ $output .= drupal_render_children($element);
+ $output .= '</div>';
+ $output .= '</div>';
+
+ return $output;
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function image_field_formatter_info() {
+ $formatters = array(
+ 'image' => array(
+ 'label' => t('Image'),
+ 'field types' => array('image'),
+ 'settings' => array('image_style' => '', 'image_link' => ''),
+ ),
+ );
+
+ return $formatters;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function image_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+ $display = $instance['display'][$view_mode];
+ $settings = $display['settings'];
+
+ $image_styles = image_style_options(FALSE, PASS_THROUGH);
+ $element['image_style'] = array(
+ '#title' => t('Image style'),
+ '#type' => 'select',
+ '#default_value' => $settings['image_style'],
+ '#empty_option' => t('None (original image)'),
+ '#options' => $image_styles,
+ );
+
+ $link_types = array(
+ 'content' => t('Content'),
+ 'file' => t('File'),
+ );
+ $element['image_link'] = array(
+ '#title' => t('Link image to'),
+ '#type' => 'select',
+ '#default_value' => $settings['image_link'],
+ '#empty_option' => t('Nothing'),
+ '#options' => $link_types,
+ );
+
+ return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function image_field_formatter_settings_summary($field, $instance, $view_mode) {
+ $display = $instance['display'][$view_mode];
+ $settings = $display['settings'];
+
+ $summary = array();
+
+ $image_styles = image_style_options(FALSE, PASS_THROUGH);
+ // Unset possible 'No defined styles' option.
+ unset($image_styles['']);
+ // Styles could be lost because of enabled/disabled modules that defines
+ // their styles in code.
+ if (isset($image_styles[$settings['image_style']])) {
+ $summary[] = t('Image style: @style', array('@style' => $image_styles[$settings['image_style']]));
+ }
+ else {
+ $summary[] = t('Original image');
+ }
+
+ $link_types = array(
+ 'content' => t('Linked to content'),
+ 'file' => t('Linked to file'),
+ );
+ // Display this setting only if image is linked.
+ if (isset($link_types[$settings['image_link']])) {
+ $summary[] = $link_types[$settings['image_link']];
+ }
+
+ return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function image_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+ $element = array();
+
+ // Check if the formatter involves a link.
+ if ($display['settings']['image_link'] == 'content') {
+ $uri = entity_uri($entity_type, $entity);
+ }
+ elseif ($display['settings']['image_link'] == 'file') {
+ $link_file = TRUE;
+ }
+
+ foreach ($items as $delta => $item) {
+ if (isset($link_file)) {
+ $uri = array(
+ 'path' => file_create_url($item['uri']),
+ 'options' => array(),
+ );
+ }
+ $element[$delta] = array(
+ '#theme' => 'image_formatter',
+ '#item' => $item,
+ '#image_style' => $display['settings']['image_style'],
+ '#path' => isset($uri) ? $uri : '',
+ );
+ }
+
+ return $element;
+}
+
+/**
+ * Returns HTML for an image field formatter.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - item: Associative array of image data, which may include "uri", "alt",
+ * "width", "height", "title" and "attributes".
+ * - image_style: An optional image style.
+ * - path: An array containing the link 'path' and link 'options'.
+ *
+ * @ingroup themeable
+ */
+function theme_image_formatter($variables) {
+ $item = $variables['item'];
+ $image = array(
+ 'path' => $item['uri'],
+ );
+
+ if (array_key_exists('alt', $item)) {
+ $image['alt'] = $item['alt'];
+ }
+
+ if (isset($item['attributes'])) {
+ $image['attributes'] = $item['attributes'];
+ }
+
+ if (isset($item['width']) && isset($item['height'])) {
+ $image['width'] = $item['width'];
+ $image['height'] = $item['height'];
+ }
+
+ // Do not output an empty 'title' attribute.
+ if (isset($item['title']) && drupal_strlen($item['title']) > 0) {
+ $image['title'] = $item['title'];
+ }
+
+ if ($variables['image_style']) {
+ $image['style_name'] = $variables['image_style'];
+ $output = theme('image_style', $image);
+ }
+ else {
+ $output = theme('image', $image);
+ }
+
+ // The link path and link options are both optional, but for the options to be
+ // processed, the link path must at least be an empty string.
+ if (isset($variables['path']['path'])) {
+ $path = $variables['path']['path'];
+ $options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
+ // When displaying an image inside a link, the html option must be TRUE.
+ $options['html'] = TRUE;
+ $output = l($output, $path, $options);
+ }
+
+ return $output;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.info b/kolab.org/www/drupal-7.26/modules/image/image.info
new file mode 100644
index 0000000..a601da7
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.info
@@ -0,0 +1,14 @@
+name = Image
+description = Provides image manipulation tools.
+package = Core
+version = VERSION
+core = 7.x
+dependencies[] = file
+files[] = image.test
+configure = admin/config/media/image-styles
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.install b/kolab.org/www/drupal-7.26/modules/image/image.install
new file mode 100644
index 0000000..45bcbbb
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.install
@@ -0,0 +1,522 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the image module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function image_install() {
+ // Create the styles directory and ensure it's writable.
+ $directory = file_default_scheme() . '://styles';
+ file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function image_uninstall() {
+ // Remove the styles directory and generated images.
+ file_unmanaged_delete_recursive(file_default_scheme() . '://styles');
+}
+
+/**
+ * Implements hook_schema().
+ */
+function image_schema() {
+ $schema = array();
+
+ $schema['cache_image'] = drupal_get_schema_unprocessed('system', 'cache');
+ $schema['cache_image']['description'] = 'Cache table used to store information about image manipulations that are in-progress.';
+
+ $schema['image_styles'] = array(
+ 'description' => 'Stores configuration options for image styles.',
+ 'fields' => array(
+ 'isid' => array(
+ 'description' => 'The primary identifier for an image style.',
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'name' => array(
+ 'description' => 'The style machine name.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'label' => array(
+ 'description' => 'The style administrative name.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ ),
+ 'primary key' => array('isid'),
+ 'unique keys' => array(
+ 'name' => array('name'),
+ ),
+ );
+
+ $schema['image_effects'] = array(
+ 'description' => 'Stores configuration options for image effects.',
+ 'fields' => array(
+ 'ieid' => array(
+ 'description' => 'The primary identifier for an image effect.',
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'isid' => array(
+ 'description' => 'The {image_styles}.isid for an image style.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'weight' => array(
+ 'description' => 'The weight of the effect in the style.',
+ 'type' => 'int',
+ 'unsigned' => FALSE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'name' => array(
+ 'description' => 'The unique name of the effect to be executed.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'data' => array(
+ 'description' => 'The configuration data for the effect.',
+ 'type' => 'blob',
+ 'not null' => TRUE,
+ 'size' => 'big',
+ 'serialize' => TRUE,
+ ),
+ ),
+ 'primary key' => array('ieid'),
+ 'indexes' => array(
+ 'isid' => array('isid'),
+ 'weight' => array('weight'),
+ ),
+ 'foreign keys' => array(
+ 'image_style' => array(
+ 'table' => 'image_styles',
+ 'columns' => array('isid' => 'isid'),
+ ),
+ ),
+ );
+
+ return $schema;
+}
+
+/**
+ * Implements hook_field_schema().
+ */
+function image_field_schema($field) {
+ return array(
+ 'columns' => array(
+ 'fid' => array(
+ 'description' => 'The {file_managed}.fid being referenced in this field.',
+ 'type' => 'int',
+ 'not null' => FALSE,
+ 'unsigned' => TRUE,
+ ),
+ 'alt' => array(
+ 'description' => "Alternative image text, for the image's 'alt' attribute.",
+ 'type' => 'varchar',
+ 'length' => 512,
+ 'not null' => FALSE,
+ ),
+ 'title' => array(
+ 'description' => "Image title text, for the image's 'title' attribute.",
+ 'type' => 'varchar',
+ 'length' => 1024,
+ 'not null' => FALSE,
+ ),
+ 'width' => array(
+ 'description' => 'The width of the image in pixels.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ ),
+ 'height' => array(
+ 'description' => 'The height of the image in pixels.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ ),
+ ),
+ 'indexes' => array(
+ 'fid' => array('fid'),
+ ),
+ 'foreign keys' => array(
+ 'fid' => array(
+ 'table' => 'file_managed',
+ 'columns' => array('fid' => 'fid'),
+ ),
+ ),
+ );
+}
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function image_update_dependencies() {
+ $dependencies['image'][7002] = array(
+ // Image update 7002 uses field API functions, so must run after
+ // Field API has been enabled.
+ 'system' => 7020,
+ );
+ return $dependencies;
+}
+
+/**
+ * Install the schema for users upgrading from the contributed module.
+ */
+function image_update_7000() {
+ if (!db_table_exists('image_styles')) {
+ $schema = array();
+
+ $schema['cache_image'] = system_schema_cache_7054();
+ $schema['cache_image']['description'] = 'Cache table used to store information about image manipulations that are in-progress.';
+
+ $schema['image_styles'] = array(
+ 'description' => 'Stores configuration options for image styles.',
+ 'fields' => array(
+ 'isid' => array(
+ 'description' => 'The primary identifier for an image style.',
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'name' => array(
+ 'description' => 'The style name.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ ),
+ 'primary key' => array('isid'),
+ 'unique keys' => array(
+ 'name' => array('name'),
+ ),
+ );
+
+ $schema['image_effects'] = array(
+ 'description' => 'Stores configuration options for image effects.',
+ 'fields' => array(
+ 'ieid' => array(
+ 'description' => 'The primary identifier for an image effect.',
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'isid' => array(
+ 'description' => 'The {image_styles}.isid for an image style.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'weight' => array(
+ 'description' => 'The weight of the effect in the style.',
+ 'type' => 'int',
+ 'unsigned' => FALSE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'name' => array(
+ 'description' => 'The unique name of the effect to be executed.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ ),
+ 'data' => array(
+ 'description' => 'The configuration data for the effect.',
+ 'type' => 'blob',
+ 'not null' => TRUE,
+ 'size' => 'big',
+ 'serialize' => TRUE,
+ ),
+ ),
+ 'primary key' => array('ieid'),
+ 'indexes' => array(
+ 'isid' => array('isid'),
+ 'weight' => array('weight'),
+ ),
+ 'foreign keys' => array(
+ 'image_style' => array(
+ 'table' => 'image_styles',
+ 'columns' => array('isid' => 'isid'),
+ ),
+ ),
+ );
+
+ db_create_table('cache_image', $schema['cache_image']);
+ db_create_table('image_styles', $schema['image_styles']);
+ db_create_table('image_effects', $schema['image_effects']);
+ }
+}
+
+/**
+ * @addtogroup updates-7.x-extra
+ * @{
+ */
+
+/**
+ * Rename possibly misnamed {image_effect} table to {image_effects}.
+ */
+function image_update_7001() {
+ // Due to a bug in earlier versions of image_update_7000() it is possible
+ // to end up with an {image_effect} table where there should be an
+ // {image_effects} table.
+ if (!db_table_exists('image_effects') && db_table_exists('image_effect')) {
+ db_rename_table('image_effect', 'image_effects');
+ }
+}
+
+/**
+ * Add width and height columns to a specific table.
+ *
+ * @param $table
+ * The name of the database table to be updated.
+ * @param $columns
+ * Keyed array of columns this table is supposed to have.
+ */
+function _image_update_7002_add_columns($table, $field_name) {
+ $spec = array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ );
+
+ $spec['description'] = 'The width of the image in pixels.';
+ db_add_field($table, $field_name . '_width', $spec);
+
+ $spec['description'] = 'The height of the image in pixels.';
+ db_add_field($table, $field_name . '_height', $spec);
+}
+
+/**
+ * Populate image dimensions in a specific table.
+ *
+ * @param $table
+ * The name of the database table to be updated.
+ * @param $columns
+ * Keyed array of columns this table is supposed to have.
+ * @param $last_fid
+ * The fid of the last image to have been processed.
+ *
+ * @return
+ * The number of images that were processed.
+ */
+function _image_update_7002_populate_dimensions($table, $field_name, &$last_fid) {
+ // Define how many images to process per pass.
+ $images_per_pass = 100;
+
+ // Query the database for fid / URI pairs.
+ $query = db_select($table, NULL, array('fetch' => PDO::FETCH_ASSOC));
+ $query->join('file_managed', NULL, $table . '.' . $field_name . '_fid = file_managed.fid');
+
+ if ($last_fid) {
+ $query->condition('file_managed.fid', $last_fid, '>');
+ }
+
+ $result = $query->fields('file_managed', array('fid', 'uri'))
+ ->orderBy('file_managed.fid')
+ ->range(0, $images_per_pass)
+ ->execute();
+
+ $count = 0;
+ foreach ($result as $file) {
+ $count++;
+ $info = image_get_info($file['uri']);
+
+ if (is_array($info)) {
+ db_update($table)
+ ->fields(array(
+ $field_name . '_width' => $info['width'],
+ $field_name . '_height' => $info['height'],
+ ))
+ ->condition($field_name . '_fid', $file['fid'])
+ ->execute();
+ }
+ }
+
+ // If less than the requested number of rows were returned then this table
+ // has been fully processed.
+ $last_fid = ($count < $images_per_pass) ? NULL : $file['fid'];
+ return $count;
+}
+
+/**
+ * Add width and height columns to image field schema and populate.
+ */
+function image_update_7002(array &$sandbox) {
+ if (empty($sandbox)) {
+ // Setup the sandbox.
+ $sandbox = array(
+ 'tables' => array(),
+ 'total' => 0,
+ 'processed' => 0,
+ 'last_fid' => NULL,
+ );
+
+ $fields = _update_7000_field_read_fields(array(
+ 'module' => 'image',
+ 'storage_type' => 'field_sql_storage',
+ 'deleted' => 0,
+ ));
+
+ foreach ($fields as $field) {
+ $tables = array(
+ _field_sql_storage_tablename($field),
+ _field_sql_storage_revision_tablename($field),
+ );
+ foreach ($tables as $table) {
+ // Add the width and height columns to the table.
+ _image_update_7002_add_columns($table, $field['field_name']);
+
+ // How many rows need dimensions populated?
+ $count = db_select($table)->countQuery()->execute()->fetchField();
+
+ if (!$count) {
+ continue;
+ }
+
+ $sandbox['total'] += $count;
+ $sandbox['tables'][$table] = $field['field_name'];
+ }
+ }
+
+ // If no tables need rows populated with dimensions then we are done.
+ if (empty($sandbox['tables'])) {
+ $sandbox = array();
+ return;
+ }
+ }
+
+ // Process the table at the top of the list.
+ $keys = array_keys($sandbox['tables']);
+ $table = reset($keys);
+ $sandbox['processed'] += _image_update_7002_populate_dimensions($table, $sandbox['tables'][$table], $sandbox['last_fid']);
+
+ // Has the table been fully processed?
+ if (!$sandbox['last_fid']) {
+ unset($sandbox['tables'][$table]);
+ }
+
+ $sandbox['#finished'] = count($sandbox['tables']) ? ($sandbox['processed'] / $sandbox['total']) : 1;
+}
+
+/**
+ * Remove the variables that set alt and title length since they were not
+ * used for database column size and could cause PDO exceptions.
+ */
+function image_update_7003() {
+ variable_del('image_alt_length');
+ variable_del('image_title_length');
+}
+
+/**
+ * Use a large setting (512 and 1024 characters) for the length of the image alt
+ * and title fields.
+ */
+function image_update_7004() {
+ $alt_spec = array(
+ 'type' => 'varchar',
+ 'length' => 512,
+ 'not null' => FALSE,
+ );
+
+ $title_spec = array(
+ 'type' => 'varchar',
+ 'length' => 1024,
+ 'not null' => FALSE,
+ );
+
+ $fields = _update_7000_field_read_fields(array(
+ 'module' => 'image',
+ 'storage_type' => 'field_sql_storage',
+ ));
+
+ foreach ($fields as $field_name => $field) {
+ $tables = array(
+ _field_sql_storage_tablename($field),
+ _field_sql_storage_revision_tablename($field),
+ );
+ $alt_column = $field['field_name'] . '_alt';
+ $title_column = $field['field_name'] . '_title';
+ foreach ($tables as $table) {
+ db_change_field($table, $alt_column, $alt_column, $alt_spec);
+ db_change_field($table, $title_column, $title_column, $title_spec);
+ }
+ }
+}
+
+/**
+ * Add a column to the 'image_style' table to store administrative labels.
+ */
+function image_update_7005() {
+ $field = array(
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'The style administrative name.',
+ );
+ db_add_field('image_styles', 'label', $field);
+
+ // Do a direct query here, rather than calling image_styles(),
+ // in case Image module is disabled.
+ $styles = db_query('SELECT name FROM {image_styles}')->fetchCol();
+ foreach ($styles as $style) {
+ db_update('image_styles')
+ ->fields(array('label' => $style))
+ ->condition('name', $style)
+ ->execute();
+ }
+}
+
+/**
+ * @} End of "addtogroup updates-7.x-extra".
+ */
+
+/**
+ * Implements hook_requirements() to check the PHP GD Library.
+ *
+ * @param $phase
+ */
+function image_requirements($phase) {
+ $requirements = array();
+
+ if ($phase == 'runtime') {
+ // Check for the PHP GD library.
+ if (function_exists('imagegd2')) {
+ $info = gd_info();
+ $requirements['image_gd'] = array(
+ 'value' => $info['GD Version'],
+ );
+
+ // Check for filter and rotate support.
+ if (function_exists('imagefilter') && function_exists('imagerotate')) {
+ $requirements['image_gd']['severity'] = REQUIREMENT_OK;
+ }
+ else {
+ $requirements['image_gd']['severity'] = REQUIREMENT_WARNING;
+ $requirements['image_gd']['description'] = t('The GD Library for PHP is enabled, but was compiled without support for functions used by the rotate and desaturate effects. It was probably compiled using the official GD libraries from http://www.libgd.org instead of the GD library bundled with PHP. You should recompile PHP --with-gd using the bundled GD library. See <a href="http://www.php.net/manual/book.image.php">the PHP manual</a>.');
+ }
+ }
+ else {
+ $requirements['image_gd'] = array(
+ 'value' => t('Not installed'),
+ 'severity' => REQUIREMENT_ERROR,
+ 'description' => t('The GD library for PHP is missing or outdated. Check the <a href="@url">PHP image documentation</a> for information on how to correct this.', array('@url' => 'http://www.php.net/manual/book.image.php')),
+ );
+ }
+ $requirements['image_gd']['title'] = t('GD library rotate and desaturate effects');
+ }
+
+ return $requirements;
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.module b/kolab.org/www/drupal-7.26/modules/image/image.module
new file mode 100644
index 0000000..c6a23f2
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.module
@@ -0,0 +1,1393 @@
+<?php
+
+/**
+ * @file
+ * Exposes global functionality for creating image styles.
+ */
+
+/**
+ * Image style constant for user presets in the database.
+ */
+define('IMAGE_STORAGE_NORMAL', 1);
+
+/**
+ * Image style constant for user presets that override module-defined presets.
+ */
+define('IMAGE_STORAGE_OVERRIDE', 2);
+
+/**
+ * Image style constant for module-defined presets in code.
+ */
+define('IMAGE_STORAGE_DEFAULT', 4);
+
+/**
+ * Image style constant to represent an editable preset.
+ */
+define('IMAGE_STORAGE_EDITABLE', IMAGE_STORAGE_NORMAL | IMAGE_STORAGE_OVERRIDE);
+
+/**
+ * Image style constant to represent any module-based preset.
+ */
+define('IMAGE_STORAGE_MODULE', IMAGE_STORAGE_OVERRIDE | IMAGE_STORAGE_DEFAULT);
+
+/**
+ * The name of the query parameter for image derivative tokens.
+ */
+define('IMAGE_DERIVATIVE_TOKEN', 'itok');
+
+// Load all Field module hooks for Image.
+require_once DRUPAL_ROOT . '/modules/image/image.field.inc';
+
+/**
+ * Implements hook_help().
+ */
+function image_help($path, $arg) {
+ switch ($path) {
+ case 'admin/help#image':
+ $output = '';
+ $output .= '<h3>' . t('About') . '</h3>';
+ $output .= '<p>' . t('The Image module allows you to manipulate images on your website. It exposes a setting for using the <em>Image toolkit</em>, allows you to configure <em>Image styles</em> that can be used for resizing or adjusting images on display, and provides an <em>Image</em> field for attaching images to content. For more information, see the online handbook entry for <a href="@image">Image module</a>.', array('@image' => 'http://drupal.org/documentation/modules/image')) . '</p>';
+ $output .= '<h3>' . t('Uses') . '</h3>';
+ $output .= '<dl>';
+ $output .= '<dt>' . t('Manipulating images') . '</dt>';
+ $output .= '<dd>' . t('With the Image module you can scale, crop, resize, rotate and desaturate images without affecting the original image using <a href="@image">image styles</a>. When you change an image style, the module automatically refreshes all created images. Every image style must have a name, which will be used in the URL of the generated images. There are two common approaches to naming image styles (which you use will depend on how the image style is being applied):',array('@image' => url('admin/config/media/image-styles')));
+ $output .= '<ul><li>' . t('Based on where it will be used: eg. <em>profile-picture</em>') . '</li>';
+ $output .= '<li>' . t('Describing its appearance: eg. <em>square-85x85</em>') . '</li></ul>';
+ $output .= t('After you create an image style, you can add effects: crop, scale, resize, rotate, and desaturate (other contributed modules provide additional effects). For example, by combining effects as crop, scale, and desaturate, you can create square, grayscale thumbnails.') . '<dd>';
+ $output .= '<dt>' . t('Attaching images to content as fields') . '</dt>';
+ $output .= '<dd>' . t("Image module also allows you to attach images to content as fields. To add an image field to a <a href='@content-type'>content type</a>, go to the content type's <em>manage fields</em> page, and add a new field of type <em>Image</em>. Attaching images to content this way allows image styles to be applied and maintained, and also allows you more flexibility when theming.", array('@content-type' => url('admin/structure/types'))) . '</dd>';
+ $output .= '</dl>';
+ return $output;
+ case 'admin/config/media/image-styles':
+ return '<p>' . t('Image styles commonly provide thumbnail sizes by scaling and cropping images, but can also add various effects before an image is displayed. When an image is displayed with a style, a new file is created and the original image is left unchanged.') . '</p>';
+ case 'admin/config/media/image-styles/edit/%/add/%':
+ $effect = image_effect_definition_load($arg[7]);
+ return isset($effect['help']) ? ('<p>' . $effect['help'] . '</p>') : NULL;
+ case 'admin/config/media/image-styles/edit/%/effects/%':
+ $effect = ($arg[5] == 'add') ? image_effect_definition_load($arg[6]) : image_effect_load($arg[6], $arg[4]);
+ return isset($effect['help']) ? ('<p>' . $effect['help'] . '</p>') : NULL;
+ }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function image_menu() {
+ $items = array();
+
+ // Generate image derivatives of publicly available files.
+ // If clean URLs are disabled, image derivatives will always be served
+ // through the menu system.
+ // If clean URLs are enabled and the image derivative already exists,
+ // PHP will be bypassed.
+ $directory_path = file_stream_wrapper_get_instance_by_scheme('public')->getDirectoryPath();
+ $items[$directory_path . '/styles/%image_style'] = array(
+ 'title' => 'Generate image style',
+ 'page callback' => 'image_style_deliver',
+ 'page arguments' => array(count(explode('/', $directory_path)) + 1),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+ // Generate and deliver image derivatives of private files.
+ // These image derivatives are always delivered through the menu system.
+ $items['system/files/styles/%image_style'] = array(
+ 'title' => 'Generate image style',
+ 'page callback' => 'image_style_deliver',
+ 'page arguments' => array(3),
+ 'access callback' => TRUE,
+ 'type' => MENU_CALLBACK,
+ );
+ $items['admin/config/media/image-styles'] = array(
+ 'title' => 'Image styles',
+ 'description' => 'Configure styles that can be used for resizing or adjusting images on display.',
+ 'page callback' => 'image_style_list',
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/list'] = array(
+ 'title' => 'List',
+ 'description' => 'List the current image styles on the site.',
+ 'page callback' => 'image_style_list',
+ 'access arguments' => array('administer image styles'),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => 1,
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/add'] = array(
+ 'title' => 'Add style',
+ 'description' => 'Add a new image style.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_style_add_form'),
+ 'access arguments' => array('administer image styles'),
+ 'type' => MENU_LOCAL_ACTION,
+ 'weight' => 2,
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/edit/%image_style'] = array(
+ 'title' => 'Edit style',
+ 'description' => 'Configure an image style.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_style_form', 5),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/delete/%image_style'] = array(
+ 'title' => 'Delete style',
+ 'description' => 'Delete an image style.',
+ 'load arguments' => array(NULL, (string) IMAGE_STORAGE_NORMAL),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_style_delete_form', 5),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/revert/%image_style'] = array(
+ 'title' => 'Revert style',
+ 'description' => 'Revert an image style.',
+ 'load arguments' => array(NULL, (string) IMAGE_STORAGE_OVERRIDE),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_style_revert_form', 5),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect'] = array(
+ 'title' => 'Edit image effect',
+ 'description' => 'Edit an existing effect within a style.',
+ 'load arguments' => array(5, (string) IMAGE_STORAGE_EDITABLE),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_effect_form', 5, 7),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect/delete'] = array(
+ 'title' => 'Delete image effect',
+ 'description' => 'Delete an existing effect from a style.',
+ 'load arguments' => array(5, (string) IMAGE_STORAGE_EDITABLE),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_effect_delete_form', 5, 7),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+ $items['admin/config/media/image-styles/edit/%image_style/add/%image_effect_definition'] = array(
+ 'title' => 'Add image effect',
+ 'description' => 'Add a new effect to a style.',
+ 'load arguments' => array(5),
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('image_effect_form', 5, 7),
+ 'access arguments' => array('administer image styles'),
+ 'file' => 'image.admin.inc',
+ );
+
+ return $items;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function image_theme() {
+ return array(
+ // Theme functions in image.module.
+ 'image_style' => array(
+ 'variables' => array(
+ 'style_name' => NULL,
+ 'path' => NULL,
+ 'width' => NULL,
+ 'height' => NULL,
+ 'alt' => '',
+ 'title' => NULL,
+ 'attributes' => array(),
+ ),
+ ),
+
+ // Theme functions in image.admin.inc.
+ 'image_style_list' => array(
+ 'variables' => array('styles' => NULL),
+ ),
+ 'image_style_effects' => array(
+ 'render element' => 'form',
+ ),
+ 'image_style_preview' => array(
+ 'variables' => array('style' => NULL),
+ ),
+ 'image_anchor' => array(
+ 'render element' => 'element',
+ ),
+ 'image_resize_summary' => array(
+ 'variables' => array('data' => NULL),
+ ),
+ 'image_scale_summary' => array(
+ 'variables' => array('data' => NULL),
+ ),
+ 'image_crop_summary' => array(
+ 'variables' => array('data' => NULL),
+ ),
+ 'image_rotate_summary' => array(
+ 'variables' => array('data' => NULL),
+ ),
+
+ // Theme functions in image.field.inc.
+ 'image_widget' => array(
+ 'render element' => 'element',
+ ),
+ 'image_formatter' => array(
+ 'variables' => array('item' => NULL, 'path' => NULL, 'image_style' => NULL),
+ ),
+ );
+}
+
+/**
+ * Implements hook_permission().
+ */
+function image_permission() {
+ return array(
+ 'administer image styles' => array(
+ 'title' => t('Administer image styles'),
+ 'description' => t('Create and modify styles for generating image modifications such as thumbnails.'),
+ ),
+ );
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function image_form_system_file_system_settings_alter(&$form, &$form_state) {
+ $form['#submit'][] = 'image_system_file_system_settings_submit';
+}
+
+/**
+ * Form submission handler for system_file_system_settings().
+ *
+ * Adds a menu rebuild after the public file path has been changed, so that the
+ * menu router item depending on that file path will be regenerated.
+ */
+function image_system_file_system_settings_submit($form, &$form_state) {
+ if ($form['file_public_path']['#default_value'] !== $form_state['values']['file_public_path']) {
+ variable_set('menu_rebuild_needed', TRUE);
+ }
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function image_flush_caches() {
+ return array('cache_image');
+}
+
+/**
+ * Implements hook_file_download().
+ *
+ * Control the access to files underneath the styles directory.
+ */
+function image_file_download($uri) {
+ $path = file_uri_target($uri);
+
+ // Private file access for image style derivatives.
+ if (strpos($path, 'styles/') === 0) {
+ $args = explode('/', $path);
+ // Discard the first part of the path (styles).
+ array_shift($args);
+ // Get the style name from the second part.
+ $style_name = array_shift($args);
+ // Remove the scheme from the path.
+ array_shift($args);
+
+ // Then the remaining parts are the path to the image.
+ $original_uri = file_uri_scheme($uri) . '://' . implode('/', $args);
+
+ // Check that the file exists and is an image.
+ if ($info = image_get_info($uri)) {
+ // Check the permissions of the original to grant access to this image.
+ $headers = module_invoke_all('file_download', $original_uri);
+ // Confirm there's at least one module granting access and none denying access.
+ if (!empty($headers) && !in_array(-1, $headers)) {
+ return array(
+ // Send headers describing the image's size, and MIME-type...
+ 'Content-Type' => $info['mime_type'],
+ 'Content-Length' => $info['file_size'],
+ // By not explicitly setting them here, this uses normal Drupal
+ // Expires, Cache-Control and ETag headers to prevent proxy or
+ // browser caching of private images.
+ );
+ }
+ }
+ return -1;
+ }
+
+ // Private file access for the original files. Note that we only check access
+ // for non-temporary images, since file.module will grant access for all
+ // temporary files.
+ $files = file_load_multiple(array(), array('uri' => $uri));
+ if (count($files)) {
+ $file = reset($files);
+ if ($file->status) {
+ return file_file_download($uri, 'image');
+ }
+ }
+}
+
+/**
+ * Implements hook_file_move().
+ */
+function image_file_move($file, $source) {
+ // Delete any image derivatives at the original image path.
+ image_path_flush($source->uri);
+}
+
+/**
+ * Implements hook_file_delete().
+ */
+function image_file_delete($file) {
+ // Delete any image derivatives of this image.
+ image_path_flush($file->uri);
+}
+
+/**
+ * Implements hook_image_default_styles().
+ */
+function image_image_default_styles() {
+ $styles = array();
+
+ $styles['thumbnail'] = array(
+ 'label' => 'Thumbnail (100x100)',
+ 'effects' => array(
+ array(
+ 'name' => 'image_scale',
+ 'data' => array('width' => 100, 'height' => 100, 'upscale' => 1),
+ 'weight' => 0,
+ ),
+ )
+ );
+
+ $styles['medium'] = array(
+ 'label' => 'Medium (220x220)',
+ 'effects' => array(
+ array(
+ 'name' => 'image_scale',
+ 'data' => array('width' => 220, 'height' => 220, 'upscale' => 1),
+ 'weight' => 0,
+ ),
+ )
+ );
+
+ $styles['large'] = array(
+ 'label' => 'Large (480x480)',
+ 'effects' => array(
+ array(
+ 'name' => 'image_scale',
+ 'data' => array('width' => 480, 'height' => 480, 'upscale' => 0),
+ 'weight' => 0,
+ ),
+ )
+ );
+
+ return $styles;
+}
+
+/**
+ * Implements hook_image_style_save().
+ */
+function image_image_style_save($style) {
+ if (isset($style['old_name']) && $style['old_name'] != $style['name']) {
+ $instances = field_read_instances();
+ // Loop through all fields searching for image fields.
+ foreach ($instances as $instance) {
+ if ($instance['widget']['module'] == 'image') {
+ $instance_changed = FALSE;
+ foreach ($instance['display'] as $view_mode => $display) {
+ // Check if the formatter involves an image style.
+ if ($display['type'] == 'image' && $display['settings']['image_style'] == $style['old_name']) {
+ // Update display information for any instance using the image
+ // style that was just deleted.
+ $instance['display'][$view_mode]['settings']['image_style'] = $style['name'];
+ $instance_changed = TRUE;
+ }
+ }
+ if ($instance['widget']['settings']['preview_image_style'] == $style['old_name']) {
+ $instance['widget']['settings']['preview_image_style'] = $style['name'];
+ $instance_changed = TRUE;
+ }
+ if ($instance_changed) {
+ field_update_instance($instance);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Implements hook_image_style_delete().
+ */
+function image_image_style_delete($style) {
+ image_image_style_save($style);
+}
+
+/**
+ * Implements hook_field_delete_field().
+ */
+function image_field_delete_field($field) {
+ if ($field['type'] != 'image') {
+ return;
+ }
+
+ // The value of a managed_file element can be an array if #extended == TRUE.
+ $fid = (is_array($field['settings']['default_image']) ? $field['settings']['default_image']['fid'] : $field['settings']['default_image']);
+ if ($fid && ($file = file_load($fid))) {
+ file_usage_delete($file, 'image', 'default_image', $field['id']);
+ }
+}
+
+/**
+ * Implements hook_field_update_field().
+ */
+function image_field_update_field($field, $prior_field, $has_data) {
+ if ($field['type'] != 'image') {
+ return;
+ }
+
+ // The value of a managed_file element can be an array if #extended == TRUE.
+ $fid_new = (is_array($field['settings']['default_image']) ? $field['settings']['default_image']['fid'] : $field['settings']['default_image']);
+ $fid_old = (is_array($prior_field['settings']['default_image']) ? $prior_field['settings']['default_image']['fid'] : $prior_field['settings']['default_image']);
+
+ $file_new = $fid_new ? file_load($fid_new) : FALSE;
+
+ if ($fid_new != $fid_old) {
+
+ // Is there a new file?
+ if ($file_new) {
+ $file_new->status = FILE_STATUS_PERMANENT;
+ file_save($file_new);
+ file_usage_add($file_new, 'image', 'default_image', $field['id']);
+ }
+
+ // Is there an old file?
+ if ($fid_old && ($file_old = file_load($fid_old))) {
+ file_usage_delete($file_old, 'image', 'default_image', $field['id']);
+ }
+ }
+
+ // If the upload destination changed, then move the file.
+ if ($file_new && (file_uri_scheme($file_new->uri) != $field['settings']['uri_scheme'])) {
+ $directory = $field['settings']['uri_scheme'] . '://default_images/';
+ file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+ file_move($file_new, $directory . $file_new->filename);
+ }
+}
+
+/**
+ * Implements hook_field_delete_instance().
+ */
+function image_field_delete_instance($instance) {
+ // Only act on image fields.
+ $field = field_read_field($instance['field_name']);
+ if ($field['type'] != 'image') {
+ return;
+ }
+
+ // The value of a managed_file element can be an array if the #extended
+ // property is set to TRUE.
+ $fid = $instance['settings']['default_image'];
+ if (is_array($fid)) {
+ $fid = $fid['fid'];
+ }
+
+ // Remove the default image when the instance is deleted.
+ if ($fid && ($file = file_load($fid))) {
+ file_usage_delete($file, 'image', 'default_image', $instance['id']);
+ }
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function image_field_update_instance($instance, $prior_instance) {
+ // Only act on image fields.
+ $field = field_read_field($instance['field_name']);
+ if ($field['type'] != 'image') {
+ return;
+ }
+
+ // The value of a managed_file element can be an array if the #extended
+ // property is set to TRUE.
+ $fid_new = $instance['settings']['default_image'];
+ if (is_array($fid_new)) {
+ $fid_new = $fid_new['fid'];
+ }
+ $fid_old = $prior_instance['settings']['default_image'];
+ if (is_array($fid_old)) {
+ $fid_old = $fid_old['fid'];
+ }
+
+ // If the old and new files do not match, update the default accordingly.
+ $file_new = $fid_new ? file_load($fid_new) : FALSE;
+ if ($fid_new != $fid_old) {
+ // Save the new file, if present.
+ if ($file_new) {
+ $file_new->status = FILE_STATUS_PERMANENT;
+ file_save($file_new);
+ file_usage_add($file_new, 'image', 'default_image', $instance['id']);
+ }
+ // Delete the old file, if present.
+ if ($fid_old && ($file_old = file_load($fid_old))) {
+ file_usage_delete($file_old, 'image', 'default_image', $instance['id']);
+ }
+ }
+
+ // If the upload destination changed, then move the file.
+ if ($file_new && (file_uri_scheme($file_new->uri) != $field['settings']['uri_scheme'])) {
+ $directory = $field['settings']['uri_scheme'] . '://default_images/';
+ file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+ file_move($file_new, $directory . $file_new->filename);
+ }
+}
+
+/**
+ * Clears cached versions of a specific file in all styles.
+ *
+ * @param $path
+ * The Drupal file path to the original image.
+ */
+function image_path_flush($path) {
+ $styles = image_styles();
+ foreach ($styles as $style) {
+ $image_path = image_style_path($style['name'], $path);
+ if (file_exists($image_path)) {
+ file_unmanaged_delete($image_path);
+ }
+ }
+}
+
+/**
+ * Gets an array of all styles and their settings.
+ *
+ * @return
+ * An array of styles keyed by the image style ID (isid).
+ * @see image_style_load()
+ */
+function image_styles() {
+ $styles = &drupal_static(__FUNCTION__);
+
+ // Grab from cache or build the array.
+ if (!isset($styles)) {
+ if ($cache = cache_get('image_styles', 'cache')) {
+ $styles = $cache->data;
+ }
+ else {
+ $styles = array();
+
+ // Select the module-defined styles.
+ foreach (module_implements('image_default_styles') as $module) {
+ $module_styles = module_invoke($module, 'image_default_styles');
+ foreach ($module_styles as $style_name => $style) {
+ $style['name'] = $style_name;
+ $style['label'] = empty($style['label']) ? $style_name : $style['label'];
+ $style['module'] = $module;
+ $style['storage'] = IMAGE_STORAGE_DEFAULT;
+ foreach ($style['effects'] as $key => $effect) {
+ $definition = image_effect_definition_load($effect['name']);
+ $effect = array_merge($definition, $effect);
+ $style['effects'][$key] = $effect;
+ }
+ $styles[$style_name] = $style;
+ }
+ }
+
+ // Select all the user-defined styles.
+ $user_styles = db_select('image_styles', NULL, array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('image_styles')
+ ->orderBy('name')
+ ->execute()
+ ->fetchAllAssoc('name', PDO::FETCH_ASSOC);
+
+ // Allow the user styles to override the module styles.
+ foreach ($user_styles as $style_name => $style) {
+ $style['module'] = NULL;
+ $style['storage'] = IMAGE_STORAGE_NORMAL;
+ $style['effects'] = image_style_effects($style);
+ if (isset($styles[$style_name]['module'])) {
+ $style['module'] = $styles[$style_name]['module'];
+ $style['storage'] = IMAGE_STORAGE_OVERRIDE;
+ }
+ $styles[$style_name] = $style;
+ }
+
+ drupal_alter('image_styles', $styles);
+ cache_set('image_styles', $styles);
+ }
+ }
+
+ return $styles;
+}
+
+/**
+ * Loads a style by style name or ID.
+ *
+ * May be used as a loader for menu items.
+ *
+ * @param $name
+ * The name of the style.
+ * @param $isid
+ * Optional. The numeric id of a style if the name is not known.
+ * @param $include
+ * If set, this loader will restrict to a specific type of image style, may be
+ * one of the defined Image style storage constants.
+ *
+ * @return
+ * An image style array containing the following keys:
+ * - "isid": The unique image style ID.
+ * - "name": The unique image style name.
+ * - "effects": An array of image effects within this image style.
+ * If the image style name or ID is not valid, an empty array is returned.
+ * @see image_effect_load()
+ */
+function image_style_load($name = NULL, $isid = NULL, $include = NULL) {
+ $styles = image_styles();
+
+ // If retrieving by name.
+ if (isset($name) && isset($styles[$name])) {
+ $style = $styles[$name];
+ }
+
+ // If retrieving by image style id.
+ if (!isset($name) && isset($isid)) {
+ foreach ($styles as $name => $database_style) {
+ if (isset($database_style['isid']) && $database_style['isid'] == $isid) {
+ $style = $database_style;
+ break;
+ }
+ }
+ }
+
+ // Restrict to the specific type of flag. This bitwise operation basically
+ // states "if the storage is X, then allow".
+ if (isset($style) && (!isset($include) || ($style['storage'] & (int) $include))) {
+ return $style;
+ }
+
+ // Otherwise the style was not found.
+ return FALSE;
+}
+
+/**
+ * Saves an image style.
+ *
+ * @param array $style
+ * An image style array containing:
+ * - name: A unique name for the style.
+ * - isid: (optional) An image style ID.
+ *
+ * @return array
+ * An image style array containing:
+ * - name: An unique name for the style.
+ * - old_name: The original name for the style.
+ * - isid: An image style ID.
+ * - is_new: TRUE if this is a new style, and FALSE if it is an existing
+ * style.
+ */
+function image_style_save($style) {
+ if (isset($style['isid']) && is_numeric($style['isid'])) {
+ // Load the existing style to make sure we account for renamed styles.
+ $old_style = image_style_load(NULL, $style['isid']);
+ image_style_flush($old_style);
+ drupal_write_record('image_styles', $style, 'isid');
+ if ($old_style['name'] != $style['name']) {
+ $style['old_name'] = $old_style['name'];
+ }
+ }
+ else {
+ // Add a default label when not given.
+ if (empty($style['label'])) {
+ $style['label'] = $style['name'];
+ }
+ drupal_write_record('image_styles', $style);
+ $style['is_new'] = TRUE;
+ }
+
+ // Let other modules update as necessary on save.
+ module_invoke_all('image_style_save', $style);
+
+ // Clear all caches and flush.
+ image_style_flush($style);
+
+ return $style;
+}
+
+/**
+ * Deletes an image style.
+ *
+ * @param $style
+ * An image style array.
+ * @param $replacement_style_name
+ * (optional) When deleting a style, specify a replacement style name so
+ * that existing settings (if any) may be converted to a new style.
+ *
+ * @return
+ * TRUE on success.
+ */
+function image_style_delete($style, $replacement_style_name = '') {
+ image_style_flush($style);
+
+ db_delete('image_effects')->condition('isid', $style['isid'])->execute();
+ db_delete('image_styles')->condition('isid', $style['isid'])->execute();
+
+ // Let other modules update as necessary on save.
+ $style['old_name'] = $style['name'];
+ $style['name'] = $replacement_style_name;
+ module_invoke_all('image_style_delete', $style);
+
+ return TRUE;
+}
+
+/**
+ * Loads all the effects for an image style.
+ *
+ * @param array $style
+ * An image style array containing:
+ * - isid: The unique image style ID that contains this image effect.
+ *
+ * @return array
+ * An array of image effects associated with specified image style in the
+ * format array('isid' => array()), or an empty array if the specified style
+ * has no effects.
+ * @see image_effects()
+ */
+function image_style_effects($style) {
+ $effects = image_effects();
+ $style_effects = array();
+ foreach ($effects as $effect) {
+ if ($style['isid'] == $effect['isid']) {
+ $style_effects[$effect['ieid']] = $effect;
+ }
+ }
+
+ return $style_effects;
+}
+
+/**
+ * Gets an array of image styles suitable for using as select list options.
+ *
+ * @param $include_empty
+ * If TRUE a <none> option will be inserted in the options array.
+ * @param $output
+ * Optional flag determining how the options will be sanitized on output.
+ * Leave this at the default (CHECK_PLAIN) if you are using the output of
+ * this function directly in an HTML context, such as for checkbox or radio
+ * button labels, and do not plan to sanitize it on your own. If using the
+ * output of this function as select list options (its primary use case), you
+ * should instead set this flag to PASS_THROUGH to avoid double-escaping of
+ * the output (the form API sanitizes select list options by default).
+ *
+ * @return
+ * Array of image styles with the machine name as key and the label as value.
+ */
+function image_style_options($include_empty = TRUE, $output = CHECK_PLAIN) {
+ $styles = image_styles();
+ $options = array();
+ if ($include_empty && !empty($styles)) {
+ $options[''] = t('<none>');
+ }
+ foreach ($styles as $name => $style) {
+ $options[$name] = ($output == PASS_THROUGH) ? $style['label'] : check_plain($style['label']);
+ }
+
+ if (empty($options)) {
+ $options[''] = t('No defined styles');
+ }
+ return $options;
+}
+
+/**
+ * Page callback: Generates a derivative, given a style and image path.
+ *
+ * After generating an image, transfer it to the requesting agent.
+ *
+ * @param $style
+ * The image style
+ */
+function image_style_deliver($style, $scheme) {
+ $args = func_get_args();
+ array_shift($args);
+ array_shift($args);
+ $target = implode('/', $args);
+
+ // Check that the style is defined, the scheme is valid, and the image
+ // derivative token is valid. (Sites which require image derivatives to be
+ // generated without a token can set the 'image_allow_insecure_derivatives'
+ // variable to TRUE to bypass the latter check, but this will increase the
+ // site's vulnerability to denial-of-service attacks. To prevent this
+ // variable from leaving the site vulnerable to the most serious attacks, a
+ // token is always required when a derivative of a derivative is requested.)
+ $valid = !empty($style) && file_stream_wrapper_valid_scheme($scheme);
+ if (!variable_get('image_allow_insecure_derivatives', FALSE) || strpos(ltrim($target, '\/'), 'styles/') === 0) {
+ $valid = $valid && isset($_GET[IMAGE_DERIVATIVE_TOKEN]) && $_GET[IMAGE_DERIVATIVE_TOKEN] === image_style_path_token($style['name'], $scheme . '://' . $target);
+ }
+ if (!$valid) {
+ return MENU_ACCESS_DENIED;
+ }
+
+ $image_uri = $scheme . '://' . $target;
+ $derivative_uri = image_style_path($style['name'], $image_uri);
+
+ // If using the private scheme, let other modules provide headers and
+ // control access to the file.
+ if ($scheme == 'private') {
+ if (file_exists($derivative_uri)) {
+ file_download($scheme, file_uri_target($derivative_uri));
+ }
+ else {
+ $headers = module_invoke_all('file_download', $image_uri);
+ if (in_array(-1, $headers) || empty($headers)) {
+ return MENU_ACCESS_DENIED;
+ }
+ if (count($headers)) {
+ foreach ($headers as $name => $value) {
+ drupal_add_http_header($name, $value);
+ }
+ }
+ }
+ }
+
+ // Don't start generating the image if the derivative already exists or if
+ // generation is in progress in another thread.
+ $lock_name = 'image_style_deliver:' . $style['name'] . ':' . drupal_hash_base64($image_uri);
+ if (!file_exists($derivative_uri)) {
+ $lock_acquired = lock_acquire($lock_name);
+ if (!$lock_acquired) {
+ // Tell client to retry again in 3 seconds. Currently no browsers are known
+ // to support Retry-After.
+ drupal_add_http_header('Status', '503 Service Unavailable');
+ drupal_add_http_header('Retry-After', 3);
+ print t('Image generation in progress. Try again shortly.');
+ drupal_exit();
+ }
+ }
+
+ // Try to generate the image, unless another thread just did it while we were
+ // acquiring the lock.
+ $success = file_exists($derivative_uri) || image_style_create_derivative($style, $image_uri, $derivative_uri);
+
+ if (!empty($lock_acquired)) {
+ lock_release($lock_name);
+ }
+
+ if ($success) {
+ $image = image_load($derivative_uri);
+ file_transfer($image->source, array('Content-Type' => $image->info['mime_type'], 'Content-Length' => $image->info['file_size']));
+ }
+ else {
+ watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri));
+ drupal_add_http_header('Status', '500 Internal Server Error');
+ print t('Error generating image.');
+ drupal_exit();
+ }
+}
+
+/**
+ * Creates a new image derivative based on an image style.
+ *
+ * Generates an image derivative by creating the destination folder (if it does
+ * not already exist), applying all image effects defined in $style['effects'],
+ * and saving a cached version of the resulting image.
+ *
+ * @param $style
+ * An image style array.
+ * @param $source
+ * Path of the source file.
+ * @param $destination
+ * Path or URI of the destination file.
+ *
+ * @return
+ * TRUE if an image derivative was generated, or FALSE if the image derivative
+ * could not be generated.
+ *
+ * @see image_style_load()
+ */
+function image_style_create_derivative($style, $source, $destination) {
+ // If the source file doesn't exist, return FALSE without creating folders.
+ if (!$image = image_load($source)) {
+ return FALSE;
+ }
+
+ // Get the folder for the final location of this style.
+ $directory = drupal_dirname($destination);
+
+ // Build the destination folder tree if it doesn't already exist.
+ if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+ watchdog('image', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
+ return FALSE;
+ }
+
+ foreach ($style['effects'] as $effect) {
+ image_effect_apply($image, $effect);
+ }
+
+ if (!image_save($image, $destination)) {
+ if (file_exists($destination)) {
+ watchdog('image', 'Cached image file %destination already exists. There may be an issue with your rewrite configuration.', array('%destination' => $destination), WATCHDOG_ERROR);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * Determines the dimensions of the styled image.
+ *
+ * Applies all of an image style's effects to $dimensions.
+ *
+ * @param $style_name
+ * The name of the style to be applied.
+ * @param $dimensions
+ * Dimensions to be modified - an array with components width and height, in
+ * pixels.
+ */
+function image_style_transform_dimensions($style_name, array &$dimensions) {
+ module_load_include('inc', 'image', 'image.effects');
+ $style = image_style_load($style_name);
+
+ if (!is_array($style)) {
+ return;
+ }
+
+ foreach ($style['effects'] as $effect) {
+ if (isset($effect['dimensions passthrough'])) {
+ continue;
+ }
+
+ if (isset($effect['dimensions callback'])) {
+ $effect['dimensions callback']($dimensions, $effect['data']);
+ }
+ else {
+ $dimensions['width'] = $dimensions['height'] = NULL;
+ }
+ }
+}
+
+/**
+ * Flushes cached media for a style.
+ *
+ * @param $style
+ * An image style array.
+ */
+function image_style_flush($style) {
+ // Delete the style directory in each registered wrapper.
+ $wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
+ foreach ($wrappers as $wrapper => $wrapper_data) {
+ if (file_exists($directory = $wrapper . '://styles/' . $style['name'])) {
+ file_unmanaged_delete_recursive($directory);
+ }
+ }
+
+ // Let other modules update as necessary on flush.
+ module_invoke_all('image_style_flush', $style);
+
+ // Clear image style and effect caches.
+ cache_clear_all('image_styles', 'cache');
+ cache_clear_all('image_effects:', 'cache', TRUE);
+ drupal_static_reset('image_styles');
+ drupal_static_reset('image_effects');
+
+ // Clear field caches so that formatters may be added for this style.
+ field_info_cache_clear();
+ drupal_theme_rebuild();
+
+ // Clear page caches when flushing.
+ if (module_exists('block')) {
+ cache_clear_all('*', 'cache_block', TRUE);
+ }
+ cache_clear_all('*', 'cache_page', TRUE);
+}
+
+/**
+ * Returns the URL for an image derivative given a style and image path.
+ *
+ * @param $style_name
+ * The name of the style to be used with this image.
+ * @param $path
+ * The path to the image.
+ *
+ * @return
+ * The absolute URL where a style image can be downloaded, suitable for use
+ * in an <img> tag. Requesting the URL will cause the image to be created.
+ * @see image_style_deliver()
+ */
+function image_style_url($style_name, $path) {
+ $uri = image_style_path($style_name, $path);
+
+ // The passed-in $path variable can be either a relative path or a full URI.
+ $original_uri = file_uri_scheme($path) ? file_stream_wrapper_uri_normalize($path) : file_build_uri($path);
+
+ // The token query is added even if the 'image_allow_insecure_derivatives'
+ // variable is TRUE, so that the emitted links remain valid if it is changed
+ // back to the default FALSE.
+ $token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($style_name, $original_uri));
+
+ // If not using clean URLs, the image derivative callback is only available
+ // with the query string. If the file does not exist, use url() to ensure
+ // that it is included. Once the file exists it's fine to fall back to the
+ // actual file path, this avoids bootstrapping PHP once the files are built.
+ if (!variable_get('clean_url') && file_uri_scheme($uri) == 'public' && !file_exists($uri)) {
+ $directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath();
+ return url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query));
+ }
+
+ $file_url = file_create_url($uri);
+ // Append the query string with the token.
+ return $file_url . (strpos($file_url, '?') !== FALSE ? '&' : '?') . drupal_http_build_query($token_query);
+}
+
+/**
+ * Generates a token to protect an image style derivative.
+ *
+ * This prevents unauthorized generation of an image style derivative,
+ * which can be costly both in CPU time and disk space.
+ *
+ * @param $style_name
+ * The name of the image style.
+ * @param $uri
+ * The URI of the image for this style, for example as returned by
+ * image_style_path().
+ *
+ * @return
+ * An eight-character token which can be used to protect image style
+ * derivatives against denial-of-service attacks.
+ */
+function image_style_path_token($style_name, $uri) {
+ // Return the first eight characters.
+ return substr(drupal_hmac_base64($style_name . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8);
+}
+
+/**
+ * Returns the URI of an image when using a style.
+ *
+ * The path returned by this function may not exist. The default generation
+ * method only creates images when they are requested by a user's browser.
+ *
+ * @param $style_name
+ * The name of the style to be used with this image.
+ * @param $uri
+ * The URI or path to the image.
+ *
+ * @return
+ * The URI to an image style image.
+ * @see image_style_url()
+ */
+function image_style_path($style_name, $uri) {
+ $scheme = file_uri_scheme($uri);
+ if ($scheme) {
+ $path = file_uri_target($uri);
+ }
+ else {
+ $path = $uri;
+ $scheme = file_default_scheme();
+ }
+ return $scheme . '://styles/' . $style_name . '/' . $scheme . '/' . $path;
+}
+
+/**
+ * Saves a default image style to the database.
+ *
+ * @param style
+ * An image style array provided by a module.
+ *
+ * @return
+ * An image style array. The returned style array will include the new 'isid'
+ * assigned to the style.
+ */
+function image_default_style_save($style) {
+ $style = image_style_save($style);
+ $effects = array();
+ foreach ($style['effects'] as $effect) {
+ $effect['isid'] = $style['isid'];
+ $effect = image_effect_save($effect);
+ $effects[$effect['ieid']] = $effect;
+ }
+ $style['effects'] = $effects;
+ return $style;
+}
+
+/**
+ * Reverts the changes made by users to a default image style.
+ *
+ * @param style
+ * An image style array.
+ * @return
+ * Boolean TRUE if the operation succeeded.
+ */
+function image_default_style_revert($style) {
+ image_style_flush($style);
+
+ db_delete('image_effects')->condition('isid', $style['isid'])->execute();
+ db_delete('image_styles')->condition('isid', $style['isid'])->execute();
+
+ return TRUE;
+}
+
+/**
+ * Returns a set of image effects.
+ *
+ * These image effects are exposed by modules implementing
+ * hook_image_effect_info().
+ *
+ * @return
+ * An array of image effects to be used when transforming images.
+ * @see hook_image_effect_info()
+ * @see image_effect_definition_load()
+ */
+function image_effect_definitions() {
+ global $language;
+
+ // hook_image_effect_info() includes translated strings, so each language is
+ // cached separately.
+ $langcode = $language->language;
+
+ $effects = &drupal_static(__FUNCTION__);
+
+ if (!isset($effects)) {
+ if ($cache = cache_get("image_effects:$langcode")) {
+ $effects = $cache->data;
+ }
+ else {
+ $effects = array();
+ include_once DRUPAL_ROOT . '/modules/image/image.effects.inc';
+ foreach (module_implements('image_effect_info') as $module) {
+ foreach (module_invoke($module, 'image_effect_info') as $name => $effect) {
+ // Ensure the current toolkit supports the effect.
+ $effect['module'] = $module;
+ $effect['name'] = $name;
+ $effect['data'] = isset($effect['data']) ? $effect['data'] : array();
+ $effects[$name] = $effect;
+ }
+ }
+ uasort($effects, '_image_effect_definitions_sort');
+ drupal_alter('image_effect_info', $effects);
+ cache_set("image_effects:$langcode", $effects);
+ }
+ }
+
+ return $effects;
+}
+
+/**
+ * Loads the definition for an image effect.
+ *
+ * The effect definition is a set of core properties for an image effect, not
+ * containing any user-settings. The definition defines various functions to
+ * call when configuring or executing an image effect. This loader is mostly for
+ * internal use within image.module. Use image_effect_load() or
+ * image_style_load() to get image effects that contain configuration.
+ *
+ * @param $effect
+ * The name of the effect definition to load.
+ * @param $style
+ * An image style array to which this effect will be added.
+ *
+ * @return
+ * An array containing the image effect definition with the following keys:
+ * - "effect": The unique name for the effect being performed. Usually prefixed
+ * with the name of the module providing the effect.
+ * - "module": The module providing the effect.
+ * - "help": A description of the effect.
+ * - "function": The name of the function that will execute the effect.
+ * - "form": (optional) The name of a function to configure the effect.
+ * - "summary": (optional) The name of a theme function that will display a
+ * one-line summary of the effect. Does not include the "theme_" prefix.
+ */
+function image_effect_definition_load($effect, $style_name = NULL) {
+ $definitions = image_effect_definitions();
+
+ // If a style is specified, do not allow loading of default style
+ // effects.
+ if (isset($style_name)) {
+ $style = image_style_load($style_name, NULL);
+ if ($style['storage'] == IMAGE_STORAGE_DEFAULT) {
+ return FALSE;
+ }
+ }
+
+ return isset($definitions[$effect]) ? $definitions[$effect] : FALSE;
+}
+
+/**
+ * Loads all image effects from the database.
+ *
+ * @return
+ * An array of all image effects.
+ * @see image_effect_load()
+ */
+function image_effects() {
+ $effects = &drupal_static(__FUNCTION__);
+
+ if (!isset($effects)) {
+ $effects = array();
+
+ // Add database image effects.
+ $result = db_select('image_effects', NULL, array('fetch' => PDO::FETCH_ASSOC))
+ ->fields('image_effects')
+ ->orderBy('image_effects.weight', 'ASC')
+ ->execute();
+ foreach ($result as $effect) {
+ $effect['data'] = unserialize($effect['data']);
+ $definition = image_effect_definition_load($effect['name']);
+ // Do not load image effects whose definition cannot be found.
+ if ($definition) {
+ $effect = array_merge($definition, $effect);
+ $effects[$effect['ieid']] = $effect;
+ }
+ }
+ }
+
+ return $effects;
+}
+
+/**
+ * Loads a single image effect.
+ *
+ * @param $ieid
+ * The image effect ID.
+ * @param $style_name
+ * The image style name.
+ * @param $include
+ * If set, this loader will restrict to a specific type of image style, may be
+ * one of the defined Image style storage constants.
+ *
+ * @return
+ * An image effect array, consisting of the following keys:
+ * - "ieid": The unique image effect ID.
+ * - "isid": The unique image style ID that contains this image effect.
+ * - "weight": The weight of this image effect within the image style.
+ * - "name": The name of the effect definition that powers this image effect.
+ * - "data": An array of configuration options for this image effect.
+ * Besides these keys, the entirety of the image definition is merged into
+ * the image effect array. Returns FALSE if the specified effect cannot be
+ * found.
+ * @see image_style_load()
+ * @see image_effect_definition_load()
+ */
+function image_effect_load($ieid, $style_name, $include = NULL) {
+ if (($style = image_style_load($style_name, NULL, $include)) && isset($style['effects'][$ieid])) {
+ return $style['effects'][$ieid];
+ }
+ return FALSE;
+}
+
+/**
+ * Saves an image effect.
+ *
+ * @param $effect
+ * An image effect array.
+ *
+ * @return
+ * An image effect array. In the case of a new effect, 'ieid' will be set.
+ */
+function image_effect_save($effect) {
+ if (!empty($effect['ieid'])) {
+ drupal_write_record('image_effects', $effect, 'ieid');
+ }
+ else {
+ drupal_write_record('image_effects', $effect);
+ }
+ $style = image_style_load(NULL, $effect['isid']);
+ image_style_flush($style);
+ return $effect;
+}
+
+/**
+ * Deletes an image effect.
+ *
+ * @param $effect
+ * An image effect array.
+ */
+function image_effect_delete($effect) {
+ db_delete('image_effects')->condition('ieid', $effect['ieid'])->execute();
+ $style = image_style_load(NULL, $effect['isid']);
+ image_style_flush($style);
+}
+
+/**
+ * Applies an image effect to the image object.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $effect
+ * An image effect array.
+ *
+ * @return
+ * TRUE on success. FALSE if unable to perform the image effect on the image.
+ */
+function image_effect_apply($image, $effect) {
+ module_load_include('inc', 'image', 'image.effects');
+ $function = $effect['effect callback'];
+ if (function_exists($function)) {
+ return $function($image, $effect['data']);
+ }
+ return FALSE;
+}
+
+/**
+ * Returns HTML for an image using a specific image style.
+ *
+ * @param $variables
+ * An associative array containing:
+ * - style_name: The name of the style to be used to alter the original image.
+ * - path: The path of the image file relative to the Drupal files directory.
+ * This function does not work with images outside the files directory nor
+ * with remotely hosted images. This should be in a format such as
+ * 'images/image.jpg', or using a stream wrapper such as
+ * 'public://images/image.jpg'.
+ * - width: The width of the source image (if known).
+ * - height: The height of the source image (if known).
+ * - alt: The alternative text for text-based browsers.
+ * - title: The title text is displayed when the image is hovered in some
+ * popular browsers.
+ * - attributes: Associative array of attributes to be placed in the img tag.
+ *
+ * @ingroup themeable
+ */
+function theme_image_style($variables) {
+ // Determine the dimensions of the styled image.
+ $dimensions = array(
+ 'width' => $variables['width'],
+ 'height' => $variables['height'],
+ );
+
+ image_style_transform_dimensions($variables['style_name'], $dimensions);
+
+ $variables['width'] = $dimensions['width'];
+ $variables['height'] = $dimensions['height'];
+
+ // Determine the URL for the styled image.
+ $variables['path'] = image_style_url($variables['style_name'], $variables['path']);
+ return theme('image', $variables);
+}
+
+/**
+ * Accepts a keyword (center, top, left, etc) and returns it as a pixel offset.
+ *
+ * @param $value
+ * @param $current_pixels
+ * @param $new_pixels
+ */
+function image_filter_keyword($value, $current_pixels, $new_pixels) {
+ switch ($value) {
+ case 'top':
+ case 'left':
+ return 0;
+
+ case 'bottom':
+ case 'right':
+ return $current_pixels - $new_pixels;
+
+ case 'center':
+ return $current_pixels / 2 - $new_pixels / 2;
+ }
+ return $value;
+}
+
+/**
+ * Internal function for sorting image effect definitions through uasort().
+ *
+ * @see image_effect_definitions()
+ */
+function _image_effect_definitions_sort($a, $b) {
+ return strcasecmp($a['name'], $b['name']);
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/image.test b/kolab.org/www/drupal-7.26/modules/image/image.test
new file mode 100644
index 0000000..4a4aab0
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/image.test
@@ -0,0 +1,1865 @@
+<?php
+
+/**
+ * @file
+ * Tests for image.module.
+ */
+
+/**
+ * TODO: Test the following functions.
+ *
+ * image.effects.inc:
+ * image_style_generate()
+ * image_style_create_derivative()
+ *
+ * image.module:
+ * image_style_load()
+ * image_style_save()
+ * image_style_delete()
+ * image_style_options()
+ * image_effect_definition_load()
+ * image_effect_load()
+ * image_effect_save()
+ * image_effect_delete()
+ * image_filter_keyword()
+ */
+
+/**
+ * This class provides methods specifically for testing Image's field handling.
+ */
+class ImageFieldTestCase extends DrupalWebTestCase {
+ protected $admin_user;
+
+ function setUp() {
+ parent::setUp('image');
+ $this->admin_user = $this->drupalCreateUser(array('access content', 'access administration pages', 'administer site configuration', 'administer content types', 'administer nodes', 'create article content', 'edit any article content', 'delete any article content', 'administer image styles'));
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Create a new image field.
+ *
+ * @param $name
+ * The name of the new field (all lowercase), exclude the "field_" prefix.
+ * @param $type_name
+ * The node type that this field will be added to.
+ * @param $field_settings
+ * A list of field settings that will be added to the defaults.
+ * @param $instance_settings
+ * A list of instance settings that will be added to the instance defaults.
+ * @param $widget_settings
+ * A list of widget settings that will be added to the widget defaults.
+ */
+ function createImageField($name, $type_name, $field_settings = array(), $instance_settings = array(), $widget_settings = array()) {
+ $field = array(
+ 'field_name' => $name,
+ 'type' => 'image',
+ 'settings' => array(),
+ 'cardinality' => !empty($field_settings['cardinality']) ? $field_settings['cardinality'] : 1,
+ );
+ $field['settings'] = array_merge($field['settings'], $field_settings);
+ field_create_field($field);
+
+ $instance = array(
+ 'field_name' => $field['field_name'],
+ 'entity_type' => 'node',
+ 'label' => $name,
+ 'bundle' => $type_name,
+ 'required' => !empty($instance_settings['required']),
+ 'settings' => array(),
+ 'widget' => array(
+ 'type' => 'image_image',
+ 'settings' => array(),
+ ),
+ );
+ $instance['settings'] = array_merge($instance['settings'], $instance_settings);
+ $instance['widget']['settings'] = array_merge($instance['widget']['settings'], $widget_settings);
+ return field_create_instance($instance);
+ }
+
+ /**
+ * Upload an image to a node.
+ *
+ * @param $image
+ * A file object representing the image to upload.
+ * @param $field_name
+ * Name of the image field the image should be attached to.
+ * @param $type
+ * The type of node to create.
+ */
+ function uploadNodeImage($image, $field_name, $type) {
+ $edit = array(
+ 'title' => $this->randomName(),
+ );
+ $edit['files[' . $field_name . '_' . LANGUAGE_NONE . '_0]'] = drupal_realpath($image->uri);
+ $this->drupalPost('node/add/' . $type, $edit, t('Save'));
+
+ // Retrieve ID of the newly created node from the current URL.
+ $matches = array();
+ preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
+ return isset($matches[1]) ? $matches[1] : FALSE;
+ }
+}
+
+/**
+ * Tests the functions for generating paths and URLs for image styles.
+ */
+class ImageStylesPathAndUrlTestCase extends DrupalWebTestCase {
+ protected $style_name;
+ protected $image_info;
+ protected $image_filepath;
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image styles path and URL functions',
+ 'description' => 'Tests functions for generating paths and URLs to image styles.',
+ 'group' => 'Image',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('image_module_test');
+
+ $this->style_name = 'style_foo';
+ image_style_save(array('name' => $this->style_name, 'label' => $this->randomString()));
+ }
+
+ /**
+ * Test image_style_path().
+ */
+ function testImageStylePath() {
+ $scheme = 'public';
+ $actual = image_style_path($this->style_name, "$scheme://foo/bar.gif");
+ $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
+ $this->assertEqual($actual, $expected, 'Got the path for a file URI.');
+
+ $actual = image_style_path($this->style_name, 'foo/bar.gif');
+ $expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
+ $this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
+ }
+
+ /**
+ * Test image_style_url() with a file using the "public://" scheme.
+ */
+ function testImageStyleUrlAndPathPublic() {
+ $this->_testImageStyleUrlAndPath('public');
+ }
+
+ /**
+ * Test image_style_url() with a file using the "private://" scheme.
+ */
+ function testImageStyleUrlAndPathPrivate() {
+ $this->_testImageStyleUrlAndPath('private');
+ }
+
+ /**
+ * Test image_style_url() with the "public://" scheme and unclean URLs.
+ */
+ function testImageStylUrlAndPathPublicUnclean() {
+ $this->_testImageStyleUrlAndPath('public', FALSE);
+ }
+
+ /**
+ * Test image_style_url() with the "private://" schema and unclean URLs.
+ */
+ function testImageStyleUrlAndPathPrivateUnclean() {
+ $this->_testImageStyleUrlAndPath('private', FALSE);
+ }
+
+ /**
+ * Test image_style_url() with a file URL that has an extra slash in it.
+ */
+ function testImageStyleUrlExtraSlash() {
+ $this->_testImageStyleUrlAndPath('public', TRUE, TRUE);
+ }
+
+ /**
+ * Test image_style_url().
+ */
+ function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
+ // Make the default scheme neither "public" nor "private" to verify the
+ // functions work for other than the default scheme.
+ variable_set('file_default_scheme', 'temporary');
+ variable_set('clean_url', $clean_url);
+
+ // Create the directories for the styles.
+ $directory = $scheme . '://styles/' . $this->style_name;
+ $status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
+ $this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
+
+ // Create a working copy of the file.
+ $files = $this->drupalGetTestFiles('image');
+ $file = array_shift($files);
+ $image_info = image_get_info($file->uri);
+ $original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
+ // Let the image_module_test module know about this file, so it can claim
+ // ownership in hook_file_download().
+ variable_set('image_module_test_file_download', $original_uri);
+ $this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.');
+
+ // Get the URL of a file that has not been generated and try to create it.
+ $generated_uri = image_style_path($this->style_name, $original_uri);
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $generate_url = image_style_url($this->style_name, $original_uri);
+
+ // Ensure that the tests still pass when the file is generated by accessing
+ // a poorly constructed (but still valid) file URL that has an extra slash
+ // in it.
+ if ($extra_slash) {
+ $modified_uri = str_replace('://', ':///', $original_uri);
+ $this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
+ $generate_url = image_style_url($this->style_name, $modified_uri);
+ }
+
+ if (!$clean_url) {
+ $this->assertTrue(strpos($generate_url, '?q=') !== FALSE, 'When using non-clean URLS, the system path contains the query string.');
+ }
+ // Add some extra chars to the token.
+ $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
+ $this->assertResponse(403, 'Image was inaccessible at the URL with an invalid token.');
+ // Change the parameter name so the token is missing.
+ $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
+ $this->assertResponse(403, 'Image was inaccessible at the URL with a missing token.');
+
+ // Check that the generated URL is the same when we pass in a relative path
+ // rather than a URI. We need to temporarily switch the default scheme to
+ // match the desired scheme before testing this, then switch it back to the
+ // "temporary" scheme used throughout this test afterwards.
+ variable_set('file_default_scheme', $scheme);
+ $relative_path = file_uri_target($original_uri);
+ $generate_url_from_relative_path = image_style_url($this->style_name, $relative_path);
+ $this->assertEqual($generate_url, $generate_url_from_relative_path, 'Generated URL is the same regardless of whether it came from a relative path or a file URI.');
+ variable_set('file_default_scheme', 'temporary');
+
+ // Fetch the URL that generates the file.
+ $this->drupalGet($generate_url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.');
+ $generated_image_info = image_get_info($generated_uri);
+ $this->assertEqual($this->drupalGetHeader('Content-Type'), $generated_image_info['mime_type'], 'Expected Content-Type was reported.');
+ $this->assertEqual($this->drupalGetHeader('Content-Length'), $generated_image_info['file_size'], 'Expected Content-Length was reported.');
+ if ($scheme == 'private') {
+ $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'no-cache, must-revalidate, post-check=0, pre-check=0', 'Cache-Control header was set to prevent caching.');
+ $this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
+
+ // Make sure that a second request to the already existing derivate works
+ // too.
+ $this->drupalGet($generate_url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+
+ // Make sure that access is denied for existing style files if we do not
+ // have access.
+ variable_del('image_module_test_file_download');
+ $this->drupalGet($generate_url);
+ $this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
+
+ // Repeat this with a different file that we do not have access to and
+ // make sure that access is denied.
+ $file_noaccess = array_shift($files);
+ $original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME);
+ $generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
+ $this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
+ $generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess);
+
+ $this->drupalGet($generate_url_noaccess);
+ $this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
+ // Verify that images are not appended to the response. Currently this test only uses PNG images.
+ if (strpos($generate_url, '.png') === FALSE ) {
+ $this->fail('Confirming that private image styles are not appended require PNG file.');
+ }
+ else {
+ // Check for PNG-Signature (cf. http://www.libpng.org/pub/png/book/chapter08.html#png.ch08.div.2) in the
+ // response body.
+ $this->assertNoRaw( chr(137) . chr(80) . chr(78) . chr(71) . chr(13) . chr(10) . chr(26) . chr(10), 'No PNG signature found in the response body.');
+ }
+ }
+ elseif ($clean_url) {
+ // Add some extra chars to the token.
+ $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', IMAGE_DERIVATIVE_TOKEN . '=Zo', $generate_url));
+ $this->assertResponse(200, 'Existing image was accessible at the URL with an invalid token.');
+ }
+
+ // Allow insecure image derivatives to be created for the remainder of this
+ // test.
+ variable_set('image_allow_insecure_derivatives', TRUE);
+
+ // Create another working copy of the file.
+ $files = $this->drupalGetTestFiles('image');
+ $file = array_shift($files);
+ $image_info = image_get_info($file->uri);
+ $original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
+ // Let the image_module_test module know about this file, so it can claim
+ // ownership in hook_file_download().
+ variable_set('image_module_test_file_download', $original_uri);
+
+ // Get the URL of a file that has not been generated and try to create it.
+ $generated_uri = image_style_path($this->style_name, $original_uri);
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $generate_url = image_style_url($this->style_name, $original_uri);
+
+ // Check that the image is accessible even without the security token.
+ $this->drupalGet(str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $generate_url));
+ $this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
+
+ // Check that a security token is still required when generating a second
+ // image derivative using the first one as a source.
+ $nested_uri = image_style_path($this->style_name, $generated_uri);
+ $nested_url = image_style_url($this->style_name, $generated_uri);
+ $nested_url_with_wrong_token = str_replace(IMAGE_DERIVATIVE_TOKEN . '=', 'wrongparam=', $nested_url);
+ $this->drupalGet($nested_url_with_wrong_token);
+ $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token.');
+ // Check that this restriction cannot be bypassed by adding extra slashes
+ // to the URL.
+ $this->drupalGet(substr_replace($nested_url_with_wrong_token, '//styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
+ $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with an extra forward slash in the URL.');
+ $this->drupalGet(substr_replace($nested_url_with_wrong_token, '/\styles/', strrpos($nested_url_with_wrong_token, '/styles/'), strlen('/styles/')));
+ $this->assertResponse(403, 'Image generated from an earlier derivative was inaccessible at the URL with a missing token, even with an extra backslash in the URL.');
+ // Make sure the image can still be generated if a correct token is used.
+ $this->drupalGet($nested_url);
+ $this->assertResponse(200, 'Image was accessible when a correct token was provided in the URL.');
+
+ // Check that requesting a nonexistent image does not create any new
+ // directories in the file system.
+ $directory = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/' . $this->randomName();
+ $this->drupalGet(file_create_url($directory . '/' . $this->randomName()));
+ $this->assertFalse(file_exists($directory), 'New directory was not created in the filesystem when requesting an unauthorized image.');
+ }
+}
+
+/**
+ * Use the image_test.module's mock toolkit to ensure that the effects are
+ * properly passing parameters to the image toolkit.
+ */
+class ImageEffectsUnitTest extends ImageToolkitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image effects',
+ 'description' => 'Test that the image effects pass parameters to the toolkit correctly.',
+ 'group' => 'Image',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('image_module_test');
+ module_load_include('inc', 'image', 'image.effects');
+ }
+
+ /**
+ * Test the image_resize_effect() function.
+ */
+ function testResizeEffect() {
+ $this->assertTrue(image_resize_effect($this->image, array('width' => 1, 'height' => 2)), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('resize'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['resize'][0][1], 1, 'Width was passed correctly');
+ $this->assertEqual($calls['resize'][0][2], 2, 'Height was passed correctly');
+ }
+
+ /**
+ * Test the image_scale_effect() function.
+ */
+ function testScaleEffect() {
+ // @todo: need to test upscaling.
+ $this->assertTrue(image_scale_effect($this->image, array('width' => 10, 'height' => 10)), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('resize'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['resize'][0][1], 10, 'Width was passed correctly');
+ $this->assertEqual($calls['resize'][0][2], 5, 'Height was based off aspect ratio and passed correctly');
+ }
+
+ /**
+ * Test the image_crop_effect() function.
+ */
+ function testCropEffect() {
+ // @todo should test the keyword offsets.
+ $this->assertTrue(image_crop_effect($this->image, array('anchor' => 'top-1', 'width' => 3, 'height' => 4)), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('crop'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['crop'][0][1], 0, 'X was passed correctly');
+ $this->assertEqual($calls['crop'][0][2], 1, 'Y was passed correctly');
+ $this->assertEqual($calls['crop'][0][3], 3, 'Width was passed correctly');
+ $this->assertEqual($calls['crop'][0][4], 4, 'Height was passed correctly');
+ }
+
+ /**
+ * Test the image_scale_and_crop_effect() function.
+ */
+ function testScaleAndCropEffect() {
+ $this->assertTrue(image_scale_and_crop_effect($this->image, array('width' => 5, 'height' => 10)), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('resize', 'crop'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['crop'][0][1], 7.5, 'X was computed and passed correctly');
+ $this->assertEqual($calls['crop'][0][2], 0, 'Y was computed and passed correctly');
+ $this->assertEqual($calls['crop'][0][3], 5, 'Width was computed and passed correctly');
+ $this->assertEqual($calls['crop'][0][4], 10, 'Height was computed and passed correctly');
+ }
+
+ /**
+ * Test the image_desaturate_effect() function.
+ */
+ function testDesaturateEffect() {
+ $this->assertTrue(image_desaturate_effect($this->image, array()), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('desaturate'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual(count($calls['desaturate'][0]), 1, 'Only the image was passed.');
+ }
+
+ /**
+ * Test the image_rotate_effect() function.
+ */
+ function testRotateEffect() {
+ // @todo: need to test with 'random' => TRUE
+ $this->assertTrue(image_rotate_effect($this->image, array('degrees' => 90, 'bgcolor' => '#fff')), 'Function returned the expected value.');
+ $this->assertToolkitOperationsCalled(array('rotate'));
+
+ // Check the parameters.
+ $calls = image_test_get_all_calls();
+ $this->assertEqual($calls['rotate'][0][1], 90, 'Degrees were passed correctly');
+ $this->assertEqual($calls['rotate'][0][2], 0xffffff, 'Background color was passed correctly');
+ }
+
+ /**
+ * Test image effect caching.
+ */
+ function testImageEffectsCaching() {
+ $image_effect_definitions_called = &drupal_static('image_module_test_image_effect_info_alter');
+
+ // First call should grab a fresh copy of the data.
+ $effects = image_effect_definitions();
+ $this->assertTrue($image_effect_definitions_called === 1, 'image_effect_definitions() generated data.');
+
+ // Second call should come from cache.
+ drupal_static_reset('image_effect_definitions');
+ drupal_static_reset('image_module_test_image_effect_info_alter');
+ $cached_effects = image_effect_definitions();
+ $this->assertTrue(is_null($image_effect_definitions_called), 'image_effect_definitions() returned data from cache.');
+
+ $this->assertTrue($effects == $cached_effects, 'Cached effects are the same as generated effects.');
+ }
+}
+
+/**
+ * Tests creation, deletion, and editing of image styles and effects.
+ */
+class ImageAdminStylesUnitTest extends ImageFieldTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image styles and effects UI configuration',
+ 'description' => 'Tests creation, deletion, and editing of image styles and effects at the UI level.',
+ 'group' => 'Image',
+ );
+ }
+
+ /**
+ * Given an image style, generate an image.
+ */
+ function createSampleImage($style) {
+ static $file_path;
+
+ // First, we need to make sure we have an image in our testing
+ // file directory. Copy over an image on the first run.
+ if (!isset($file_path)) {
+ $files = $this->drupalGetTestFiles('image');
+ $file = reset($files);
+ $file_path = file_unmanaged_copy($file->uri);
+ }
+
+ return image_style_url($style['name'], $file_path) ? $file_path : FALSE;
+ }
+
+ /**
+ * Count the number of images currently create for a style.
+ */
+ function getImageCount($style) {
+ return count(file_scan_directory('public://styles/' . $style['name'], '/.*/'));
+ }
+
+ /**
+ * Test creating an image style with a numeric name and ensuring it can be
+ * applied to an image.
+ */
+ function testNumericStyleName() {
+ $style_name = rand();
+ $style_label = $this->randomString();
+ $edit = array(
+ 'name' => $style_name,
+ 'label' => $style_label,
+ );
+ $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
+ $this->assertRaw(t('Style %name was created.', array('%name' => $style_label)), 'Image style successfully created.');
+ $options = image_style_options();
+ $this->assertTrue(array_key_exists($style_name, $options), format_string('Array key %key exists.', array('%key' => $style_name)));
+ }
+
+ /**
+ * General test to add a style, add/remove/edit effects to it, then delete it.
+ */
+ function testStyle() {
+ // Setup a style to be created and effects to add to it.
+ $style_name = strtolower($this->randomName(10));
+ $style_label = $this->randomString();
+ $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
+ $effect_edits = array(
+ 'image_resize' => array(
+ 'data[width]' => 100,
+ 'data[height]' => 101,
+ ),
+ 'image_scale' => array(
+ 'data[width]' => 110,
+ 'data[height]' => 111,
+ 'data[upscale]' => 1,
+ ),
+ 'image_scale_and_crop' => array(
+ 'data[width]' => 120,
+ 'data[height]' => 121,
+ ),
+ 'image_crop' => array(
+ 'data[width]' => 130,
+ 'data[height]' => 131,
+ 'data[anchor]' => 'center-center',
+ ),
+ 'image_desaturate' => array(
+ // No options for desaturate.
+ ),
+ 'image_rotate' => array(
+ 'data[degrees]' => 5,
+ 'data[random]' => 1,
+ 'data[bgcolor]' => '#FFFF00',
+ ),
+ );
+
+ // Add style form.
+
+ $edit = array(
+ 'name' => $style_name,
+ 'label' => $style_label,
+ );
+ $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
+ $this->assertRaw(t('Style %name was created.', array('%name' => $style_label)), 'Image style successfully created.');
+
+ // Add effect form.
+
+ // Add each sample effect to the style.
+ foreach ($effect_edits as $effect => $edit) {
+ // Add the effect.
+ $this->drupalPost($style_path, array('new' => $effect), t('Add'));
+ if (!empty($edit)) {
+ $this->drupalPost(NULL, $edit, t('Add effect'));
+ }
+ }
+
+ // Edit effect form.
+
+ // Revisit each form to make sure the effect was saved.
+ drupal_static_reset('image_styles');
+ $style = image_style_load($style_name);
+
+ foreach ($style['effects'] as $ieid => $effect) {
+ $this->drupalGet($style_path . '/effects/' . $ieid);
+ foreach ($effect_edits[$effect['name']] as $field => $value) {
+ $this->assertFieldByName($field, $value, format_string('The %field field in the %effect effect has the correct value of %value.', array('%field' => $field, '%effect' => $effect['name'], '%value' => $value)));
+ }
+ }
+
+ // Image style overview form (ordering and renaming).
+
+ // Confirm the order of effects is maintained according to the order we
+ // added the fields.
+ $effect_edits_order = array_keys($effect_edits);
+ $effects_order = array_values($style['effects']);
+ $order_correct = TRUE;
+ foreach ($effects_order as $index => $effect) {
+ if ($effect_edits_order[$index] != $effect['name']) {
+ $order_correct = FALSE;
+ }
+ }
+ $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
+
+ // Test the style overview form.
+ // Change the name of the style and adjust the weights of effects.
+ $style_name = strtolower($this->randomName(10));
+ $style_label = $this->randomString();
+ $weight = count($effect_edits);
+ $edit = array(
+ 'name' => $style_name,
+ 'label' => $style_label,
+ );
+ foreach ($style['effects'] as $ieid => $effect) {
+ $edit['effects[' . $ieid . '][weight]'] = $weight;
+ $weight--;
+ }
+
+ // Create an image to make sure it gets flushed after saving.
+ $image_path = $this->createSampleImage($style);
+ $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
+
+ $this->drupalPost($style_path, $edit, t('Update style'));
+
+ // Note that after changing the style name, the style path is changed.
+ $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
+
+ // Check that the URL was updated.
+ $this->drupalGet($style_path);
+ $this->assertResponse(200, format_string('Image style %original renamed to %new', array('%original' => $style['label'], '%new' => $style_label)));
+
+ // Check that the image was flushed after updating the style.
+ // This is especially important when renaming the style. Make sure that
+ // the old image directory has been deleted.
+ $this->assertEqual($this->getImageCount($style), 0, format_string('Image style %style was flushed after renaming the style and updating the order of effects.', array('%style' => $style['label'])));
+
+ // Load the style by the new name with the new weights.
+ drupal_static_reset('image_styles');
+ $style = image_style_load($style_name, NULL);
+
+ // Confirm the new style order was saved.
+ $effect_edits_order = array_reverse($effect_edits_order);
+ $effects_order = array_values($style['effects']);
+ $order_correct = TRUE;
+ foreach ($effects_order as $index => $effect) {
+ if ($effect_edits_order[$index] != $effect['name']) {
+ $order_correct = FALSE;
+ }
+ }
+ $this->assertTrue($order_correct, 'The order of the effects is correctly set by default.');
+
+ // Image effect deletion form.
+
+ // Create an image to make sure it gets flushed after deleting an effect.
+ $image_path = $this->createSampleImage($style);
+ $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
+
+ // Test effect deletion form.
+ $effect = array_pop($style['effects']);
+ $this->drupalPost($style_path . '/effects/' . $effect['ieid'] . '/delete', array(), t('Delete'));
+ $this->assertRaw(t('The image effect %name has been deleted.', array('%name' => $effect['label'])), 'Image effect deleted.');
+
+ // Style deletion form.
+
+ // Delete the style.
+ $this->drupalPost('admin/config/media/image-styles/delete/' . $style_name, array(), t('Delete'));
+
+ // Confirm the style directory has been removed.
+ $directory = file_default_scheme() . '://styles/' . $style_name;
+ $this->assertFalse(is_dir($directory), format_string('Image style %style directory removed on style deletion.', array('%style' => $style['label'])));
+
+ drupal_static_reset('image_styles');
+ $this->assertFalse(image_style_load($style_name), format_string('Image style %style successfully deleted.', array('%style' => $style['label'])));
+
+ }
+
+ /**
+ * Test to override, edit, then revert a style.
+ */
+ function testDefaultStyle() {
+ // Setup a style to be created and effects to add to it.
+ $style_name = 'thumbnail';
+ $style_label = 'Thumbnail (100x100)';
+ $edit_path = 'admin/config/media/image-styles/edit/' . $style_name;
+ $delete_path = 'admin/config/media/image-styles/delete/' . $style_name;
+ $revert_path = 'admin/config/media/image-styles/revert/' . $style_name;
+
+ // Ensure deleting a default is not possible.
+ $this->drupalGet($delete_path);
+ $this->assertText(t('Page not found'), 'Default styles may not be deleted.');
+
+ // Ensure that editing a default is not possible (without overriding).
+ $this->drupalGet($edit_path);
+ $disabled_field = $this->xpath('//input[@id=:id and @disabled="disabled"]', array(':id' => 'edit-name'));
+ $this->assertTrue($disabled_field, 'Default styles may not be renamed.');
+ $this->assertNoField('edit-submit', 'Default styles may not be edited.');
+ $this->assertNoField('edit-add', 'Default styles may not have new effects added.');
+
+ // Create an image to make sure the default works before overriding.
+ drupal_static_reset('image_styles');
+ $style = image_style_load($style_name);
+ $image_path = $this->createSampleImage($style);
+ $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
+
+ // Verify that effects attached to a default style do not have an ieid key.
+ foreach ($style['effects'] as $effect) {
+ $this->assertFalse(isset($effect['ieid']), format_string('The %effect effect does not have an ieid.', array('%effect' => $effect['name'])));
+ }
+
+ // Override the default.
+ $this->drupalPost($edit_path, array(), t('Override defaults'));
+ $this->assertRaw(t('The %style style has been overridden, allowing you to change its settings.', array('%style' => $style_label)), 'Default image style may be overridden.');
+
+ // Add sample effect to the overridden style.
+ $this->drupalPost($edit_path, array('new' => 'image_desaturate'), t('Add'));
+ drupal_static_reset('image_styles');
+ $style = image_style_load($style_name);
+
+ // Verify that effects attached to the style have an ieid now.
+ foreach ($style['effects'] as $effect) {
+ $this->assertTrue(isset($effect['ieid']), format_string('The %effect effect has an ieid.', array('%effect' => $effect['name'])));
+ }
+
+ // The style should now have 2 effect, the original scale provided by core
+ // and the desaturate effect we added in the override.
+ $effects = array_values($style['effects']);
+ $this->assertEqual($effects[0]['name'], 'image_scale', 'The default effect still exists in the overridden style.');
+ $this->assertEqual($effects[1]['name'], 'image_desaturate', 'The added effect exists in the overridden style.');
+
+ // Check that we are able to rename an overridden style.
+ $this->drupalGet($edit_path);
+ $disabled_field = $this->xpath('//input[@id=:id and @disabled="disabled"]', array(':id' => 'edit-name'));
+ $this->assertFalse($disabled_field, 'Overridden styles may be renamed.');
+
+ // Create an image to ensure the override works properly.
+ $image_path = $this->createSampleImage($style);
+ $this->assertEqual($this->getImageCount($style), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['label'], '%file' => $image_path)));
+
+ // Revert the image style.
+ $this->drupalPost($revert_path, array(), t('Revert'));
+ drupal_static_reset('image_styles');
+ $style = image_style_load($style_name);
+
+ // The style should now have the single effect for scale.
+ $effects = array_values($style['effects']);
+ $this->assertEqual($effects[0]['name'], 'image_scale', 'The default effect still exists in the reverted style.');
+ $this->assertFalse(array_key_exists(1, $effects), 'The added effect has been removed in the reverted style.');
+ }
+
+ /**
+ * Test deleting a style and choosing a replacement style.
+ */
+ function testStyleReplacement() {
+ // Create a new style.
+ $style_name = strtolower($this->randomName(10));
+ $style_label = $this->randomString();
+ image_style_save(array('name' => $style_name, 'label' => $style_label));
+ $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
+
+ // Create an image field that uses the new style.
+ $field_name = strtolower($this->randomName(10));
+ $this->createImageField($field_name, 'article');
+ $instance = field_info_instance('node', $field_name, 'article');
+ $instance['display']['default']['type'] = 'image';
+ $instance['display']['default']['settings']['image_style'] = $style_name;
+ field_update_instance($instance);
+
+ // Create a new node with an image attached.
+ $test_image = current($this->drupalGetTestFiles('image'));
+ $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
+ $node = node_load($nid);
+
+ // Test that image is displayed using newly created style.
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw(check_plain(image_style_url($style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style @style.', array('@style' => $style_name)));
+
+ // Rename the style and make sure the image field is updated.
+ $new_style_name = strtolower($this->randomName(10));
+ $new_style_label = $this->randomString();
+ $edit = array(
+ 'name' => $new_style_name,
+ 'label' => $new_style_label,
+ );
+ $this->drupalPost('admin/config/media/image-styles/edit/' . $style_name, $edit, t('Update style'));
+ $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw(check_plain(image_style_url($new_style_name, $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style replacement style.'));
+
+ // Delete the style and choose a replacement style.
+ $edit = array(
+ 'replacement' => 'thumbnail',
+ );
+ $this->drupalPost('admin/config/media/image-styles/delete/' . $new_style_name, $edit, t('Delete'));
+ $message = t('Style %name was deleted.', array('%name' => $new_style_label));
+ $this->assertRaw($message, $message);
+
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw(check_plain(image_style_url('thumbnail', $node->{$field_name}[LANGUAGE_NONE][0]['uri'])), format_string('Image displayed using style replacement style.'));
+ }
+}
+
+/**
+ * Test class to check that formatters and display settings are working.
+ */
+class ImageFieldDisplayTestCase extends ImageFieldTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image field display tests',
+ 'description' => 'Test the display of image fields.',
+ 'group' => 'Image',
+ );
+ }
+
+ /**
+ * Test image formatters on node display for public files.
+ */
+ function testImageFieldFormattersPublic() {
+ $this->_testImageFieldFormatters('public');
+ }
+
+ /**
+ * Test image formatters on node display for private files.
+ */
+ function testImageFieldFormattersPrivate() {
+ // Remove access content permission from anonymous users.
+ user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array('access content' => FALSE));
+ $this->_testImageFieldFormatters('private');
+ }
+
+ /**
+ * Test image formatters on node display.
+ */
+ function _testImageFieldFormatters($scheme) {
+ $field_name = strtolower($this->randomName());
+ $this->createImageField($field_name, 'article', array('uri_scheme' => $scheme));
+ // Create a new node with an image attached.
+ $test_image = current($this->drupalGetTestFiles('image'));
+ $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
+ $node = node_load($nid, NULL, TRUE);
+
+ // Test that the default formatter is being used.
+ $image_uri = $node->{$field_name}[LANGUAGE_NONE][0]['uri'];
+ $image_info = array(
+ 'path' => $image_uri,
+ 'width' => 40,
+ 'height' => 20,
+ );
+ $default_output = theme('image', $image_info);
+ $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
+
+ // Test the image linked to file formatter.
+ $instance = field_info_instance('node', $field_name, 'article');
+ $instance['display']['default']['type'] = 'image';
+ $instance['display']['default']['settings']['image_link'] = 'file';
+ field_update_instance($instance);
+ $default_output = l(theme('image', $image_info), file_create_url($image_uri), array('html' => TRUE));
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
+ // Verify that the image can be downloaded.
+ $this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
+ if ($scheme == 'private') {
+ // Only verify HTTP headers when using private scheme and the headers are
+ // sent by Drupal.
+ $this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
+ $this->assertEqual($this->drupalGetHeader('Cache-Control'), 'private', 'Cache-Control header was sent.');
+
+ // Log out and try to access the file.
+ $this->drupalLogout();
+ $this->drupalGet(file_create_url($image_uri));
+ $this->assertResponse('403', 'Access denied to original image as anonymous user.');
+
+ // Log in again.
+ $this->drupalLogin($this->admin_user);
+ }
+
+ // Test the image linked to content formatter.
+ $instance['display']['default']['settings']['image_link'] = 'content';
+ field_update_instance($instance);
+ $default_output = l(theme('image', $image_info), 'node/' . $nid, array('html' => TRUE, 'attributes' => array('class' => 'active')));
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw($default_output, 'Image linked to content formatter displaying correctly on full node view.');
+
+ // Test the image style 'thumbnail' formatter.
+ $instance['display']['default']['settings']['image_link'] = '';
+ $instance['display']['default']['settings']['image_style'] = 'thumbnail';
+ field_update_instance($instance);
+ // Ensure the derivative image is generated so we do not have to deal with
+ // image style callback paths.
+ $this->drupalGet(image_style_url('thumbnail', $image_uri));
+ // Need to create the URL again since it will change if clean URLs
+ // are disabled.
+ $image_info['path'] = image_style_url('thumbnail', $image_uri);
+ $image_info['width'] = 100;
+ $image_info['height'] = 50;
+ $default_output = theme('image', $image_info);
+ $this->drupalGet('node/' . $nid);
+ $this->assertRaw($default_output, 'Image style thumbnail formatter displaying correctly on full node view.');
+
+ if ($scheme == 'private') {
+ // Log out and try to access the file.
+ $this->drupalLogout();
+ $this->drupalGet(image_style_url('thumbnail', $image_uri));
+ $this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
+ }
+ }
+
+ /**
+ * Tests for image field settings.
+ */
+ function testImageFieldSettings() {
+ $test_image = current($this->drupalGetTestFiles('image'));
+ list(, $test_image_extension) = explode('.', $test_image->filename);
+ $field_name = strtolower($this->randomName());
+ $instance_settings = array(
+ 'alt_field' => 1,
+ 'file_extensions' => $test_image_extension,
+ 'max_filesize' => '50 KB',
+ 'max_resolution' => '100x100',
+ 'min_resolution' => '10x10',
+ 'title_field' => 1,
+ );
+ $widget_settings = array(
+ 'preview_image_style' => 'medium',
+ );
+ $field = $this->createImageField($field_name, 'article', array(), $instance_settings, $widget_settings);
+ $field['deleted'] = 0;
+ $table = _field_sql_storage_tablename($field);
+ $schema = drupal_get_schema($table, TRUE);
+ $instance = field_info_instance('node', $field_name, 'article');
+
+ $this->drupalGet('node/add/article');
+ $this->assertText(t('Files must be less than 50 KB.'), 'Image widget max file size is displayed on article form.');
+ $this->assertText(t('Allowed file types: ' . $test_image_extension . '.'), 'Image widget allowed file types displayed on article form.');
+ $this->assertText(t('Images must be between 10x10 and 100x100 pixels.'), 'Image widget allowed resolution displayed on article form.');
+
+ // We have to create the article first and then edit it because the alt
+ // and title fields do not display until the image has been attached.
+ $nid = $this->uploadNodeImage($test_image, $field_name, 'article');
+ $this->drupalGet('node/' . $nid . '/edit');
+ $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][alt]', '', 'Alt field displayed on article form.');
+ $this->assertFieldByName($field_name . '[' . LANGUAGE_NONE . '][0][title]', '', 'Title field displayed on article form.');
+ // Verify that the attached image is being previewed using the 'medium'
+ // style.
+ $node = node_load($nid, NULL, TRUE);
+ $image_info = array(
+ 'path' => image_style_url('medium', $node->{$field_name}[LANGUAGE_NONE][0]['uri']),
+ 'width' => 220,
+ 'height' => 110,
+ );
+ $default_output = theme('image', $image_info);
+ $this->assertRaw($default_output, "Preview image is displayed using 'medium' style.");
+
+ // Add alt/title fields to the image and verify that they are displayed.
+ $image_info = array(
+ 'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
+ 'alt' => $this->randomName(),
+ 'title' => $this->randomName(),
+ 'width' => 40,
+ 'height' => 20,
+ );
+ $edit = array(
+ $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $image_info['alt'],
+ $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $image_info['title'],
+ );
+ $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
+ $default_output = theme('image', $image_info);
+ $this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.');
+
+ // Verify that alt/title longer than allowed results in a validation error.
+ $test_size = 2000;
+ $edit = array(
+ $field_name . '[' . LANGUAGE_NONE . '][0][alt]' => $this->randomName($test_size),
+ $field_name . '[' . LANGUAGE_NONE . '][0][title]' => $this->randomName($test_size),
+ );
+ $this->drupalPost('node/' . $nid . '/edit', $edit, t('Save'));
+ $this->assertRaw(t('Alternate text cannot be longer than %max characters but is currently %length characters long.', array(
+ '%max' => $schema['fields'][$field_name .'_alt']['length'],
+ '%length' => $test_size,
+ )));
+ $this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array(
+ '%max' => $schema['fields'][$field_name .'_title']['length'],
+ '%length' => $test_size,
+ )));
+ }
+
+ /**
+ * Test passing attributes into the image field formatters.
+ */
+ function testImageFieldFormatterAttributes() {
+ $image = theme('image_formatter', array(
+ 'item' => array(
+ 'uri' => 'http://example.com/example.png',
+ 'attributes' => array(
+ 'data-image-field-formatter' => 'testFound',
+ ),
+ 'alt' => t('Image field formatter attribute test.'),
+ 'title' => t('Image field formatter'),
+ ),
+ ));
+ $this->assertTrue(stripos($image, 'testFound') > 0, 'Image field formatters can have attributes.');
+ }
+
+ /**
+ * Test use of a default image with an image field.
+ */
+ function testImageFieldDefaultImage() {
+ // Create a new image field.
+ $field_name = strtolower($this->randomName());
+ $this->createImageField($field_name, 'article');
+
+ // Create a new node, with no images and verify that no images are
+ // displayed.
+ $node = $this->drupalCreateNode(array('type' => 'article'));
+ $this->drupalGet('node/' . $node->nid);
+ // Verify that no image is displayed on the page by checking for the class
+ // that would be used on the image field.
+ $this->assertNoPattern('<div class="(.*?)field-name-' . strtr($field_name, '_', '-') . '(.*?)">', 'No image displayed when no image is attached and no default image specified.');
+
+ // Add a default image to the public imagefield instance.
+ $images = $this->drupalGetTestFiles('image');
+ $edit = array(
+ 'files[field_settings_default_image]' => drupal_realpath($images[0]->uri),
+ );
+ $this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
+ // Clear field info cache so the new default image is detected.
+ field_info_cache_clear();
+ $field = field_info_field($field_name);
+ $image = file_load($field['settings']['default_image']);
+ $this->assertTrue($image->status == FILE_STATUS_PERMANENT, 'The default image status is permanent.');
+ $default_output = theme('image', array('path' => $image->uri));
+ $this->drupalGet('node/' . $node->nid);
+ $this->assertRaw($default_output, 'Default image displayed when no user supplied image is present.');
+
+ // Create a node with an image attached and ensure that the default image
+ // is not displayed.
+ $nid = $this->uploadNodeImage($images[1], $field_name, 'article');
+ $node = node_load($nid, NULL, TRUE);
+ $image_info = array(
+ 'path' => $node->{$field_name}[LANGUAGE_NONE][0]['uri'],
+ 'width' => 40,
+ 'height' => 20,
+ );
+ $image_output = theme('image', $image_info);
+ $this->drupalGet('node/' . $nid);
+ $this->assertNoRaw($default_output, 'Default image is not displayed when user supplied image is present.');
+ $this->assertRaw($image_output, 'User supplied image is displayed.');
+
+ // Remove default image from the field and make sure it is no longer used.
+ $edit = array(
+ 'field[settings][default_image][fid]' => 0,
+ );
+ $this->drupalPost('admin/structure/types/manage/article/fields/' . $field_name, $edit, t('Save settings'));
+ // Clear field info cache so the new default image is detected.
+ field_info_cache_clear();
+ $field = field_info_field($field_name);
+ $this->assertFalse($field['settings']['default_image'], 'Default image removed from field.');
+ // Create an image field that uses the private:// scheme and test that the
+ // default image works as expected.
+ $private_field_name = strtolower($this->randomName());
+ $this->createImageField($private_field_name, 'article', array('uri_scheme' => 'private'));
+ // Add a default image to the new field.
+ $edit = array(
+ 'files[field_settings_default_image]' => drupal_realpath($images[1]->uri),
+ );
+ $this->drupalPost('admin/structure/types/manage/article/fields/' . $private_field_name, $edit, t('Save settings'));
+ $private_field = field_info_field($private_field_name);
+ $image = file_load($private_field['settings']['default_image']);
+ $this->assertEqual('private', file_uri_scheme($image->uri), 'Default image uses private:// scheme.');
+ $this->assertTrue($image->status == FILE_STATUS_PERMANENT, 'The default image status is permanent.');
+ // Create a new node with no image attached and ensure that default private
+ // image is displayed.
+ $node = $this->drupalCreateNode(array('type' => 'article'));
+ $default_output = theme('image', array('path' => $image->uri));
+ $this->drupalGet('node/' . $node->nid);
+ $this->assertRaw($default_output, 'Default private image displayed when no user supplied image is present.');
+ }
+}
+
+/**
+ * Test class to check for various validations.
+ */
+class ImageFieldValidateTestCase extends ImageFieldTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image field validation tests',
+ 'description' => 'Tests validation functions such as min/max resolution.',
+ 'group' => 'Image',
+ );
+ }
+
+ /**
+ * Test min/max resolution settings.
+ */
+ function testResolution() {
+ $field_name = strtolower($this->randomName());
+ $min_resolution = 50;
+ $max_resolution = 100;
+ $instance_settings = array(
+ 'max_resolution' => $max_resolution . 'x' . $max_resolution,
+ 'min_resolution' => $min_resolution . 'x' . $min_resolution,
+ );
+ $this->createImageField($field_name, 'article', array(), $instance_settings);
+
+ // We want a test image that is too small, and a test image that is too
+ // big, so cycle through test image files until we have what we need.
+ $image_that_is_too_big = FALSE;
+ $image_that_is_too_small = FALSE;
+ foreach ($this->drupalGetTestFiles('image') as $image) {
+ $info = image_get_info($image->uri);
+ if ($info['width'] > $max_resolution) {
+ $image_that_is_too_big = $image;
+ }
+ if ($info['width'] < $min_resolution) {
+ $image_that_is_too_small = $image;
+ }
+ if ($image_that_is_too_small && $image_that_is_too_big) {
+ break;
+ }
+ }
+ $nid = $this->uploadNodeImage($image_that_is_too_small, $field_name, 'article');
+ $this->assertText(t('The specified file ' . $image_that_is_too_small->filename . ' could not be uploaded. The image is too small; the minimum dimensions are 50x50 pixels.'), 'Node save failed when minimum image resolution was not met.');
+ $nid = $this->uploadNodeImage($image_that_is_too_big, $field_name, 'article');
+ $this->assertText(t('The image was resized to fit within the maximum allowed dimensions of 100x100 pixels.'), 'Image exceeding max resolution was properly resized.');
+ }
+}
+
+/**
+ * Tests that images have correct dimensions when styled.
+ */
+class ImageDimensionsTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image dimensions',
+ 'description' => 'Tests that images have correct dimensions when styled.',
+ 'group' => 'Image',
+ );
+ }
+
+ function setUp() {
+ parent::setUp('image_module_test');
+ }
+
+ /**
+ * Test styled image dimensions cumulatively.
+ */
+ function testImageDimensions() {
+ // Create a working copy of the file.
+ $files = $this->drupalGetTestFiles('image');
+ $file = reset($files);
+ $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
+
+ // Create a style.
+ $style = image_style_save(array('name' => 'test', 'label' => 'Test'));
+ $generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
+ $url = image_style_url('test', $original_uri);
+
+ $variables = array(
+ 'style_name' => 'test',
+ 'path' => $original_uri,
+ 'width' => 40,
+ 'height' => 20,
+ );
+
+ // Scale an image that is wider than it is high.
+ $effect = array(
+ 'name' => 'image_scale',
+ 'data' => array(
+ 'width' => 120,
+ 'height' => 90,
+ 'upscale' => TRUE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="120" height="60" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 120, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 60, 'Expected height was found.');
+
+ // Rotate 90 degrees anticlockwise.
+ $effect = array(
+ 'name' => 'image_rotate',
+ 'data' => array(
+ 'degrees' => -90,
+ 'random' => FALSE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="60" height="120" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 60, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 120, 'Expected height was found.');
+
+ // Scale an image that is higher than it is wide (rotated by previous effect).
+ $effect = array(
+ 'name' => 'image_scale',
+ 'data' => array(
+ 'width' => 120,
+ 'height' => 90,
+ 'upscale' => TRUE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
+
+ // Test upscale disabled.
+ $effect = array(
+ 'name' => 'image_scale',
+ 'data' => array(
+ 'width' => 400,
+ 'height' => 200,
+ 'upscale' => FALSE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
+
+ // Add a desaturate effect.
+ $effect = array(
+ 'name' => 'image_desaturate',
+ 'data' => array(),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="45" height="90" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 45, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 90, 'Expected height was found.');
+
+ // Add a random rotate effect.
+ $effect = array(
+ 'name' => 'image_rotate',
+ 'data' => array(
+ 'degrees' => 180,
+ 'random' => TRUE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+
+
+ // Add a crop effect.
+ $effect = array(
+ 'name' => 'image_crop',
+ 'data' => array(
+ 'width' => 30,
+ 'height' => 30,
+ 'anchor' => 'center-center',
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" width="30" height="30" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+ $image_info = image_get_info($generated_uri);
+ $this->assertEqual($image_info['width'], 30, 'Expected width was found.');
+ $this->assertEqual($image_info['height'], 30, 'Expected height was found.');
+
+ // Rotate to a non-multiple of 90 degrees.
+ $effect = array(
+ 'name' => 'image_rotate',
+ 'data' => array(
+ 'degrees' => 57,
+ 'random' => FALSE,
+ ),
+ 'isid' => $style['isid'],
+ );
+
+ $effect = image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
+ $this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
+ $this->drupalGet($url);
+ $this->assertResponse(200, 'Image was generated at the URL.');
+ $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
+
+ image_effect_delete($effect);
+
+ // Ensure that an effect with no dimensions callback unsets the dimensions.
+ // This ensures compatibility with 7.0 contrib modules.
+ $effect = array(
+ 'name' => 'image_module_test_null',
+ 'data' => array(),
+ 'isid' => $style['isid'],
+ );
+
+ image_effect_save($effect);
+ $img_tag = theme_image_style($variables);
+ $this->assertEqual($img_tag, '<img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" />', 'Expected img tag was found.');
+ }
+}
+
+/**
+ * Tests image_dimensions_scale().
+ */
+class ImageDimensionsScaleTestCase extends DrupalUnitTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'image_dimensions_scale()',
+ 'description' => 'Tests all control flow branches in image_dimensions_scale().',
+ 'group' => 'Image',
+ );
+ }
+
+ /**
+ * Tests all control flow branches in image_dimensions_scale().
+ */
+ function testImageDimensionsScale() {
+ // Define input / output datasets to test different branch conditions.
+ $test = array();
+
+ // Test branch conditions:
+ // - No height.
+ // - Upscale, don't need to upscale.
+ $tests[] = array(
+ 'input' => array(
+ 'dimensions' => array(
+ 'width' => 1000,
+ 'height' => 2000,
+ ),
+ 'width' => 200,
+ 'height' => NULL,
+ 'upscale' => TRUE,
+ ),
+ 'output' => array(
+ 'dimensions' => array(
+ 'width' => 200,
+ 'height' => 400,
+ ),
+ 'return_value' => TRUE,
+ ),
+ );
+
+ // Test branch conditions:
+ // - No width.
+ // - Don't upscale, don't need to upscale.
+ $tests[] = array(
+ 'input' => array(
+ 'dimensions' => array(
+ 'width' => 1000,
+ 'height' => 800,
+ ),
+ 'width' => NULL,
+ 'height' => 140,
+ 'upscale' => FALSE,
+ ),
+ 'output' => array(
+ 'dimensions' => array(
+ 'width' => 175,
+ 'height' => 140,
+ ),
+ 'return_value' => TRUE,
+ ),
+ );
+
+ // Test branch conditions:
+ // - Source aspect ratio greater than target.
+ // - Upscale, need to upscale.
+ $tests[] = array(
+ 'input' => array(
+ 'dimensions' => array(
+ 'width' => 8,
+ 'height' => 20,
+ ),
+ 'width' => 200,
+ 'height' => 140,
+ 'upscale' => TRUE,
+ ),
+ 'output' => array(
+ 'dimensions' => array(
+ 'width' => 56,
+ 'height' => 140,
+ ),
+ 'return_value' => TRUE,
+ ),
+ );
+
+ // Test branch condition: target aspect ratio greater than source.
+ $tests[] = array(
+ 'input' => array(
+ 'dimensions' => array(
+ 'width' => 2000,
+ 'height' => 800,
+ ),
+ 'width' => 200,
+ 'height' => 140,
+ 'upscale' => FALSE,
+ ),
+ 'output' => array(
+ 'dimensions' => array(
+ 'width' => 200,
+ 'height' => 80,
+ ),
+ 'return_value' => TRUE,
+ ),
+ );
+
+ // Test branch condition: don't upscale, need to upscale.
+ $tests[] = array(
+ 'input' => array(
+ 'dimensions' => array(
+ 'width' => 100,
+ 'height' => 50,
+ ),
+ 'width' => 200,
+ 'height' => 140,
+ 'upscale' => FALSE,
+ ),
+ 'output' => array(
+ 'dimensions' => array(
+ 'width' => 100,
+ 'height' => 50,
+ ),
+ 'return_value' => FALSE,
+ ),
+ );
+
+ foreach ($tests as $test) {
+ // Process the test dataset.
+ $return_value = image_dimensions_scale($test['input']['dimensions'], $test['input']['width'], $test['input']['height'], $test['input']['upscale']);
+
+ // Check the width.
+ $this->assertEqual($test['output']['dimensions']['width'], $test['input']['dimensions']['width'], format_string('Computed width (@computed_width) equals expected width (@expected_width)', array('@computed_width' => $test['output']['dimensions']['width'], '@expected_width' => $test['input']['dimensions']['width'])));
+
+ // Check the height.
+ $this->assertEqual($test['output']['dimensions']['height'], $test['input']['dimensions']['height'], format_string('Computed height (@computed_height) equals expected height (@expected_height)', array('@computed_height' => $test['output']['dimensions']['height'], '@expected_height' => $test['input']['dimensions']['height'])));
+
+ // Check the return value.
+ $this->assertEqual($test['output']['return_value'], $return_value, 'Correct return value.');
+ }
+ }
+}
+
+/**
+ * Tests default image settings.
+ */
+class ImageFieldDefaultImagesTestCase extends ImageFieldTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image field default images tests',
+ 'description' => 'Tests setting up default images both to the field and field instance.',
+ 'group' => 'Image',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('field_ui'));
+ }
+
+ /**
+ * Tests CRUD for fields and fields instances with default images.
+ */
+ function testDefaultImages() {
+ // Create files to use as the default images.
+ $files = $this->drupalGetTestFiles('image');
+ $default_images = array();
+ foreach (array('field', 'instance', 'instance2', 'field_new', 'instance_new') as $image_target) {
+ $file = array_pop($files);
+ $file = file_save($file);
+ $default_images[$image_target] = $file;
+ }
+
+ // Create an image field and add an instance to the article content type.
+ $field_name = strtolower($this->randomName());
+ $field_settings = array(
+ 'default_image' => $default_images['field']->fid,
+ );
+ $instance_settings = array(
+ 'default_image' => $default_images['instance']->fid,
+ );
+ $widget_settings = array(
+ 'preview_image_style' => 'medium',
+ );
+ $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings);
+ $field = field_info_field($field_name);
+ $instance = field_info_instance('node', $field_name, 'article');
+
+ // Add another instance with another default image to the page content type.
+ $instance2 = array_merge($instance, array(
+ 'bundle' => 'page',
+ 'settings' => array(
+ 'default_image' => $default_images['instance2']->fid,
+ ),
+ ));
+ field_create_instance($instance2);
+ $instance2 = field_info_instance('node', $field_name, 'page');
+
+
+ // Confirm the defaults are present on the article field admin form.
+ $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
+ $this->assertFieldByXpath(
+ '//input[@name="field[settings][default_image][fid]"]',
+ $default_images['field']->fid,
+ format_string(
+ 'Article image field default equals expected file ID of @fid.',
+ array('@fid' => $default_images['field']->fid)
+ )
+ );
+ $this->assertFieldByXpath(
+ '//input[@name="instance[settings][default_image][fid]"]',
+ $default_images['instance']->fid,
+ format_string(
+ 'Article image field instance default equals expected file ID of @fid.',
+ array('@fid' => $default_images['instance']->fid)
+ )
+ );
+
+ // Confirm the defaults are present on the page field admin form.
+ $this->drupalGet("admin/structure/types/manage/page/fields/$field_name");
+ $this->assertFieldByXpath(
+ '//input[@name="field[settings][default_image][fid]"]',
+ $default_images['field']->fid,
+ format_string(
+ 'Page image field default equals expected file ID of @fid.',
+ array('@fid' => $default_images['field']->fid)
+ )
+ );
+ $this->assertFieldByXpath(
+ '//input[@name="instance[settings][default_image][fid]"]',
+ $default_images['instance2']->fid,
+ format_string(
+ 'Page image field instance default equals expected file ID of @fid.',
+ array('@fid' => $default_images['instance2']->fid)
+ )
+ );
+
+ // Confirm that the image default is shown for a new article node.
+ $article = $this->drupalCreateNode(array('type' => 'article'));
+ $article_built = node_view($article);
+ $this->assertEqual(
+ $article_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance']->fid,
+ format_string(
+ 'A new article node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance']->fid)
+ )
+ );
+
+ // Confirm that the image default is shown for a new page node.
+ $page = $this->drupalCreateNode(array('type' => 'page'));
+ $page_built = node_view($page);
+ $this->assertEqual(
+ $page_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance2']->fid,
+ format_string(
+ 'A new page node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance2']->fid)
+ )
+ );
+
+ // Upload a new default for the field.
+ $field['settings']['default_image'] = $default_images['field_new']->fid;
+ field_update_field($field);
+
+ // Confirm that the new field default is used on the article admin form.
+ $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
+ $this->assertFieldByXpath(
+ '//input[@name="field[settings][default_image][fid]"]',
+ $default_images['field_new']->fid,
+ format_string(
+ 'Updated image field default equals expected file ID of @fid.',
+ array('@fid' => $default_images['field_new']->fid)
+ )
+ );
+
+ // Reload the nodes and confirm the field instance defaults are used.
+ $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
+ $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
+ $this->assertEqual(
+ $article_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance']->fid,
+ format_string(
+ 'An existing article node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance']->fid)
+ )
+ );
+ $this->assertEqual(
+ $page_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance2']->fid,
+ format_string(
+ 'An existing page node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance2']->fid)
+ )
+ );
+
+ // Upload a new default for the article's field instance.
+ $instance['settings']['default_image'] = $default_images['instance_new']->fid;
+ field_update_instance($instance);
+
+ // Confirm the new field instance default is used on the article field
+ // admin form.
+ $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
+ $this->assertFieldByXpath(
+ '//input[@name="instance[settings][default_image][fid]"]',
+ $default_images['instance_new']->fid,
+ format_string(
+ 'Updated article image field instance default equals expected file ID of @fid.',
+ array('@fid' => $default_images['instance_new']->fid)
+ )
+ );
+
+ // Reload the nodes.
+ $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
+ $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
+
+ // Confirm the article uses the new default.
+ $this->assertEqual(
+ $article_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance_new']->fid,
+ format_string(
+ 'An existing article node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance_new']->fid)
+ )
+ );
+ // Confirm the page remains unchanged.
+ $this->assertEqual(
+ $page_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance2']->fid,
+ format_string(
+ 'An existing page node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance2']->fid)
+ )
+ );
+
+ // Remove the instance default from articles.
+ $instance['settings']['default_image'] = NULL;
+ field_update_instance($instance);
+
+ // Confirm the article field instance default has been removed.
+ $this->drupalGet("admin/structure/types/manage/article/fields/$field_name");
+ $this->assertFieldByXpath(
+ '//input[@name="instance[settings][default_image][fid]"]',
+ '',
+ 'Updated article image field instance default has been successfully removed.'
+ );
+
+ // Reload the nodes.
+ $article_built = node_view($article = node_load($article->nid, NULL, $reset = TRUE));
+ $page_built = node_view($page = node_load($page->nid, NULL, $reset = TRUE));
+ // Confirm the article uses the new field (not instance) default.
+ $this->assertEqual(
+ $article_built[$field_name]['#items'][0]['fid'],
+ $default_images['field_new']->fid,
+ format_string(
+ 'An existing article node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['field_new']->fid)
+ )
+ );
+ // Confirm the page remains unchanged.
+ $this->assertEqual(
+ $page_built[$field_name]['#items'][0]['fid'],
+ $default_images['instance2']->fid,
+ format_string(
+ 'An existing page node without an image has the expected default image file ID of @fid.',
+ array('@fid' => $default_images['instance2']->fid)
+ )
+ );
+ }
+
+}
+
+/**
+ * Tests image theme functions.
+ */
+class ImageThemeFunctionWebTestCase extends DrupalWebTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image theme functions',
+ 'description' => 'Test that the image theme functions work correctly.',
+ 'group' => 'Image',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('image'));
+ }
+
+ /**
+ * Tests usage of the image field formatters.
+ */
+ function testImageFormatterTheme() {
+ // Create an image.
+ $files = $this->drupalGetTestFiles('image');
+ $file = reset($files);
+ $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
+
+ // Create a style.
+ image_style_save(array('name' => 'test', 'label' => 'Test'));
+ $url = image_style_url('test', $original_uri);
+
+ // Test using theme_image_formatter() without an image title, alt text, or
+ // link options.
+ $path = $this->randomName();
+ $element = array(
+ '#theme' => 'image_formatter',
+ '#image_style' => 'test',
+ '#item' => array(
+ 'uri' => $original_uri,
+ ),
+ '#path' => array(
+ 'path' => $path,
+ ),
+ );
+ $rendered_element = render($element);
+ $expected_result = '<a href="' . url($path) . '"><img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" /></a>';
+ $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders without title, alt, or path options.');
+
+ // Link the image to a fragment on the page, and not a full URL.
+ $fragment = $this->randomName();
+ $element['#path']['path'] = '';
+ $element['#path']['options'] = array(
+ 'external' => TRUE,
+ 'fragment' => $fragment,
+ );
+ $rendered_element = render($element);
+ $expected_result = '<a href="#' . $fragment . '"><img typeof="foaf:Image" src="' . check_plain($url) . '" alt="" /></a>';
+ $this->assertEqual($expected_result, $rendered_element, 'theme_image_formatter() correctly renders a link fragment.');
+ }
+
+}
+
+/**
+ * Tests flushing of image styles.
+ */
+class ImageStyleFlushTest extends ImageFieldTestCase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => 'Image style flushing',
+ 'description' => 'Tests flushing of image styles.',
+ 'group' => 'Image',
+ );
+ }
+
+ /**
+ * Given an image style and a wrapper, generate an image.
+ */
+ function createSampleImage($style, $wrapper) {
+ static $file;
+
+ if (!isset($file)) {
+ $files = $this->drupalGetTestFiles('image');
+ $file = reset($files);
+ }
+
+ // Make sure we have an image in our wrapper testing file directory.
+ $source_uri = file_unmanaged_copy($file->uri, $wrapper . '://');
+ // Build the derivative image.
+ $derivative_uri = image_style_path($style['name'], $source_uri);
+ $derivative = image_style_create_derivative($style, $source_uri, $derivative_uri);
+
+ return $derivative ? $derivative_uri : FALSE;
+ }
+
+ /**
+ * Count the number of images currently created for a style in a wrapper.
+ */
+ function getImageCount($style, $wrapper) {
+ return count(file_scan_directory($wrapper . '://styles/' . $style['name'], '/.*/'));
+ }
+
+ /**
+ * General test to flush a style.
+ */
+ function testFlush() {
+
+ // Setup a style to be created and effects to add to it.
+ $style_name = strtolower($this->randomName(10));
+ $style_label = $this->randomString();
+ $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
+ $effect_edits = array(
+ 'image_resize' => array(
+ 'data[width]' => 100,
+ 'data[height]' => 101,
+ ),
+ 'image_scale' => array(
+ 'data[width]' => 110,
+ 'data[height]' => 111,
+ 'data[upscale]' => 1,
+ ),
+ );
+
+ // Add style form.
+ $edit = array(
+ 'name' => $style_name,
+ 'label' => $style_label,
+ );
+ $this->drupalPost('admin/config/media/image-styles/add', $edit, t('Create new style'));
+ // Add each sample effect to the style.
+ foreach ($effect_edits as $effect => $edit) {
+ // Add the effect.
+ $this->drupalPost($style_path, array('new' => $effect), t('Add'));
+ if (!empty($edit)) {
+ $this->drupalPost(NULL, $edit, t('Add effect'));
+ }
+ }
+
+ // Load the saved image style.
+ $style = image_style_load($style_name);
+
+ // Create an image for the 'public' wrapper.
+ $image_path = $this->createSampleImage($style, 'public');
+ // Expecting to find 2 images, one is the sample.png image shown in
+ // image style preview.
+ $this->assertEqual($this->getImageCount($style, 'public'), 2, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
+
+ // Create an image for the 'private' wrapper.
+ $image_path = $this->createSampleImage($style, 'private');
+ $this->assertEqual($this->getImageCount($style, 'private'), 1, format_string('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%file' => $image_path)));
+
+ // Remove the 'image_scale' effect and updates the style, which in turn
+ // forces an image style flush.
+ $effect = array_pop($style['effects']);
+ $this->drupalPost($style_path . '/effects/' . $effect['ieid'] . '/delete', array(), t('Delete'));
+ $this->assertResponse(200);
+ $this->drupalPost($style_path, array(), t('Update style'));
+ $this->assertResponse(200);
+
+ // Post flush, expected 1 image in the 'public' wrapper (sample.png).
+ $this->assertEqual($this->getImageCount($style, 'public'), 1, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style['name'], '%wrapper' => 'public')));
+
+ // Post flush, expected no image in the 'private' wrapper.
+ $this->assertEqual($this->getImageCount($style, 'private'), 0, format_string('Image style %style flushed correctly for %wrapper wrapper.', array('%style' => $style['name'], '%wrapper' => 'private')));
+ }
+}
diff --git a/kolab.org/www/drupal-7.26/modules/image/sample.png b/kolab.org/www/drupal-7.26/modules/image/sample.png
new file mode 100644
index 0000000..f22e0df
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/sample.png
Binary files differ
diff --git a/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.info b/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.info
new file mode 100644
index 0000000..7bb35f5
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.info
@@ -0,0 +1,13 @@
+name = Image test
+description = Provides hook implementations for testing Image module functionality.
+package = Core
+version = VERSION
+core = 7.x
+files[] = image_module_test.module
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2014-01-15
+version = "7.26"
+project = "drupal"
+datestamp = "1389815930"
+
diff --git a/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.module b/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.module
new file mode 100644
index 0000000..8a322fb
--- /dev/null
+++ b/kolab.org/www/drupal-7.26/modules/image/tests/image_module_test.module
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Provides Image module hook implementations for testing purposes.
+ */
+
+function image_module_test_file_download($uri) {
+ if (variable_get('image_module_test_file_download', FALSE) == $uri) {
+ return array('X-Image-Owned-By' => 'image_module_test');
+ }
+}
+
+/**
+ * Implements hook_image_effect_info().
+ */
+function image_module_test_image_effect_info() {
+ $effects = array(
+ 'image_module_test_null' => array(
+ 'effect callback' => 'image_module_test_null_effect',
+ ),
+ );
+
+ return $effects;
+}
+
+/**
+ * Image effect callback; Null.
+ *
+ * @param $image
+ * An image object returned by image_load().
+ * @param $data
+ * An array with no attributes.
+ *
+ * @return
+ * TRUE
+ */
+function image_module_test_null_effect(array &$image, array $data) {
+ return TRUE;
+}
+
+/**
+ * Implements hook_image_effect_info_alter().
+ *
+ * Used to keep a count of cache misses in image_effect_definitions().
+ */
+function image_module_test_image_effect_info_alter(&$effects) {
+ $image_effects_definition_called = &drupal_static(__FUNCTION__, 0);
+ $image_effects_definition_called++;
+}