View source
<?php
include_once 'imagecache_testsuite.features.inc';
function imagecache_testsuite_menu() {
$items = array();
$items['admin/config/media/image-styles/testsuite'] = array(
'title' => 'Test Suite',
'page callback' => 'imagecache_testsuite_page',
'access arguments' => array(
'administer image styles',
),
'type' => MENU_LOCAL_TASK,
'weight' => 10,
);
$items['admin/config/media/image-styles/testsuite/%/%'] = array(
'title' => 'Test Suite Image',
'page callback' => 'imagecache_testsuite_generate',
'page arguments' => array(
5,
6,
),
'access arguments' => array(
'administer image styles',
),
'type' => MENU_CALLBACK,
);
$items['admin/config/media/image-styles/testsuite/positioning_test'] = array(
'title' => 'Positioning Test',
'page callback' => 'imagecache_testsuite_positioning',
'access arguments' => array(
'administer image styles',
),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function imagecache_testsuite_help($path) {
switch ($path) {
case 'admin/build/imagecache/test':
$output = file_get_contents(drupal_get_path('module', 'imagecache_testsuite') . "/README.txt");
return _filter_autop($output);
break;
case 'admin/config/media/image-styles/testsuite':
return t("<p>\n This page displays a number of examples of image effects.\n Illustrated are both the expected result and the actual result.\n </p><p>\n This page is just for debugging to confirm that this behavior doesn't\n change as the code gets updated.\n If the two illustrations do not match, there is probably something\n that needs fixing.\n </p><p>\n More actions are provided by each of the imagecache actions submodules\n and will be shown as you enable them.\n </p>");
break;
case 'admin/config/media/image-styles':
return t('
A number of styles here are provided by the Imagecache
Testsuite module as examples.
Disable this module to make them go away.
');
break;
}
return '';
}
function imagecache_testsuite_page() {
module_load_include('inc', 'image', 'image.admin');
module_load_include('inc', 'image', 'image.effects');
$tests = array_merge(image_styles(), imagecache_testsuite_get_tests());
$toolkits = image_get_available_toolkits();
$sample_folders = imagecache_testsuite_get_folders();
$test_table = array();
foreach ($tests as $style_name => $style) {
image_style_flush($style);
$row = array();
$row_class = 'test';
$details_list = array();
foreach ($style['effects'] as $effect) {
if (!isset($effect['name'])) {
watchdog('imagecache_testsuite', 'invalid testcase within %style_name. No effect name', array(
'%style_name' => $style_name,
), WATCHDOG_ERROR);
$details_list[] = '<div>Unidentified effect</div>';
$row_class = 'error';
continue;
}
$effect_definition = image_effect_definition_load($effect['name']);
if (function_exists($effect_definition['effect callback'])) {
$description = "<strong>{$effect_definition['label']}</strong> ";
$description .= isset($effect_definition['summary theme']) ? theme($effect_definition['summary theme'], array(
'data' => $effect['data'],
)) : '';
$details_list[] = "<div>{$description}</div>";
}
else {
$strings = array(
'%action' => $effect['name'],
'%module' => $effect['module'],
);
$details_list[$effect['name']] = t("<div><b>%action unavailable</b>. Please enable %module module.</div>", $strings);
$row_class = 'error';
}
}
$row['details'] = "<h3>{$style['name']}</h3><p>" . implode($details_list) . "</p>";
foreach ($sample_folders as $sample_folder) {
if (file_exists("{$sample_folder}/{$style_name}.png")) {
$style['sample'] = "{$sample_folder}/{$style_name}.png";
}
elseif (file_exists("{$sample_folder}/{$style_name}.jpg")) {
$style['sample'] = "{$sample_folder}/{$style_name}.jpg";
}
}
if (isset($style['sample']) && file_exists($style['sample'])) {
$sample_img = theme('image', array(
'path' => $style['sample'],
));
if (!is_readable($style['sample'])) {
$sample_img = "FILE UNREADABLE: {$style['sample']}";
}
}
else {
$sample_img = "[no sample]";
}
$row['sample'] = $sample_img;
foreach ($toolkits as $toolkit => $toolkit_info) {
$test_url = "admin/config/media/image-styles/testsuite/{$style_name}/{$toolkit}";
$test_img = theme('image', array(
'path' => $test_url,
'alt' => "{$style_name}/{$toolkit}",
));
$row[$toolkit] = l($test_img, $test_url, array(
'html' => TRUE,
));
}
$test_table[$style_name] = array(
'data' => $row,
'class' => array(
$row_class,
),
);
}
$header = array_merge(array(
'test',
'sample',
), array_keys($toolkits));
$output = theme('table', array(
'header' => $header,
'rows' => $test_table,
'id' => 'imagecache-testsuite',
));
drupal_add_html_head('<style type="text/css" >#imagecache-testsuite tr.even{background-color:#EEEEEE !important;} #imagecache-testsuite td{vertical-align:top;} #imagecache-testsuite tr.error{background-color:#FFCCCC !important;}</style>');
return $output;
}
function imagecache_testsuite_generate($test_id = '', $toolkit = '') {
module_load_include('inc', 'image', 'image.admin');
module_load_include('inc', 'image', 'image.effects');
if (empty($toolkit)) {
$toolkit = image_get_toolkit();
}
else {
global $conf;
$conf['image_toolkit'] = $toolkit;
if ($toolkit === 'gd') {
include_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'system') . '/' . 'image.gd.inc';
}
}
$target = 'module://imagecache_testsuite/sample.jpg';
$tests = array_merge(image_styles(), imagecache_testsuite_get_tests());
$style = $tests[$test_id];
if (!$style) {
trigger_error("Unknown test style preset '{$test_id}' ", E_USER_ERROR);
return FALSE;
}
if (!($image = image_load($target, $toolkit))) {
trigger_error("Failed to open original image {$target} with toolkit {$toolkit}", E_USER_ERROR);
return FALSE;
}
$filename = "{$test_id}-{$toolkit}.{$image->info['extension']}";
$derivative_uri = image_style_path($style['name'], $filename);
$directory = dirname($derivative_uri);
file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
watchdog('imagecache_testsuite', 'Checking a save dir %dir', array(
'%dir' => dirname($derivative_uri),
), WATCHDOG_DEBUG);
foreach ($style['effects'] as $effect) {
$effect_definition = image_effect_definition_load($effect['name']);
if (empty($effect_definition)) {
watchdog('imagecache_testsuite', 'I have no idea what %name is', array(
'%name' => $effect['name'],
), WATCHDOG_ERROR);
continue;
}
$full_effect = array_merge($effect_definition, array(
'data' => $effect['data'],
));
if (!image_effect_apply($image, $full_effect)) {
watchdog('imagecache_testsuite', 'action: %action (%callback) failed for %src', array(
'%action' => $full_effect['label'],
'%src' => $target,
'%callback' => $full_effect['effect callback'],
), WATCHDOG_ERROR);
}
}
if (!image_save($image, $derivative_uri)) {
watchdog('imagecache_testsuite', 'saving image %label failed for %derivative_uri', array(
'%derivative_uri' => $derivative_uri,
'%label' => isset($style['label']) ? $style['label'] : $style['name'],
), WATCHDOG_ERROR);
return FALSE;
}
if ($result_image = image_load($derivative_uri)) {
file_transfer($result_image->source, array(
'Content-Type' => $result_image->info['mime_type'],
'Content-Length' => $result_image->info['file_size'],
));
drupal_exit();
}
return "Failed to load the expected result from {$derivative_uri}";
}
function imagecache_testsuite_image_default_styles() {
$styles = imagecache_testsuite_get_tests();
return $styles;
}
function imagecache_testsuite_get_tests() {
$presets = array();
$folders = imagecache_testsuite_get_folders();
foreach ($folders as $folder) {
$preset_files = file_scan_directory($folder, "/.*.imagecache_preset.inc/");
$filepath = $folder;
foreach ($preset_files as $preset_file) {
include_once $preset_file->uri;
}
}
uasort($presets, 'element_sort');
return $presets;
}
function imagecache_testsuite_get_folders() {
$folders = array(
drupal_get_path('module', 'imagecache_testsuite'),
);
foreach (module_implements('image_effect_info') as $module_name) {
$folders[] = drupal_get_path('module', $module_name) . '/tests';
}
return $folders;
}
function imagecache_testsuite_positioning() {
module_load_include('inc', 'imagecache_actions', 'utility');
drupal_set_title("Testing the positioning algorithm");
$tests = imagecache_testsuite_positioning_get_tests();
$table = array();
$src_image = new stdClass();
$src_image->info = array(
'width' => 75,
'height' => 100,
);
$dst_image = new stdClass();
$dst_image->info = array(
'width' => 200,
'height' => 150,
);
foreach ($tests as $testname => $test) {
if (isset($test['parameters']['x']) || isset($test['parameters']['y'])) {
$result['x'] = imagecache_actions_keyword_filter($test['parameters']['x'], $dst_image->info['width'], $src_image->info['width']);
$result['y'] = imagecache_actions_keyword_filter($test['parameters']['y'], $dst_image->info['height'], $src_image->info['height']);
}
else {
$result = imagecache_actions_calculate_relative_position($dst_image, $src_image, $test['parameters']);
}
$expected_illustration = theme_positioning_test($test['expected']['x'], $test['expected']['y']);
$result_illustration = theme_positioning_test($result['x'], $result['y']);
$row = array();
$row['name'] = array(
'data' => '<h3>' . $testname . '</h3>' . $test['description'],
);
$row['parameters'] = theme_positioning_parameters($test['parameters']);
$row['expected'] = theme_positioning_parameters($test['expected']);
$row['expected_image'] = $expected_illustration;
$row['result'] = theme_positioning_parameters($result);
$row['result_image'] = $result_illustration;
$table[] = $row;
}
return 'Result of test:' . theme('table', array(
'test',
'parameters',
'expected',
'image',
'result',
'actual image',
'status',
), $table);
}
function theme_positioning_test($x, $y) {
$inner = "<div style='background-color:red; width:75px; height:100px; position:absolute; left:{$x}px; top:{$y}px'>";
$outer = "<div style='background-color:blue; width:200px; height:150px; position:absolute; left:25px; top:25px'><div style='position:relative'>{$inner}</div></div>";
$wrapper = "<div style='background-color:#CCCCCC; width:250px; height:200px; position:relative'>{$outer}</div>";
return $wrapper;
}
function theme_positioning_parameters($parameters) {
$outputs = array();
foreach ($parameters as $key => $value) {
$outputs[] = "[{$key}] => {$value}";
}
return '<pre>' . join("\n", $outputs) . '</pre>';
}
function imagecache_testsuite_positioning_get_tests() {
return array(
'base' => array(
'parameters' => array(
'x' => '0',
'y' => '0',
),
'description' => '0 is top left.',
'expected' => array(
'x' => '0',
'y' => '0',
),
),
'numbers' => array(
'parameters' => array(
'x' => '50',
'y' => '-50',
),
'description' => 'Basic numbers indicate distance and direction from top left.',
'expected' => array(
'x' => '50',
'y' => '-50',
),
),
'keywords' => array(
'parameters' => array(
'x' => 'center',
'y' => 'bottom',
),
'description' => "Plain keywords will align against the region",
'expected' => array(
'x' => '62.5',
'y' => '50',
),
),
'keyword with offsets' => array(
'parameters' => array(
'x' => 'right+10',
'y' => 'bottom+10',
),
'description' => "Keywords can be used with offsets. Positive numbers are in from the named side",
'expected' => array(
'x' => '115',
'y' => '40',
),
),
'keyword with negative offsets' => array(
'parameters' => array(
'x' => 'right-10',
'y' => 'bottom-10',
),
'description' => "Negative numbers place the item outside the boundry",
'expected' => array(
'x' => '135',
'y' => '60',
),
),
'percent' => array(
'parameters' => array(
'x' => '50%',
'y' => '50%',
),
'description' => "Percentages on their own will CENTER on both the source and destination items",
'expected' => array(
'x' => '62.5',
'y' => '25',
),
),
'keyword with percent' => array(
'parameters' => array(
'x' => 'right+10%',
'y' => 'bottom+10%',
),
'description' => "Percentages can be used with keywords, though the placed image will be centered on the calculated position.",
'expected' => array(
'x' => '142.5',
'y' => '85',
),
),
'css styles' => array(
'parameters' => array(
'left' => '10px',
'bottom' => '10px',
),
'description' => "A different method uses css-like parameters.",
'expected' => array(
'x' => '10',
'y' => '40',
),
),
'css negatives' => array(
'parameters' => array(
'left' => '-10px',
'bottom' => '-10px',
),
'description' => "Negative numbers from sides always move outside of the boundries.",
'expected' => array(
'x' => '-10',
'y' => '60',
),
),
'css with percents' => array(
'parameters' => array(
'right' => '+10%',
'bottom' => '+10%',
),
'description' => "Using percents with sides calculates the percent location on the base, then centers the source item on that point.",
'expected' => array(
'x' => '142.5',
'y' => '85',
),
),
'css centering' => array(
'parameters' => array(
'right' => '50%',
'top' => '50%',
),
'description' => "The auto-centering that happens when percents are used means you can easily center things at 50%.",
'expected' => array(
'x' => '62.5',
'y' => '25',
),
),
'css positioning' => array(
'parameters' => array(
'right' => 'left+20',
'top' => 'bottom-20',
),
'description' => "It's also possible to use keywords there, though it's not smart to do so",
'expected' => array(
'x' => '-55',
'y' => '130',
),
),
);
}