Commit 2da6a0ed authored by webchick's avatar webchick

#371374 by quicksketch, drewish, eojthebrave, and dopry: ImageCache UI in...

#371374 by quicksketch, drewish, eojthebrave, and dopry: ImageCache UI in core. Hell yeah! :D Resizable, scalable, croppable, grey-scalable, rotatey images for all.
parent 6199ae64
......@@ -103,6 +103,11 @@ Drupal 7.0, xxxx-xx-xx (development version)
uploading a site logo--that don't require the overhead of databases and
hooks, the current unmanaged copy, move and delete operations have been
preserved but renamed to file_unmanaged_*().
- Image handling:
* Improved image handling, including better support for add-on image
libraries.
* Added API and interface for creating advanced image thumbnails.
* Inclusion of additional effects such as rotate and desaturate.
- Added aliased multi-site support:
* Added support for mapping domain names to sites directories.
- Added RDF support:
......
/* $Id$ */
/**
* 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;
}
This diff is collapsed.
......@@ -21,18 +21,24 @@
* 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:
* - "name": The human-readable name of the effect.
* - "effect callback": The function to call to perform this effect.
* - "label": The human-readable name of the effect.
* - "effect callback": The function to call to perform this image effect.
* - "help": (optional) A brief description of the effect that will be shown
* when adding or configuring this effect.
* 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.
*/
function hook_image_effect_info() {
$effects = array();
$effects['mymodule_resize'] = array(
'name' => t('Resize'),
'label' => t('Resize'),
'help' => t('Resize an image to an exact set of dimensions, ignoring aspect ratio.'),
'effect callback' => 'mymodule_resize_image',
'form callback' => 'mymodule_resize_form',
'summary theme' => 'mymodule_resize_summary',
);
return $effects;
......
......@@ -12,34 +12,44 @@
function image_image_effect_info() {
$effects = array(
'image_resize' => array(
'name' => t('Resize'),
'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',
'form callback' => 'image_resize_form',
'summary theme' => 'image_resize_summary',
),
'image_scale' => array(
'name' => t('Scale'),
'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',
'form callback' => 'image_scale_form',
'summary theme' => 'image_scale_summary',
),
'image_scale_and_crop' => array(
'name' => t('Scale and Crop'),
'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',
'form callback' => 'image_resize_form',
'summary theme' => 'image_resize_summary',
),
'image_crop' => array(
'name' => t('Crop'),
'label' => t('Crop'),
'help' => t('Cropping will remove portions of an image to make it the specified dimensions.'),
'effect callback' => 'image_crop_effect',
'form callback' => 'image_crop_form',
'summary theme' => 'image_crop_summary',
),
'image_desaturate' => array(
'name' => t('Desaturate'),
'label' => t('Desaturate'),
'help' => t('Desaturate converts an image to grayscale.'),
'effect callback' => 'image_desaturate_effect',
),
'image_rotate' => array(
'name' => t('Rotate'),
'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',
'form callback' => 'image_rotate_form',
'summary theme' => 'image_rotate_summary',
),
);
......
......@@ -5,6 +5,7 @@ package = Core
version = VERSION
core = 7.x
files[] = image.module
files[] = image.admin.inc
files[] = image.effects.inc
files[] = image.install
files[] = image.test
This diff is collapsed.
......@@ -136,10 +136,10 @@ class ImageEffectsUnitTest extends ImageToolkitTestCase {
*/
function testEffects() {
$effects = image_effects();
$this->assertEqual(count($effects), 1, t("Found core's effect."));
$this->assertEqual(count($effects), 1, t("Found core's image effect."));
$effect_definitions = image_effect_definitions();
$this->assertEqual(count($effect_definitions), 6, t("Found core's effects."));
$this->assertEqual(count($effect_definitions), 6, t("Found core's image effects."));
}
/**
......@@ -226,3 +226,203 @@ class ImageEffectsUnitTest extends ImageToolkitTestCase {
$this->assertEqual($calls['rotate'][0][2], 0xffffff, t('Background color was passed correctly'));
}
}
/**
* Tests creation, deletion, and editing of image styles and effects.
*/
class ImageAdminStylesUnitTest extends DrupalWebTestCase {
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',
);
}
/**
* Implementation of setUp().
*/
function setUp() {
parent::setUp();
// Create an administrative user.
$this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer image styles'));
$this->drupalLogin($this->admin_user);
}
/**
* 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)) {
$file = reset($this->drupalGetTestFiles('image'));
$file_path = file_unmanaged_copy($file->filename);
}
return image_style_url($style['name'], $file_path) ? $file_path : FALSE;
}
/**
* Count the number of images currently create for a style.
*/
function getImageCount($style) {
$directory = file_directory_path() . '/styles/' . $style['name'];
return count(file_scan_directory($directory, '/.*/'));
}
/**
* 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_path = 'admin/settings/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,
);
$this->drupalPost('admin/settings/image-styles/add', $edit, t('Create new style'));
$this->assertRaw(t('Style %name was created.', array('%name' => $style_name)), t('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.
$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, t('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, t('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));
$weight = count($effect_edits);
$edit = array(
'name' => $style_name,
);
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, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%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/settings/image-styles/edit/' . $style_name;
// Check that the URL was updated.
$this->drupalGet($style_path);
$this->assertResponse(200, t('Image style %original renamed to %new', array('%original' => $style['name'], '%new' => $style_name)));
// 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, t('Image style %style was flushed after renaming the style and updating the order of effects.', array('%style' => $style['name'])));
// 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, t('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, t('Image style %style image %file successfully generated.', array('%style' => $style['name'], '%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'])), t('Image effect deleted.'));
// Style deletion form.
// Delete the style.
$this->drupalPost('admin/settings/image-styles/delete/' . $style_name, array(), t('Delete'));
// Confirm the style directory has been removed.
$directory = file_directory_path() . '/styles/' . $style_name;
$this->assertFalse(is_dir($directory), t('Image style %style directory removed on style deletion.', array('%style' => $style['name'])));
drupal_static_reset('image_styles');
$this->assertFalse(image_style_load($style_name), t('Image style %style successfully deleted.', array('%style' => $style['name'])));
}
}
......@@ -363,26 +363,29 @@ function user_admin_settings() {
if (module_exists('image')) {
$form['personalization']['pictures']['settings']['user_picture_style'] = array(
'#type' => 'select',
'#title' => t('Picture style'),
'#title' => t('Picture display style'),
'#options' => image_style_options(TRUE),
'#default_value' => variable_get('user_picture_style', ''),
'#description' => t('The style selected will be used on display, while the original image is retained. Styles may be configured in the <a href="!url">Image styles</a> administration area.', array('!url' => url('admin/settings/image-styles'))),
);
}
$form['personalization']['pictures']['user_picture_dimensions'] = array(
'#type' => 'textfield',
'#title' => t('Picture maximum dimensions'),
'#title' => t('Picture upload dimensions'),
'#default_value' => variable_get('user_picture_dimensions', '85x85'),
'#size' => 15,
'#size' => 10,
'#maxlength' => 10,
'#description' => t('Maximum dimensions for pictures, in pixels.'),
'#field_suffix' => ' ' . t('pixels'),
'#description' => t('Maximum allowed dimensions for uploaded pictures.'),
);
$form['personalization']['pictures']['user_picture_file_size'] = array(
'#type' => 'textfield',
'#title' => t('Picture maximum file size'),
'#title' => t('Picture upload file size'),
'#default_value' => variable_get('user_picture_file_size', '30'),
'#size' => 15,
'#size' => 10,
'#maxlength' => 10,
'#description' => t('Maximum file size for pictures, in kB.'),
'#field_suffix' => ' ' . t('KB'),
'#description' => t('Maximum allowed file size for uploaded pictures.'),
);
$form['personalization']['pictures']['user_picture_guidelines'] = array(
'#type' => 'textarea',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment