updated i18n i10n_update workflwo imachecache_actions
This commit is contained in:
@@ -4,6 +4,45 @@ Imagecache Actions
|
||||
Imagecache Actions 7.x-1.x-dev
|
||||
------------------------------
|
||||
|
||||
Imagecache Actions 7.x-1.12
|
||||
---------------------------
|
||||
- [#3151871]: by DamienMcKenna: EXIF autorotate support for remote images.
|
||||
- [#3117901] by jacob.embree: Curly brace syntax for accessing array elements and
|
||||
string offsets has been deprecated in PHP 7.4.
|
||||
|
||||
Imagecache Actions 7.x-1.11
|
||||
---------------------------
|
||||
- [#3072639]: PDOException: SQLSTATE[HY000]: General error: 25 bind or column
|
||||
index out of range: INSERT INTO {menu_router}.
|
||||
|
||||
Imagecache Actions 7.x-1.10
|
||||
---------------------------
|
||||
- Use json for exporting image styles.
|
||||
- [#2988487] by AdamEvertsson: Minor spelling error.
|
||||
|
||||
Imagecache Actions 7.x-1.9
|
||||
--------------------------
|
||||
- [#2760121] by lebster, fietserwin: Add a "Perspective" effect.
|
||||
- [#2947014]: PHP 7.2 warning that each() has been deprecated.
|
||||
|
||||
Imagecache Actions 7.x-1.8
|
||||
--------------------------
|
||||
- [#2917097]: PHP 7.1 Warning "A non-numeric value encountered".
|
||||
- [#2905130] by bserem, fietserwin: Remove animation from moving images.
|
||||
- [#2888678] by das-peter: ImageMagick: Add support for invert effect.
|
||||
- [#1099300]: Notice: A non well formed numeric value encountered in
|
||||
image_gd_definecanvas() (line 381 of canvasactions.inc).
|
||||
- [#2719661] by SKAUGHT: Division by zero.
|
||||
- [#2717789]: Prevent exif_read_data() warnings.
|
||||
- Warning: Theme hook coloractions_invert_summary not found.
|
||||
- [#2696225] by mnlund, fietserwin: Add support for multiply color blending.
|
||||
- by fietserwin: image_styles_admin: sort image styles by label.
|
||||
- [#2039379]: Add some better examples for using custom actions.
|
||||
- Made more contextual information (image style and image effect) available in
|
||||
the custom action and text image effects.
|
||||
- [#2690337] by Ajithlal, fietserwin: Would like a feature for converting case
|
||||
in text effect.
|
||||
|
||||
Imagecache Actions 7.x-1.7
|
||||
--------------------------
|
||||
- [#2671526]: Fatal error on image style flush when image styles are defined in
|
||||
|
||||
+3
-4
@@ -5,9 +5,8 @@ core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+33
-3
@@ -129,7 +129,32 @@ function image_gd_imagecache_autorotate(stdClass $image) {
|
||||
watchdog('imagecache_actions', 'Image %file could not be auto-rotated: !message', array('%file' => $image->source, '!message' => t('The exif_read_data() function is not available in this PHP installation. You probably have to enable the exif extension.')));
|
||||
return FALSE;
|
||||
}
|
||||
$exif = exif_read_data(drupal_realpath($image->source));
|
||||
|
||||
// Read and check result.
|
||||
$path = drupal_realpath($image->source);
|
||||
if ($path) {
|
||||
$exif = @exif_read_data($path);
|
||||
}
|
||||
else {
|
||||
// drupal_realpath and exif fail for remote file systems like S3.
|
||||
// Copy to a local temporary folder and retry.
|
||||
$base = drupal_basename($image->source);
|
||||
$uniq = md5(microtime() . $image->source);
|
||||
$path = file_directory_temp() . '/' . $uniq . '-' . $base;
|
||||
file_unmanaged_copy($image->source, $path);
|
||||
$exif = @exif_read_data($path);
|
||||
|
||||
// Cleanup so we don't leave files behind.
|
||||
// The server would get them later on a reboot, but who knows when that
|
||||
// would be.
|
||||
file_unmanaged_delete($path);
|
||||
}
|
||||
|
||||
if ($exif === FALSE) {
|
||||
watchdog('imagecache_actions', 'Image %file could not be auto-rotated: !message', array('%file' => $image->source, '!message' => t('The exif_read_data() function returned FALSE.')));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (isset($exif['Orientation'])) {
|
||||
// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html:
|
||||
// 1 = Horizontal (normal)
|
||||
@@ -181,7 +206,7 @@ function image_imagemagick_imagecache_autorotate(stdClass $image) {
|
||||
// image when it should not, we only pass the auto-orient argument when the
|
||||
// exif extension could detect the 'Orientation' tag.
|
||||
if (function_exists('exif_read_data')) {
|
||||
$exif = exif_read_data(drupal_realpath($image->source));
|
||||
$exif = @exif_read_data(drupal_realpath($image->source));
|
||||
if (isset($exif['Orientation'])) {
|
||||
switch ($exif['Orientation']) {
|
||||
case 1:
|
||||
@@ -204,13 +229,18 @@ function image_imagemagick_imagecache_autorotate(stdClass $image) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
elseif ($exif === FALSE && $image->extension === 'jpg') {
|
||||
watchdog('imagecache_actions', 'Image %file could not be auto-rotated: !message', array('%file' => $image->source, '!message' => t('The exif_read_data() function returned FALSE.')));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We do add the auto-orient argument to IM. IM will determine itself
|
||||
// whether to rotate or not.
|
||||
$image->ops[] = '-auto-orient';
|
||||
// However we cannot keep track of the dimensions anymore.
|
||||
$image->info['width'] = $image->info['height'] = NULL;
|
||||
if ($image->info['width'] !== $image->info['height']) {
|
||||
$image->info['width'] = $image->info['height'] = NULL;;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+468
-24
@@ -269,6 +269,7 @@ function canvasactions_definecanvas_form(array $data) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
/** @noinspection PhpDocMissingThrowsInspection */
|
||||
/**
|
||||
* Implements theme_hook() for the define canvas effect summary.
|
||||
*
|
||||
@@ -295,6 +296,7 @@ function theme_canvasactions_definecanvas_summary(array $variables) {
|
||||
$output .= ' top:' . $data['relative']['topdiff'];
|
||||
$output .= ' bottom:' . $data['relative']['bottomdiff'];
|
||||
}
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$output .= theme('imagecacheactions_rgb', array('RGB' => $data['RGB']));
|
||||
$output .= ($data['under']) ? t(" <b>under</b> image ") : t(" <b>over</b> image ");
|
||||
return $output;
|
||||
@@ -320,19 +322,19 @@ function canvasactions_definecanvas_effect(stdClass $image, array $data) {
|
||||
$data['exact']['height'] = $image->info['height'];
|
||||
}
|
||||
|
||||
$targetsize['width'] = imagecache_actions_percent_filter($data['exact']['width'], $image->info['width']);
|
||||
$targetsize['height'] = imagecache_actions_percent_filter($data['exact']['height'], $image->info['height']);
|
||||
$target_size['width'] = imagecache_actions_percent_filter($data['exact']['width'], $image->info['width']);
|
||||
$target_size['height'] = imagecache_actions_percent_filter($data['exact']['height'], $image->info['height']);
|
||||
|
||||
$targetsize['left'] = image_filter_keyword($data['exact']['xpos'], $targetsize['width'], $image->info['width']);
|
||||
$targetsize['top'] = image_filter_keyword($data['exact']['ypos'], $targetsize['height'], $image->info['height']);
|
||||
$target_size['left'] = image_filter_keyword($data['exact']['xpos'], $target_size['width'], $image->info['width']);
|
||||
$target_size['top'] = image_filter_keyword($data['exact']['ypos'], $target_size['height'], $image->info['height']);
|
||||
|
||||
}
|
||||
else {
|
||||
// Calculate relative size.
|
||||
$targetsize['width'] = $image->info['width'] + $data['relative']['leftdiff'] + $data['relative']['rightdiff'];
|
||||
$targetsize['height'] = $image->info['height'] + $data['relative']['topdiff'] + $data['relative']['bottomdiff'];
|
||||
$targetsize['left'] = $data['relative']['leftdiff'];
|
||||
$targetsize['top'] = $data['relative']['topdiff'];
|
||||
$target_size['width'] = $image->info['width'] + ((int) $data['relative']['leftdiff']) + ((int) $data['relative']['rightdiff']);
|
||||
$target_size['height'] = $image->info['height'] + ((int) $data['relative']['topdiff']) + ((int) $data['relative']['bottomdiff']);
|
||||
$target_size['left'] = (int) $data['relative']['leftdiff'];
|
||||
$target_size['top'] = (int) $data['relative']['topdiff'];
|
||||
}
|
||||
|
||||
// Convert from hex (as it is stored in the UI).
|
||||
@@ -341,12 +343,12 @@ function canvasactions_definecanvas_effect(stdClass $image, array $data) {
|
||||
}
|
||||
|
||||
// All the math is done, now defer to the toolkit in use.
|
||||
$data['targetsize'] = $targetsize;
|
||||
$data['targetsize'] = $target_size;
|
||||
|
||||
$success = image_toolkit_invoke('definecanvas', $image, array($data));
|
||||
if ($success) {
|
||||
$image->info['width'] = $targetsize['width'];
|
||||
$image->info['height'] = $targetsize['height'];
|
||||
$image->info['width'] = $target_size['width'];
|
||||
$image->info['height'] = $target_size['height'];
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
@@ -363,10 +365,10 @@ function canvasactions_definecanvas_effect(stdClass $image, array $data) {
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_gd_definecanvas(stdClass $image, array $data) {
|
||||
$targetsize = $data['targetsize'];
|
||||
$target_size = $data['targetsize'];
|
||||
$RGB = $data['RGB'];
|
||||
|
||||
$newcanvas = imagecreatetruecolor($targetsize['width'], $targetsize['height']);
|
||||
$newcanvas = imagecreatetruecolor($target_size['width'], $target_size['height']);
|
||||
imagesavealpha($newcanvas, TRUE);
|
||||
imagealphablending($newcanvas, FALSE);
|
||||
imagesavealpha($image->resource, TRUE);
|
||||
@@ -378,19 +380,19 @@ function image_gd_definecanvas(stdClass $image, array $data) {
|
||||
// No color, attempt transparency, assume white.
|
||||
$background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127);
|
||||
}
|
||||
imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background);
|
||||
imagefilledrectangle($newcanvas, 0, 0, $target_size['width'], $target_size['height'], $background);
|
||||
|
||||
if ($data['under']) {
|
||||
$canvas_object = new stdClass();
|
||||
$canvas_object->resource = $newcanvas;
|
||||
$canvas_object->info = array(
|
||||
'width' => $targetsize['width'],
|
||||
'height' => $targetsize['height'],
|
||||
'width' => $target_size['width'],
|
||||
'height' => $target_size['height'],
|
||||
'mime_type' => $image->info['mime_type'],
|
||||
'extension' => $image->info['extension'],
|
||||
);
|
||||
$canvas_object->toolkit = $image->toolkit;
|
||||
image_overlay($image, $canvas_object, $targetsize['left'], $targetsize['top'], 100, TRUE);
|
||||
image_overlay($image, $canvas_object, $target_size['left'], $target_size['top'], 100, TRUE);
|
||||
}
|
||||
else {
|
||||
$image->resource = $newcanvas;
|
||||
@@ -421,10 +423,10 @@ function image_imagemagick_definecanvas(stdClass $image, $data) {
|
||||
$compose_operator = $data['under'] ? 'src-over' : 'dst-over';
|
||||
$image->ops[] = "-compose $compose_operator";
|
||||
|
||||
$targetsize = $data['targetsize'];
|
||||
$geometry = sprintf('%dx%d', $targetsize['width'], $targetsize['height']);
|
||||
if ($targetsize['left'] || $targetsize['top']) {
|
||||
$geometry .= sprintf('%+d%+d', -$targetsize['left'], -$targetsize['top']);
|
||||
$target_size = $data['targetsize'];
|
||||
$geometry = sprintf('%dx%d', $target_size['width'], $target_size['height']);
|
||||
if ($target_size['left'] || $target_size['top']) {
|
||||
$geometry .= sprintf('%+d%+d', -$target_size['left'], -$target_size['top']);
|
||||
}
|
||||
$image->ops[] = '-extent ' . escapeshellarg($geometry);
|
||||
|
||||
@@ -594,7 +596,7 @@ function canvasactions_canvas2file_effect(stdClass $image, array $data) {
|
||||
// This func modifies the underlay image by ref, placing the current canvas on it.
|
||||
if (image_overlay($image, $underlay, $data['xpos'], $data['ypos'], $data['alpha'], TRUE)) {
|
||||
//$image->resource = $underlay->resource;
|
||||
$image = $underlay; //@todo: this is a no-op.
|
||||
//$image = $underlay; //@todo: this is a no-op.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -935,7 +937,7 @@ function canvasactions_aspect_effect(stdClass $image, array $data) {
|
||||
* An associative array containing the effect data.
|
||||
*/
|
||||
function canvasactions_aspect_dimensions(array &$dimensions, array $data) {
|
||||
if (!isset($dimensions['width']) || !isset($dimensions['height'])) {
|
||||
if (empty($dimensions['width']) || empty($dimensions['height'])) {
|
||||
// We cannot know which preset would be executed and thus cannot know the
|
||||
// resulting dimensions, unless both styles return the same dimensions:
|
||||
$landscape_dimensions = $portrait_dimensions = $dimensions;
|
||||
@@ -998,9 +1000,13 @@ function canvasactions_resizepercent_form(array $data) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Element validate handler to ensure that a positive number is specified.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element to validate.
|
||||
* @param array $form_state
|
||||
* The form state.
|
||||
*/
|
||||
function canvasactions_resizepercent_validate($element, &$form_state) {
|
||||
element_validate_number($element, $form_state);
|
||||
@@ -1247,3 +1253,441 @@ function image_imagemagick_interlace($image/*, array $data*/) {
|
||||
$image->ops[] = '-interlace Plane';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect form callback for the Perspective effect.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function canvasactions_perspective_form(array $data) {
|
||||
$defaults = array(
|
||||
'vanish' => 'right',
|
||||
'symmetry' => 'symmetrical',
|
||||
'distortion' => 14,
|
||||
'opposite_distortion' => 10,
|
||||
);
|
||||
$data = array_merge($defaults, $data);
|
||||
|
||||
$form['vanish'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Vanishing point'),
|
||||
'#options' => array(
|
||||
'top' => t('Top'),
|
||||
'left' => t('Left'),
|
||||
'right' => t('Right'),
|
||||
'bottom' => t('Bottom'),
|
||||
),
|
||||
'#theme' => 'canvasactions_perspective_anchor',
|
||||
'#default_value' => $data['vanish'],
|
||||
'#description' => t('The position of the vanishing point relative to the source image.'),
|
||||
);
|
||||
|
||||
$form['symmetry'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Symmetry of image perspective'),
|
||||
'#description' => t('If symmetrical, the perspective effect will be built symmetrically. If asymmetrical, you can set different distortion values for both sides. Mathematically speaking: symmetrical distortion results in an isosceles trapezoid, whereas asymmetrical distortion results in just an acute trapezoid.'),
|
||||
'#default_value' => $data['symmetry'],
|
||||
'#options' => array(
|
||||
'symmetrical' => t('Symmetrical perspective'),
|
||||
'asymmetrical' => t('Asymmetrical perspective'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['distortion'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Distortion'),
|
||||
'#field_suffix' => '%',
|
||||
'#size' => 5,
|
||||
'#default_value' => $data['distortion'],
|
||||
'#element_validate' => array('canvasactions_perspective_distortion_validate'),
|
||||
'#description' => t('How much the corner(s) (on the vanishing point side of the image) should move to the horizon (i.e. the line containing the vanishing point). With 0% you will have no perspective effect at all and the vanishing point will be infinitely far away. With a sum of 100%, the 2 corner(s) and the vanishing point will be the same, resulting in a triangle instead of a trapezoid. For a pleasing effect, you should choose (a) number(s) between 0 and 35%, especially with ImageMagick as that toolkit also adds some stretching within the image.'),
|
||||
);
|
||||
|
||||
$form['opposite_distortion'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Distortion for opposite side'),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="data[symmetry]"]' => array('value' => 'asymmetrical'),
|
||||
),
|
||||
),
|
||||
'#field_suffix' => '%',
|
||||
'#size' => 5,
|
||||
'#default_value' => $data['opposite_distortion'],
|
||||
'#element_validate' => array('canvasactions_perspective_distortion_validate'),
|
||||
'#description' => t('How much the 2nd corner on the vanishing point side of the image should move to the horizon line containing the vanishing point.'),
|
||||
);
|
||||
|
||||
$form['additional_help'] = array(
|
||||
'#markup' => '<p>Some notes:</p>
|
||||
<ul><li>This effect adds a perspective effect to an image.
|
||||
Normally, to get a realistic effect, the side that gets the perspective effect should be reduced in size.
|
||||
However, this effect does not do so, as it is easy to add a (percentage) resize effect to the image style yourself.
|
||||
A resize to 85% of the original size is a good start when experimenting.</li>
|
||||
<li>CSS3 also defines <a href="https://www.w3.org/TR/2009/WD-css3-3d-transforms-20090320/#perspective-property">3D perspective transformations</a>.
|
||||
So you might get some of the results of ths effect with pure CSS as well.</li></ul>',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element validation handler for distortion.
|
||||
*
|
||||
* @param array $element
|
||||
* The form element to validate.
|
||||
* @param array $form_state
|
||||
* The form state.
|
||||
*/
|
||||
function canvasactions_perspective_distortion_validate($element, &$form_state) {
|
||||
$symmetrical = $form_state['values']['data']['symmetry'] === 'symmetrical';
|
||||
$element_name = $element['#name'];
|
||||
// Do not check opposite distortion if it is hidden in the UI.
|
||||
if (!$symmetrical || $element_name === 'data[distortion]') {
|
||||
$value = $element['#value'];
|
||||
// Check value itself: a number between 0 and 100 (50 if symmetrical):
|
||||
$max_value = $symmetrical ? 50 : 100;
|
||||
if (!is_numeric($value) || $value < 0 || $value >= $max_value) {
|
||||
if ($symmetrical) {
|
||||
form_error($element, t('!name must be a value between 0 and 50.', array('!name' => $element['#title'])));
|
||||
}
|
||||
else {
|
||||
form_error($element, t('!name must be a value between 0 and 100.',array('!name' => $element['#title'])));
|
||||
}
|
||||
}
|
||||
// Sum of both distortion values should also be smaller then 100.
|
||||
if (!$symmetrical) {
|
||||
$other_value_name = $element_name === 'data[distortion]' ? 'opposite_distortion' : 'distortion';
|
||||
$other_value = $form_state['values']['data'][$other_value_name];
|
||||
if (is_numeric($other_value) && $value + $other_value >= 100) {
|
||||
form_error($element, t('The sum of %name and %name2 must be lower then 100.',
|
||||
array(
|
||||
'%name' => $element['#title'],
|
||||
'%name2' => $other_value_name === 'distortion' ? t('Distortion') : t('Distortion for opposite side'),
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the define perspective effect summary.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_canvasactions_perspective_summary(array $variables) {
|
||||
$data = $variables['data'];
|
||||
$output = array();
|
||||
|
||||
$output[] = t('%symmetry. Vanishing point: %vanish.',
|
||||
array(
|
||||
'%symmetry' => $data['symmetry'],
|
||||
'%vanish' => $data['vanish'],
|
||||
));
|
||||
|
||||
if ($data['symmetry'] == 'asymmetrical') {
|
||||
switch ($data['vanish']) {
|
||||
case 'top':
|
||||
case 'bottom':
|
||||
$output[] = t('Left distortion: %distortion, right distortion: %opposite_distortion.',
|
||||
array(
|
||||
'%distortion' => $data['distortion'] . '%',
|
||||
'%opposite_distortion' => $data['opposite_distortion'] . '%',
|
||||
));
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
case 'left':
|
||||
$output[] = t('Top distortion: %distortion, bottom distortion: %opposite_distortion.',
|
||||
array(
|
||||
'%distortion' => $data['distortion'] . '%',
|
||||
'%opposite_distortion' => $data['opposite_distortion'] . '%',
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$output[] = t('Distortion: %distortion.', array('%distortion' => $data['distortion'] . '%'));
|
||||
}
|
||||
|
||||
return implode(' ', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the Perspective effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* Image object containing the image to operate on.
|
||||
* @param array $data
|
||||
* The current configuration for this image effect, contains the keys:
|
||||
* distortion, vanish, symmetry and opposite_distortion options.
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function canvasactions_perspective_effect(stdClass $image, array $data) {
|
||||
if (!image_toolkit_invoke('perspective', $image, array($data))) {
|
||||
watchdog('imagecache_canvasactions', 'Image perspective transform failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array(
|
||||
'%toolkit' => $image->toolkit,
|
||||
'%path' => $image->source,
|
||||
'%mimetype' => $image->info['mime_type'],
|
||||
'%dimensions' => $image->info['height'] . 'x' . $image->info['height'],
|
||||
), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of the image Perspective effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* Image object containing the image resource to operate on.
|
||||
* @param array $data
|
||||
* The current configuration for this image effect, contains the keys:
|
||||
* distortion, vanish, symmetry and opposite_distortion options.
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function image_gd_perspective(stdClass $image, $data) {
|
||||
$width = $image->info['width'];
|
||||
$height = $image->info['height'];
|
||||
$distortion = $data['distortion'];
|
||||
$opposite_distortion = $data['symmetry'] === 'symmetrical' ? $distortion : $data['opposite_distortion'];
|
||||
|
||||
// To reduce distortion, we work with a temporary hires version of the image.
|
||||
// @todo: during processing we have 2 resources this size: this might crash on memory limits: warn and/or prevent.
|
||||
$multiplier = 3;
|
||||
$hires_width = $width * $multiplier;
|
||||
$hires_height = $height * $multiplier;
|
||||
$hires_source_image = imagecreatetruecolor($hires_width, $hires_height);
|
||||
$transparent_white = imagecolorallocatealpha($hires_source_image, 255, 255, 255, 127);
|
||||
imagealphablending($hires_source_image, FALSE);
|
||||
imagefilledrectangle($hires_source_image, 0, 0, $hires_width, $hires_height, $transparent_white);
|
||||
imagesavealpha($hires_source_image, TRUE);
|
||||
imagecopyresized($hires_source_image, $image->resource, 0, 0, 0, 0, $hires_width, $hires_height, $width, $height);
|
||||
imagedestroy($image->resource);
|
||||
|
||||
// Creating a hires target canvas to apply the perspective effect on.
|
||||
$hires_target_image = imagecreatetruecolor($hires_width, $hires_height);
|
||||
$transparent_white = imagecolorallocatealpha($hires_target_image, 255, 255, 255, 127);
|
||||
// We don't want to blend: the transparent background we set is only for the
|
||||
// parts that do not get covered.
|
||||
imagealphablending($hires_target_image, FALSE);
|
||||
imagefilledrectangle($hires_target_image, 0, 0, $hires_width, $hires_height, $transparent_white);
|
||||
|
||||
// Building perspective effect with help four point distortion methods.
|
||||
// On each step found new distortion point by right triangle formula.
|
||||
switch ($data['vanish']) {
|
||||
case 'top':
|
||||
$left = round($hires_width * $distortion / 100);
|
||||
$right = round($hires_width - ($hires_width * (100 - $opposite_distortion) / 100));
|
||||
|
||||
$tg_beta_left = $left / $hires_height;
|
||||
$tg_beta_right = $right / $hires_height;
|
||||
|
||||
for ($y = 0; $y < $hires_height; $y++) {
|
||||
$new_left = ($hires_height - $y) * $tg_beta_left;
|
||||
$new_right = ($hires_height - $y) * $tg_beta_right;
|
||||
$new_width = $hires_width - $new_left - $new_right;
|
||||
imagecopyresampled($hires_target_image, $hires_source_image,
|
||||
$new_left, $y,
|
||||
0, $y,
|
||||
$new_width, 1,
|
||||
$hires_width, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
$left = round($hires_width * $distortion / 100);
|
||||
$right = round($hires_width - ($hires_width * (100 - $opposite_distortion) / 100));
|
||||
|
||||
$tg_beta_left = $left / $hires_height;
|
||||
$tg_beta_right = $right / $hires_height;
|
||||
|
||||
for ($y = $hires_height; $y > 0; $y--) {
|
||||
$new_left = $y * $tg_beta_left;
|
||||
$new_right = $y * $tg_beta_right;
|
||||
$new_width = $hires_width - $new_left - $new_right;
|
||||
imagecopyresampled($hires_target_image, $hires_source_image,
|
||||
$new_left, $y,
|
||||
0, $y,
|
||||
$new_width, 1,
|
||||
$hires_width, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
$top = round($hires_height * $distortion / 100);
|
||||
$bottom = round($hires_height - ($hires_height * (100 - $opposite_distortion) / 100));
|
||||
|
||||
$tg_beta_top = $top / $hires_width;
|
||||
$tg_beta_bottom = $bottom / $hires_width;
|
||||
|
||||
for ($x = $hires_width; $x > 0; $x--) {
|
||||
$new_top = $x * $tg_beta_top;
|
||||
$new_bottom = $x * $tg_beta_bottom;
|
||||
$new_height = $hires_height - $new_top - $new_bottom;
|
||||
imagecopyresampled($hires_target_image, $hires_source_image,
|
||||
$x, $new_top,
|
||||
$x, 0,
|
||||
1, $new_height,
|
||||
1, $hires_height);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
$top = round($hires_height * $distortion / 100);
|
||||
$bottom = round($hires_height - ($hires_height * (100 - $opposite_distortion) / 100));
|
||||
|
||||
$tg_beta_top = $top / $hires_width;
|
||||
$tg_beta_bottom = $bottom / $hires_width;
|
||||
|
||||
for ($x = 0; $x < $hires_width; $x++) {
|
||||
$new_top = ($hires_width - $x) * $tg_beta_top;
|
||||
$new_bottom = ($hires_width - $x) * $tg_beta_bottom;
|
||||
$new_height = $hires_height - $new_top - $new_bottom;
|
||||
imagecopyresampled($hires_target_image, $hires_source_image,
|
||||
$x, $new_top,
|
||||
$x, 0,
|
||||
1, $new_height,
|
||||
1, $hires_height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
imagedestroy($hires_source_image);
|
||||
imagealphablending($hires_target_image, FALSE);
|
||||
imagesavealpha($hires_target_image, TRUE);
|
||||
|
||||
// Return image with perspective effect to original size.
|
||||
$target_image = imagecreatetruecolor($width, $height);
|
||||
imagealphablending($target_image, FALSE);
|
||||
imagecopyresampled($target_image, $hires_target_image, 0, 0, 0, 0, $width, $height, $hires_width, $hires_height);
|
||||
imagedestroy($hires_target_image);
|
||||
imagesavealpha($target_image, TRUE);
|
||||
|
||||
$image->resource = $target_image;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the image Perspective effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* Image object containing the image to operate on.
|
||||
* @param array $data
|
||||
* The current configuration for this image effect, contains the keys
|
||||
* distortion, vanish, symmetry and opposite_distortion options.
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function image_imagemagick_perspective(stdClass $image, $data) {
|
||||
$width = $image->info['width'];
|
||||
$height = $image->info['height'];
|
||||
$distortion = $data['distortion'];
|
||||
$opposite_distortion = $data['symmetry'] === 'symmetrical' ? $distortion : $data['opposite_distortion'];
|
||||
|
||||
switch ($data['vanish']) {
|
||||
case 'top':
|
||||
$left = round($width * $distortion / 100);
|
||||
$right = round($width * (100 - $opposite_distortion) / 100);
|
||||
$perspective_arg = "0,0,$left,0 0,$height,0,$height $width,0,$right,0 $width,$height,$width,$height";
|
||||
break;
|
||||
|
||||
case 'right':
|
||||
default: // Prevents warning about possibly undefined variable.
|
||||
$top = round($height * $distortion / 100);
|
||||
$bottom = round($height * (100 - $opposite_distortion) / 100);
|
||||
$perspective_arg = "0,0,0,0 0,$height,0,$height $width,0,$width,$top $width,$height,$width,$bottom";
|
||||
break;
|
||||
|
||||
case 'bottom':
|
||||
$left = round($width * $distortion / 100);
|
||||
$right = round($width * (100 - $opposite_distortion) / 100);
|
||||
$perspective_arg = "0,0,0,0 0,$height,$left,$height $width,0,$width,0 $width,$height,$right,$height";
|
||||
break;
|
||||
|
||||
case 'left':
|
||||
$top = round($height * $distortion / 100);
|
||||
$bottom = round($height * (100 - $opposite_distortion) / 100);
|
||||
$perspective_arg = "0,0,0,$top 0,$height,0,$bottom $width,0,$width,0 $width,$height,$width,$height";
|
||||
break;
|
||||
}
|
||||
|
||||
$transparent_white = escapeshellarg('#ffffffff');
|
||||
$perspective = escapeshellarg($perspective_arg);
|
||||
$image->ops[] = "-background $transparent_white -virtual-pixel background -distort Perspective $perspective";
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/** @noinspection PhpDocMissingThrowsInspection */
|
||||
/**
|
||||
* Implements theme_hook().
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - element: A render element containing radio buttons.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for a 3x3 grid of checkboxes for image anchors.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_canvasactions_perspective_anchor($variables) {
|
||||
$element = $variables['element'];
|
||||
|
||||
$rows = $row = $option = array();
|
||||
|
||||
$blank = array('#markup' => '');
|
||||
$blank = drupal_render($blank);
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
$image = array(
|
||||
'#markup' => theme('image', array(
|
||||
'path' => drupal_get_path('module', 'image') . '/sample.png',
|
||||
'attributes' => array('width' => "40", 'height' => "40"),
|
||||
)),
|
||||
);
|
||||
$image = drupal_render($image);
|
||||
|
||||
foreach (element_children($element) as $key) {
|
||||
$element[$key]['#attributes']['title'] = $element[$key]['#title'];
|
||||
unset($element[$key]['#title']);
|
||||
$option[] = drupal_render($element[$key]);
|
||||
}
|
||||
|
||||
$row[] = $blank;
|
||||
$row[] = $option[0];
|
||||
$row[] = $blank;
|
||||
$rows[] = $row;
|
||||
$row = array();
|
||||
|
||||
$row[] = $option[1];
|
||||
$row[] = $image;
|
||||
$row[] = $option[2];
|
||||
$rows[] = $row;
|
||||
$row = array();
|
||||
|
||||
$row[] = $blank;
|
||||
$row[] = $option[3];
|
||||
$row[] = $blank;
|
||||
$rows[] = $row;
|
||||
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
return theme('table', array('header' => array(), 'rows' => $rows, 'attributes' => array('class' => array('image-anchor'))));
|
||||
}
|
||||
|
||||
+3
-4
@@ -6,9 +6,8 @@ core = 7.x
|
||||
dependencies[] = imagecache_actions
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+16
@@ -145,6 +145,15 @@ function imagecache_canvasactions_image_effect_info() {
|
||||
'form callback' => 'canvasactions_interlace_form',
|
||||
);
|
||||
|
||||
$effects['canvasactions_perspective'] = array(
|
||||
'label' => t('Perspective transform'),
|
||||
'help' => t('Adds a perspective transformation to the image.'),
|
||||
'effect callback' => 'canvasactions_perspective_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'canvasactions_perspective_form',
|
||||
'summary theme' => 'canvasactions_perspective_summary',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
@@ -191,6 +200,13 @@ function imagecache_canvasactions_theme() {
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_perspective_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
'file' => 'canvasactions.inc',
|
||||
),
|
||||
'canvasactions_perspective_anchor' => array(
|
||||
'render element' => 'element',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -152,8 +152,8 @@ function image_gd_roundedcorners($image, $action) {
|
||||
}
|
||||
|
||||
// key can be 'tl', 'tr', 'bl', 'br'.
|
||||
$is_bottom = ($key{0} == 'b');
|
||||
$is_right = ($key{1} == 'r');
|
||||
$is_bottom = ($key[0] == 'b');
|
||||
$is_right = ($key[1] == 'r');
|
||||
|
||||
// dx and dy are in "continuous coordinates",
|
||||
// and mark the distance of the pixel middle to the image border.
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ $presets['cheap_dropshadow'] = array (
|
||||
'data' =>
|
||||
array (
|
||||
'width' => '200',
|
||||
'height' => '100%',
|
||||
'height' => '',
|
||||
'upscale' => 0,
|
||||
),
|
||||
),
|
||||
|
||||
+3
-4
@@ -10,9 +10,8 @@ files[] = imagecache_coloractions.module
|
||||
files[] = transparency.inc
|
||||
files[] = tests/green.imagecache_preset.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+238
-8
@@ -51,6 +51,15 @@ function imagecache_coloractions_image_effect_info() {
|
||||
'summary theme' => 'coloractions_coloroverlay_summary',
|
||||
);
|
||||
|
||||
$effects['imagecache_colormultiply'] = array(
|
||||
'label' => t('Color Multiply'),
|
||||
'help' => t('Apply a multiply blend effect to an image. The result color is always a darker color.'),
|
||||
'effect callback' => 'coloractions_colormultiply_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'coloractions_colormultiply_form',
|
||||
'summary theme' => 'coloractions_colormultiply_summary',
|
||||
);
|
||||
|
||||
$effects['coloractions_brightness'] = array(
|
||||
'label' => t('Brightness'),
|
||||
'help' => t('Adjust image brightness.'),
|
||||
@@ -67,7 +76,6 @@ function imagecache_coloractions_image_effect_info() {
|
||||
'effect callback' => 'coloractions_invert_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'coloractions_invert_form',
|
||||
'summary theme' => 'coloractions_invert_summary',
|
||||
);
|
||||
|
||||
// @todo Convert may need a little more work.
|
||||
@@ -116,6 +124,15 @@ function imagecache_coloractions_image_effect_info() {
|
||||
'summary theme' => 'coloractions_desaturatealpha_summary',
|
||||
);
|
||||
|
||||
$effects['imagecache_removeanimation'] = array(
|
||||
'label' => t('Remove animation'),
|
||||
'help' => t('Freezes an animated image, keeping only the first frame.'),
|
||||
'effect callback' => 'coloractions_removeanimation_effect',
|
||||
'dimensions passthrough' => TRUE,
|
||||
'form callback' => 'coloractions_removeanimation_form',
|
||||
'summary theme' => 'coloractions_removeanimation_summary',
|
||||
);
|
||||
|
||||
return $effects;
|
||||
}
|
||||
|
||||
@@ -132,6 +149,9 @@ function imagecache_coloractions_theme() {
|
||||
'coloractions_coloroverlay_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
'coloractions_colormultiply_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
'coloractions_brightness_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
@@ -151,6 +171,9 @@ function imagecache_coloractions_theme() {
|
||||
'coloractions_desaturatealpha_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
'coloractions_removeanimation_summary' => array(
|
||||
'variables' => array('data' => NULL),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -215,7 +238,7 @@ function coloractions_colorshift_form(array $data) {
|
||||
desaturate (greyscale) it before colorizing.
|
||||
The hue (color wheel) is the <em>direction</em> the
|
||||
existing colors are shifted. The tone (inner box) is the amount.
|
||||
Keep the tone half-way up the left site of the color box
|
||||
Keep the tone half-way up the left side of the color box
|
||||
for best results.
|
||||
</p>"));
|
||||
return $form;
|
||||
@@ -300,7 +323,7 @@ function image_imagemagick_colorshift(stdClass $image, array $data) {
|
||||
function coloractions_coloroverlay_form(array $data) {
|
||||
$defaults = array(
|
||||
'RGB' => array(
|
||||
'HEX' => '#E2DB6A',
|
||||
'HEX' => '',
|
||||
),
|
||||
);
|
||||
$data = array_merge($defaults, (array) $data);
|
||||
@@ -313,7 +336,7 @@ function coloractions_coloroverlay_form(array $data) {
|
||||
desaturate (greyscale) it before colorizing.
|
||||
The hue (color wheel) is the <em>direction</em> the
|
||||
existing colors are shifted. The tone (inner box) is the amount.
|
||||
Keep the tone half-way up the left site of the color box
|
||||
Keep the tone half-way up the left side of the color box
|
||||
for best results.
|
||||
</p>"));
|
||||
return $form;
|
||||
@@ -411,6 +434,126 @@ function image_imagemagick_coloroverlay(stdClass $image, array $data) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect form callback for the color multiply effect.
|
||||
*
|
||||
* @param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function coloractions_colormultiply_form(array $data) {
|
||||
$defaults = array(
|
||||
'RGB' => array(
|
||||
'HEX' => '',
|
||||
),
|
||||
);
|
||||
$data = array_merge($defaults, (array) $data);
|
||||
$form = array('#theme' => 'imagecache_rgb_form');
|
||||
$form['RGB'] = imagecache_rgb_form($data['RGB']);
|
||||
$form['note'] = array('#value' => t("<p>
|
||||
Note that color multiply is a mathematical filter that doesn't always
|
||||
have the expected result.
|
||||
To shift an image precisely TO a target color,
|
||||
desaturate (greyscale) it before colorizing.
|
||||
The hue (color wheel) is the <em>direction</em> the
|
||||
existing colors are shifted. The tone (inner box) is the amount.
|
||||
Keep the tone half-way up the left side of the color box
|
||||
for best results.
|
||||
</p>"));
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the color multiply effect summary.
|
||||
*
|
||||
* @param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_coloractions_colormultiply_summary(array $variables) {
|
||||
return theme_imagecacheactions_rgb($variables['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the color multiply effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function coloractions_colormultiply_effect(stdClass $image, array $data) {
|
||||
// Convert color from hex (as it is stored in the UI).
|
||||
if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
|
||||
$data['RGB'] = array_merge($data['RGB'], $deduced);
|
||||
}
|
||||
return image_toolkit_invoke('colormultiply', $image, array($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of the color multiply effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_gd_colormultiply(stdClass $image, array $data) {
|
||||
$factor_r = $data['RGB']['red'] / 255;
|
||||
$factor_g = $data['RGB']['green'] / 255;
|
||||
$factor_b = $data['RGB']['blue'] / 255;
|
||||
|
||||
$w = $image->info['width'];
|
||||
$h = $image->info['height'];
|
||||
|
||||
for ($y = 0; $y < $h; $y++) {
|
||||
for ($x = 0; $x < $w; $x++) {
|
||||
$rgb = imagecolorat($image->resource, $x, $y);
|
||||
$source = imagecolorsforindex($image->resource, $rgb);
|
||||
|
||||
$final_r = (int) ($source['red'] * $factor_r);
|
||||
$final_g = (int) ($source['green'] * $factor_g);
|
||||
$final_b = (int) ($source['blue'] * $factor_b);
|
||||
|
||||
$final_colour = imagecolorallocate($image->resource, $final_r, $final_g, $final_b);
|
||||
if ($final_colour === FALSE) {
|
||||
return FALSE;
|
||||
}
|
||||
if (!imagesetpixel($image->resource, $x, $y, $final_colour)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the color multiply effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_imagemagick_colormultiply(stdClass $image, array $data) {
|
||||
$multiply_color = $data['RGB']['HEX'] != '' ? '#' . ltrim($data['RGB']['HEX'], '#') : 'None';
|
||||
$image->ops[] = escapeshellcmd('(') . ' +clone -fill ' . escapeshellarg($multiply_color) . ' -colorize 100 ' . escapeshellcmd(')');
|
||||
$image->ops[] = '-compose multiply -composite';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Image effect form callback for the brightness effect.
|
||||
@@ -545,16 +688,17 @@ function image_gd_invert(stdClass $image/*, array $data*/) {
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the image invert effect.
|
||||
*
|
||||
* param stdClass $image
|
||||
* @param stdClass $image
|
||||
* param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function image_imagemagick_invert(/*stdClass $image, array $data*/) {
|
||||
// @todo
|
||||
return FALSE;
|
||||
function image_imagemagick_invert(stdClass $image/*, array $data*/) {
|
||||
// http://www.imagemagick.org/script/command-line-options.php?#negate
|
||||
$image->ops[] = "-negate";
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1100,3 +1244,89 @@ function image_gd_desaturatealpha(stdClass $image/*, array $data*/) {
|
||||
imagealphablending($image->resource, TRUE);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect form callback for the remove animation effect.
|
||||
*
|
||||
* This effect has no parameters.
|
||||
*
|
||||
* param array $data
|
||||
* The current configuration for this image effect.
|
||||
*
|
||||
* @return array
|
||||
* The form definition for this effect.
|
||||
*/
|
||||
function coloractions_removeanimation_form(/*array $data*/) {
|
||||
$form = array();
|
||||
$form['help'] = array(
|
||||
'#markup' => "<p><strong>There are no user-configurable options for this effect.</strong></p>
|
||||
<p>This image effect will remove all animation from a gif image, keeping only the first frame. Some notes:</p>
|
||||
<ul>
|
||||
<li>GD cannot handle animation at all and will always silently remove animation, whether this effect has been added to an image style or not.</li>
|
||||
<li>Thus, this effect will only do something with ImageMagick as image toolkit.</li>
|
||||
<li>Non gif images and non-animated gif images are silently ignored.</li>
|
||||
<li>You can place this effect anywhere in the list of effects for an image style. There may be some performance gains when you add it as first though.</li>
|
||||
</ul>
|
||||
",
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements theme_hook() for the remove animation effect summary.
|
||||
*
|
||||
* param array $variables
|
||||
* An associative array containing:
|
||||
* - data: The current configuration for this image effect.
|
||||
*
|
||||
* @return string
|
||||
* The HTML for the summary of this image effect.
|
||||
* @ingroup themeable
|
||||
*/
|
||||
function theme_coloractions_removeanimation_summary(/*array $variables*/) {
|
||||
return t('Remove animation, keeping only the first frame.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Image effect callback for the remove animation effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function coloractions_removeanimation_effect(stdClass $image, array $data) {
|
||||
return image_toolkit_invoke('removeanimation', $image, array($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* GD toolkit specific implementation of the remove animation effect.
|
||||
*
|
||||
* param stdClass $image
|
||||
* param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* Always true, GD removes animations anyway.
|
||||
*/
|
||||
function image_gd_removeanimation(/*stdClass $image, array $data*/) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imagemagick toolkit specific implementation of the remove animation effect.
|
||||
*
|
||||
* @param stdClass $image
|
||||
* param array $data
|
||||
* The parameters for this effect.
|
||||
*
|
||||
* @return bool
|
||||
* True on success, false otherwise.
|
||||
*/
|
||||
function image_imagemagick_removeanimation(stdClass $image/*, array $data*/) {
|
||||
if ($image->info['mime_type'] === 'image/gif') {
|
||||
$image->ops[] = '-delete 1--1';
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -58,8 +58,9 @@ record so by changing $image->info['width'] and/or $image->info['height'].
|
||||
General
|
||||
-------
|
||||
To ease your task, this effect makes some information regarding the image being
|
||||
processed available in 2 variables: $image and $image_context. These variables
|
||||
are readily available in your snippet.
|
||||
processed available in a number of variables: $image, $image_context,
|
||||
$image_style, and $image_effect_id. These variables are readily available in
|
||||
your snippet.
|
||||
|
||||
$image is an object containing the following properties:
|
||||
- source: string, the source of the image, e.g. public://photo.jpg
|
||||
@@ -112,6 +113,18 @@ $image_context is an associative array containing:
|
||||
- title (string) ...
|
||||
- ...
|
||||
|
||||
$image_style is an associative array containing the current image style being
|
||||
processed. It ocntians a.o.:
|
||||
- isid: the unique image style id
|
||||
- name: machine name.
|
||||
- label: Human readable name.
|
||||
- effects: An array with the effects of this image style, ordered in the way
|
||||
they should be applied.
|
||||
|
||||
$image_effect_id is an int containng the unique id of the current image effect
|
||||
being applied. This can be used to look the current image effect up in the
|
||||
$image_style array.
|
||||
|
||||
Of course there are many other possible useful globals. Think of:
|
||||
- base_url
|
||||
- base_path
|
||||
@@ -143,3 +156,41 @@ foreach ($referring_entities as $field_name => $field_referring_entities) {
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
"Dynamic" parameters
|
||||
--------------------
|
||||
Thee are many requests for adding token support or allowing for dynamic
|
||||
parameters in another way. However, the current image style processing does not
|
||||
easily allow for this. But for these cases we have the custom action to our
|
||||
rescue. It is quite easy to:
|
||||
- Create you own array of parameters.
|
||||
- Call the effect callback yourself
|
||||
|
||||
Exanple, calling the watermark/canvas overlay effect:
|
||||
<?php
|
||||
$data = array(
|
||||
'xpos' => 'center',
|
||||
'ypos' => 'center',
|
||||
'alpha' => '100',
|
||||
'scale' => '',
|
||||
'path' => 'module://imagecache_actions/tests/black-ribbon.gif',
|
||||
);
|
||||
return canvasactions_file2canvas_effect($image, $data);
|
||||
?>
|
||||
|
||||
Or, to be on the safe side with effect info altering:
|
||||
<?php
|
||||
$definition = image_effect_definition_load('canvasactions_file2canvas');
|
||||
$callback = $definition['effect callback'];
|
||||
if (function_exists($callback)) {
|
||||
$data = array(
|
||||
'xpos' => 'center',
|
||||
'ypos' => 'center',
|
||||
'alpha' => '100',
|
||||
'scale' => '',
|
||||
'path' => 'module://imagecache_actions/tests/black-ribbon.gif',
|
||||
);
|
||||
return $callback($image, $data);
|
||||
}
|
||||
return FALSE;
|
||||
?>
|
||||
|
||||
+3
-4
@@ -6,9 +6,8 @@ core = 7.x
|
||||
dependencies[] = imagecache_actions
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+7
-1
@@ -156,7 +156,6 @@ function theme_imagecache_customactions_summary(/*array $variables*/) {
|
||||
* true on success, false otherwise.
|
||||
*/
|
||||
function imagecache_customactions_effect(stdClass $image, array $data) {
|
||||
// Check that the PHP filter module is enabled.
|
||||
$result = module_exists('php');
|
||||
if ($result) {
|
||||
// Get context about the image.
|
||||
@@ -164,10 +163,17 @@ function imagecache_customactions_effect(stdClass $image, array $data) {
|
||||
$GLOBALS['image_context'] = imagecache_actions_get_image_context($image, $data);
|
||||
$GLOBALS['image'] = $image;
|
||||
|
||||
// Get (non-alterable) context about the image style and image effect.
|
||||
$execution_info = imagecache_actions_get_image_effect_context();
|
||||
$GLOBALS['image_style'] = $execution_info['image_style'];
|
||||
$GLOBALS['image_effect_id'] = $execution_info['image_effect_id'];
|
||||
|
||||
$result = php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>');
|
||||
// php_eval returns '1' if the snippet returns true.
|
||||
$result = $result === '1';
|
||||
|
||||
unset($GLOBALS['image_effect_id']);
|
||||
unset($GLOBALS['image_style']);
|
||||
unset($GLOBALS['image']);
|
||||
unset($GLOBALS['image_context']);
|
||||
}
|
||||
|
||||
@@ -150,8 +150,9 @@ PHP snippets to determine the text
|
||||
----------------------------------
|
||||
Given the correct permission, you can write your own PHP snippet to compute the
|
||||
text to display. To ease this task, this module makes some information regarding
|
||||
the image being processed available in 2 variables: $image and $image_context.
|
||||
These variables are readily available in your snippet.
|
||||
the image being processed available in a number of variables: $image,
|
||||
$image_context, $image_style, and $image_effect_id. These variables are readily
|
||||
available in your snippet.
|
||||
|
||||
$image is an object containing the following properties:
|
||||
- source: string, the source of the image, e.g. public://photo.jpg
|
||||
@@ -214,6 +215,18 @@ $image_context is an associative array containing:
|
||||
- title (string) ...
|
||||
- ...
|
||||
|
||||
$image_style is an associative array containing the current image style being
|
||||
processed. It ocntians a.o.:
|
||||
- isid: the unique image style id
|
||||
- name: machine name.
|
||||
- label: Human readable name.
|
||||
- effects: An array with the effects of this image style, ordered in the way
|
||||
they should be applied.
|
||||
|
||||
$image_effect_id is an int containng the unique id of the current image effect
|
||||
being applied. This can be used to look the current image effect up in the
|
||||
$image_style array.
|
||||
|
||||
Of course there are many other possible useful globals. Think of:
|
||||
- base_url
|
||||
- base_path
|
||||
|
||||
+141
-75
@@ -66,15 +66,6 @@ function image_effects_text_form_inc(array $data) {
|
||||
// - Change the 'PHP code' textarea.
|
||||
$allow_php = module_exists('php') && user_access('use PHP for settings');
|
||||
$defaults = array(
|
||||
'size' => 50,
|
||||
'angle' => 0,
|
||||
'xpos' => '0',
|
||||
'ypos' => '0',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'RGB' => array('HEX' => '#000000'),
|
||||
'alpha' => 100,
|
||||
'fontfile' => drupal_get_path('module', 'image_effects_text') . '/Komika_display.ttf',
|
||||
'text_source' => 'text',
|
||||
'text' => t('Hello World!'),
|
||||
'php' => 'if (!$image_context[\'entity\']) {
|
||||
@@ -88,77 +79,21 @@ if ($field) {
|
||||
return isset($field[0][\'value\']) ? $field[0][\'value\'] : \'' . t('No field value') . '\';
|
||||
}
|
||||
',
|
||||
'text_case' => 'none',
|
||||
'fontfile' => drupal_get_path('module', 'image_effects_text') . '/Komika_display.ttf',
|
||||
'size' => 50,
|
||||
'RGB' => array('HEX' => '#000000'),
|
||||
'alpha' => 100,
|
||||
'xpos' => '0',
|
||||
'ypos' => '0',
|
||||
'halign' => 'left',
|
||||
'valign' => 'top',
|
||||
'angle' => 0,
|
||||
);
|
||||
$data += $defaults;
|
||||
$tokens = token_info();
|
||||
$tokens = array_keys($tokens['types']);
|
||||
$form = array(
|
||||
'size' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font size'),
|
||||
'#default_value' => $data['size'],
|
||||
'#description' => t('The font size in points. Only in GD1 this is in pixels.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
'xpos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('X offset'),
|
||||
'#default_value' => $data['xpos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>left</em>, <em>center</em>, or <em>right</em>. Syntax like <em>right-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'ypos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Y offset'),
|
||||
'#default_value' => $data['ypos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>top</em>, <em>center</em>, or <em>bottom</em>. Syntax like <em>bottom-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'halign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Horizontal alignment'),
|
||||
'#default_value' => $data['halign'],
|
||||
'#description' => t('The horizontal alignment of the text around the given %xpos.', array('%xpos' => t('X offset'))),
|
||||
'#options' => array(
|
||||
'left' => t('Left'),
|
||||
'center' => t('Center'),
|
||||
'right' => t('Right')
|
||||
),
|
||||
),
|
||||
'valign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Vertical alignment'),
|
||||
'#default_value' => $data['valign'],
|
||||
'#description' => t('The vertical alignment of the text around the given %ypos.', array('%ypos' => t('Y offset'))),
|
||||
'#options' => array(
|
||||
'top' => t('Top'),
|
||||
'center' => t('Center'),
|
||||
'bottom' => t('Bottom')
|
||||
),
|
||||
),
|
||||
'RGB' => imagecache_rgb_form($data['RGB']),
|
||||
'alpha' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Opacity'),
|
||||
'#default_value' => $data['alpha'] ? $data['alpha'] : 100,
|
||||
'#size' => 3,
|
||||
'#description' => t('Opacity: 1-100.'),
|
||||
),
|
||||
'angle' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Angle'),
|
||||
'#default_value' => $data['angle'],
|
||||
'#description' => t('Angle: The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
'fontfile' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font file name'),
|
||||
'#default_value' => $data['fontfile'],
|
||||
'#description' => imagecache_actions_file_field_description(),
|
||||
'#element_validate' => array('image_effects_text_validate_font'),
|
||||
'#size' => 80,
|
||||
),
|
||||
'text_help' => array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Text'),
|
||||
@@ -221,6 +156,85 @@ if ($field) {
|
||||
),
|
||||
'#wysiwyg' => FALSE,
|
||||
),
|
||||
'text_case' => array(
|
||||
'#title' => t('Capitalization'),
|
||||
'#type' => 'select',
|
||||
'#options' => array(
|
||||
'none' => t('No transform'),
|
||||
'upper' => t('Upper case'),
|
||||
'lower' => t('Lower case'),
|
||||
'ucfirst' => t('Capitalize first letter'),
|
||||
'ucwords' => t('Capitalize each word'),
|
||||
),
|
||||
'#default_value' => $data['text_case'],
|
||||
'#description' => t('Defines if and how to transform the case of the text to render.'),
|
||||
),
|
||||
'fontfile' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font file name'),
|
||||
'#default_value' => $data['fontfile'],
|
||||
'#description' => imagecache_actions_file_field_description(),
|
||||
'#element_validate' => array('image_effects_text_validate_font'),
|
||||
'#size' => 80,
|
||||
),
|
||||
'size' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Font size'),
|
||||
'#default_value' => $data['size'],
|
||||
'#description' => t('The font size in points. Only in GD1 this is in pixels.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
'RGB' => imagecache_rgb_form($data['RGB']),
|
||||
'alpha' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Opacity'),
|
||||
'#default_value' => $data['alpha'],
|
||||
'#size' => 3,
|
||||
'#description' => t('Opacity: 1-100.'),
|
||||
),
|
||||
'xpos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('X offset'),
|
||||
'#default_value' => $data['xpos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>left</em>, <em>center</em>, or <em>right</em>. Syntax like <em>right-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'ypos' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Y offset'),
|
||||
'#default_value' => $data['ypos'],
|
||||
'#description' => t('Enter an offset in pixels or use a keyword: <em>top</em>, <em>center</em>, or <em>bottom</em>. Syntax like <em>bottom-20</em> is also valid.'),
|
||||
'#size' => 10,
|
||||
),
|
||||
'halign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Horizontal alignment'),
|
||||
'#default_value' => $data['halign'],
|
||||
'#description' => t('The horizontal alignment of the text around the given %xpos.', array('%xpos' => t('X offset'))),
|
||||
'#options' => array(
|
||||
'left' => t('Left'),
|
||||
'center' => t('Center'),
|
||||
'right' => t('Right')
|
||||
),
|
||||
),
|
||||
'valign' => array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Vertical alignment'),
|
||||
'#default_value' => $data['valign'],
|
||||
'#description' => t('The vertical alignment of the text around the given %ypos.', array('%ypos' => t('Y offset'))),
|
||||
'#options' => array(
|
||||
'top' => t('Top'),
|
||||
'center' => t('Center'),
|
||||
'bottom' => t('Bottom')
|
||||
),
|
||||
),
|
||||
'angle' => array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Angle'),
|
||||
'#default_value' => $data['angle'],
|
||||
'#description' => t('Angle: The angle in degrees, with 0 degrees being left-to-right reading text. Higher values represent a counter-clockwise rotation. For example, a value of 90 would result in bottom-to-top reading text.'),
|
||||
'#size' => 3,
|
||||
),
|
||||
);
|
||||
if (!$allow_php && $data['text_source'] !== 'php') {
|
||||
unset($form['text_fieldset']['text_source']['#options']['php']);
|
||||
@@ -717,12 +731,64 @@ function image_effects_text_get_text(stdClass $image, array $data) {
|
||||
// variables, so they can be passed successfully.
|
||||
$GLOBALS['image_context'] = $image_context;
|
||||
$GLOBALS['image'] = $image;
|
||||
|
||||
// Get (non-alterable) context about the image style and image effect.
|
||||
$execution_info = imagecache_actions_get_image_effect_context();
|
||||
$GLOBALS['image_style'] = $execution_info['image_style'];
|
||||
$GLOBALS['image_effect_id'] = $execution_info['image_effect_id'];
|
||||
|
||||
// We don't need to check_plain() the resulting text, as the text is not
|
||||
// rendered in a browser but processed on the server.
|
||||
$text = module_exists('php') ? php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>') : '';
|
||||
|
||||
unset($GLOBALS['image_effect_id']);
|
||||
unset($GLOBALS['image_style']);
|
||||
unset($GLOBALS['image']);
|
||||
unset($GLOBALS['image_context']);
|
||||
}
|
||||
|
||||
// Convert case.
|
||||
$text = image_effect_text_case_transform($text, isset($data['text_case']) ? $data['text_case'] : 'none');
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a string by a certain method.
|
||||
*
|
||||
* Proudly copied from module://views/includes/handlers.inc.
|
||||
*
|
||||
* @param $string
|
||||
* The input you want to transform.
|
||||
* @param $option
|
||||
* How do you want to transform it, possible values:
|
||||
* - upper: Uppercase the string.
|
||||
* - lower: lowercase the string.
|
||||
* - ucfirst: Make the first char uppercase.
|
||||
* - ucwords: Make each word in the string uppercase.
|
||||
*
|
||||
* @return string
|
||||
* The transformed string.
|
||||
*/
|
||||
function image_effect_text_case_transform($string, $option) {
|
||||
global $multibyte;
|
||||
|
||||
switch ($option) {
|
||||
default:
|
||||
return $string;
|
||||
case 'upper':
|
||||
return drupal_strtoupper($string);
|
||||
case 'lower':
|
||||
return drupal_strtolower($string);
|
||||
case 'ucfirst':
|
||||
return drupal_strtoupper(drupal_substr($string, 0, 1)) . drupal_substr($string, 1);
|
||||
case 'ucwords':
|
||||
if ($multibyte == UNICODE_MULTIBYTE) {
|
||||
return mb_convert_case($string, MB_CASE_TITLE);
|
||||
}
|
||||
else {
|
||||
return ucwords($string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -6,9 +6,8 @@ core = 7.x
|
||||
dependencies[] = image
|
||||
dependencies[] = imagecache_actions
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+3
-4
@@ -8,9 +8,8 @@ dependencies[] = image_effects_text
|
||||
dependencies[] = imagecache_canvasactions
|
||||
dependencies[] = system_stream_wrapper
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
README for the Image styleds admin Drupal module
|
||||
------------------------------------------------
|
||||
README for the Image styles admin Drupal module
|
||||
-----------------------------------------------
|
||||
|
||||
Project page: https://drupal.org/project/imagecache_actions
|
||||
|
||||
@@ -14,14 +14,13 @@ Release notes for 7.x-1.x-dev
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The Image style admin module extends the administrative interface for image
|
||||
The Image styles admin module extends the administrative interface for image
|
||||
styles by providing additional features.
|
||||
|
||||
Currently a duplicate, import and export image style feature are implemented.
|
||||
More features may be added in the future. These features typically allow you to
|
||||
more easily handle image styles. It allows us to more easily set up
|
||||
a test/showcase sute of styles. Finally, it allows everybody to test D8 image
|
||||
module features in real life.
|
||||
more easily handle image styles. It allows us to more easily set up a
|
||||
test/showcase suite of styles.
|
||||
|
||||
This module is not a replacement for the features module
|
||||
(https://drupal.org/project/features). If you are serious about configuration
|
||||
@@ -30,9 +29,3 @@ management and want to distribute styles to other systems, use features.
|
||||
Use this module for 1 time export/imports between different sites, "copy &
|
||||
paste" reuse within a site, and when reporting issues to the imagecache_actions
|
||||
issue queue.
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
Solving errors in the core image handling?
|
||||
- [#1554074]: scale does not work with imagemagick when dimensions are unknown?
|
||||
|
||||
+35
-38
@@ -117,7 +117,7 @@ function image_styles_admin_export_form($form, $form_state, $style) {
|
||||
'#type' => 'textarea',
|
||||
'#rows' => 5,
|
||||
'#title' => t('Image style export data'),
|
||||
'#default_value' => image_styles_admin_export_serialize($style),
|
||||
'#default_value' => image_styles_admin_style_to_string($style),
|
||||
'#attributes' => array('readonly' =>'readonly'),
|
||||
'#description' => t('Copy the contents of this field to the clipboard and, on another site, paste it in the textarea of an %page_title page.',
|
||||
array('%page_title' => t('Import image style'))),
|
||||
@@ -178,16 +178,16 @@ function image_styles_admin_import_form_submit($form, &$form_state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes image style data so it can be exported.
|
||||
* Converts image style data into a json string so it can be exported.
|
||||
*
|
||||
* @param array $style
|
||||
* An image style array.
|
||||
*
|
||||
* @return string
|
||||
* The serialized image style. Keys that are not needed for import are not
|
||||
* serialized.
|
||||
* The image style converted to a string. Keys that are not needed for import
|
||||
* are not serialized.
|
||||
*/
|
||||
function image_styles_admin_export_serialize($style) {
|
||||
function image_styles_admin_style_to_string($style) {
|
||||
$style = array_intersect_key($style, array('name' => 0, 'label' => 0, 'effects' => 0));
|
||||
foreach ($style['effects'] as &$effect) {
|
||||
$effect = array_intersect_key($effect, array('weight' => 0, 'name' => 0, 'data' => 0));
|
||||
@@ -198,16 +198,14 @@ function image_styles_admin_export_serialize($style) {
|
||||
$value = image_styles_admin_unify_newlines($value);
|
||||
}
|
||||
});
|
||||
return serialize($style);
|
||||
return json_encode($style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unifies newlines in the string to the Unix newline standard.
|
||||
*
|
||||
* #2636314: textareas may convert newlines to the underlying OS style: convert
|
||||
* all new lines to Unix style before unserializing. As string length is in the
|
||||
* serialized data, we must ensure that we also do this on each array value
|
||||
* before serializing.
|
||||
* all new lines to Unix style before stringifying an image style.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
@@ -220,17 +218,41 @@ function image_styles_admin_unify_newlines($str) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unserializes and validates a string into image style data.
|
||||
* Decodes and validates a json string into image style data.
|
||||
*
|
||||
* Some notes on any security implications for creating styles like this:
|
||||
* - json_decode() is considered safe regardless of the contents give to it.
|
||||
* - Not expected array entries are subsequently removed (array_intersect_key)
|
||||
* thus the return will not contain unexpected array entries
|
||||
* - Values with known types are checked.
|
||||
* - Effect data array is not checked as it cannot be checked. Possibly unsafe
|
||||
* but:
|
||||
* - Proper checking and/or converting to int/float/bool while processing an
|
||||
* image derivative is the responsibility of the image effect.
|
||||
* - Effect data is only shown to a user on the edit form and in the image
|
||||
* effect summary theme. Proper escaping and/or converting to int/float/bool
|
||||
* in the theme before rendering it is again the responsibility of the image
|
||||
* effect. On the form it is the form api that will do so.
|
||||
* - Effect data may contain PHP code and if the image effect is allowing this
|
||||
* it may get [php_]eval()'ed. The image effects themselves should check for
|
||||
* the 'use PHP for settings' permission on the create/edit form and check
|
||||
* that the PHP module is enabled on execution (that is: during image
|
||||
* derivative creation).
|
||||
* However, we cannot do so on importing as we cannot know if the imported
|
||||
* image style contains image effects that allow PHP code. Therefore, we use a
|
||||
* separate access right for importing styles that is to be considered having
|
||||
* the same security implications as the 'use PHP for settings' right (from
|
||||
* the PHP module) and thus should only be given to highly trusted users.
|
||||
*
|
||||
* @param string $import
|
||||
* The string representation of a @see serialize()'d image style array.
|
||||
* The json representation of an image style array.
|
||||
*
|
||||
* @return array|false
|
||||
* An image style array or false if the string could not be unserialized into
|
||||
* An image style array or false if the string could not be decoded into
|
||||
* image style data.
|
||||
*/
|
||||
function image_styles_admin_import_extract_style($import) {
|
||||
$style = unserialize($import);
|
||||
$style = json_decode($import, TRUE);
|
||||
|
||||
// Check if the contents of the textarea could be unserialized into an array.
|
||||
if (!is_array($style)) {
|
||||
@@ -280,30 +302,5 @@ function image_styles_admin_import_extract_style($import) {
|
||||
}
|
||||
}
|
||||
|
||||
// @todo: are there any security implications for creating styles like this?
|
||||
// - Unserialize() is save in itself: it only creates data (except possibly
|
||||
// for__wakeup(), but that can only be in already existing code: safe
|
||||
// - Not expected array entries are removed (array_intersect_key): safe
|
||||
// - Basic types are checked: safe
|
||||
// - Effect data array is not checked. Possibly unsafe?! The effect data array
|
||||
// contains the effect parameters. Normally these are entered and validated
|
||||
// via a form and subsequently saved in the database (serialized as here).
|
||||
// The form validation is not executed on import and thus the data may
|
||||
// contain invalid values. This is acceptable as it can also be done by
|
||||
// operating directly on the database. In Drupal this is not normally
|
||||
// checked for during processing: error messages will make clear that the
|
||||
// data has been played with. Can incorrect data be abused? It may contain:
|
||||
// - incorrect types: we do not know the data structure of the various
|
||||
// effects, so we cannot check that and have to accept it as it comes.
|
||||
// Effects should check_plain in summary theme and convert to int/float
|
||||
// whenever possible before using it in commands.
|
||||
// - PHP code, but that may be valid content for the text or custom effects:
|
||||
// Effects should check_plain in summary theme and convert to int/float
|
||||
// whenever possible before using it in commands.
|
||||
// @todo: if the style contains an effect that contains PHP code, the user
|
||||
// should need the 'use PHP for settings' permission.
|
||||
// - HTML and or JS code: when used as parameter, this normally won't hurt.
|
||||
// When showing on the screen (summary theme), proper escaping should
|
||||
// suffice and is needed anyway: responsibility of effect.
|
||||
return $style;
|
||||
}
|
||||
|
||||
+3
-4
@@ -5,9 +5,8 @@ core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Rebuild the menu.
|
||||
*/
|
||||
function image_styles_admin_update_7001(&$sandbox) {
|
||||
menu_rebuild();
|
||||
}
|
||||
+27
-2
@@ -3,6 +3,25 @@
|
||||
* @file Hook and callback implementations that must be available at all times.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function image_styles_admin_permission() {
|
||||
return array(
|
||||
'import image styles' => array(
|
||||
'title' => t('Import image styles.') ,
|
||||
'restrict access' => TRUE,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines access to the import image style form for the current user.
|
||||
*/
|
||||
function image_styles_admin_access() {
|
||||
return user_access('import image styles') && user_access('administer image styles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
@@ -29,7 +48,7 @@ function image_styles_admin_menu() {
|
||||
'description' => 'Import an image style.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('image_styles_admin_import_form'),
|
||||
'access arguments' => array('administer image styles'),
|
||||
'access callback' => 'image_styles_admin_access',
|
||||
'type' => MENU_LOCAL_ACTION,
|
||||
'weight' => 3,
|
||||
'file' => 'image_styles_admin.inc',
|
||||
@@ -41,9 +60,15 @@ function image_styles_admin_menu() {
|
||||
* Implements hook_preprocess_HOOK for theme image_style_list.
|
||||
*/
|
||||
function image_styles_admin_preprocess_image_style_list(&$variables) {
|
||||
// Sort the image styles by name.
|
||||
uasort($variables['styles'], function ($a, $b) {
|
||||
return strcasecmp($a['label'], $b['label']);
|
||||
});
|
||||
|
||||
// Tell imagecache_actions_preprocess_table to preprocess the next call to
|
||||
// theme_table()
|
||||
// theme_table().
|
||||
$image_styles = array_values($variables['styles']);
|
||||
|
||||
image_styles_admin_preprocess_table($image_styles);
|
||||
|
||||
// Add CSS and JS files.
|
||||
|
||||
@@ -5,9 +5,8 @@ core = 7.x
|
||||
|
||||
dependencies[] = image
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
@@ -8,9 +8,8 @@ dependencies[] = system_stream_wrapper
|
||||
|
||||
features[image][] = 'corners_combo'
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-19
|
||||
version = "7.x-1.7"
|
||||
; Information added by Drupal.org packaging script on 2020-06-16
|
||||
version = "7.x-1.12"
|
||||
core = "7.x"
|
||||
project = "imagecache_actions"
|
||||
datestamp = "1455872655"
|
||||
|
||||
datestamp = "1592294437"
|
||||
|
||||
@@ -19,8 +19,8 @@ function imagecache_actions_pos_form(array $data) {
|
||||
);
|
||||
$data = array_merge($defaults, (array) $data);
|
||||
|
||||
$description1 = t('Enter an offset in pixels (e.g. 10, 10px), a percentage (e.g. 25%), or one of the keywords: <em>left</em>, <em>center</em>, or <em>right</em> wih an optional offset (e.g. center, right - 10%).');
|
||||
$description2 = t('Enter an offset in pixels (e.g. 10, 10px), a percentage (e.g. 25%), or one of the keywords: <em>top</em>, <em>center</em>, or <em>bottom</em> wih an optional offset (e.g. center, bottom - 10%).');
|
||||
$description1 = t('Enter an offset in pixels (e.g. 10, 10px), a percentage (e.g. 25%), or one of the keywords: <em>left</em>, <em>center</em>, or <em>right</em> with an optional offset (e.g. center, right - 10%).');
|
||||
$description2 = t('Enter an offset in pixels (e.g. 10, 10px), a percentage (e.g. 25%), or one of the keywords: <em>top</em>, <em>center</em>, or <em>bottom</em> with an optional offset (e.g. center, bottom - 10%).');
|
||||
$form = array(
|
||||
'xpos' => array(
|
||||
'#type' => 'textfield',
|
||||
|
||||
@@ -143,7 +143,7 @@ function imagecache_actions_get_style_label($style_name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array with context information about the image.
|
||||
* Returns an array with context information about the image.
|
||||
*
|
||||
* This information is called by effects that need contextual information or
|
||||
* that allow custom PHP:
|
||||
@@ -192,27 +192,33 @@ function imagecache_actions_get_image_context($image, $data) {
|
||||
+ file_get_file_references($managed_file, NULL, FIELD_LOAD_CURRENT, 'file');
|
||||
|
||||
if ($references) {
|
||||
// Load referring entities.
|
||||
// Load referring entities., keep track of 1st reference separately.
|
||||
$entity_type_first = '';
|
||||
$field_name_first = '';
|
||||
foreach ($references as $field_name => $field_references) {
|
||||
foreach ($field_references as $entity_type => $entity_stubs) {
|
||||
$image_context['referring_entities'][$field_name][$entity_type] = entity_load($entity_type, array_keys($entity_stubs));
|
||||
$entities = entity_load($entity_type, array_keys($entity_stubs));
|
||||
if (!empty($entities)) {
|
||||
$image_context['referring_entities'][$field_name][$entity_type] = $entities;
|
||||
// Make it easy to access the '1st' entity and its referring image
|
||||
// field, part 1: entity.
|
||||
if (empty($entity_type_first)) {
|
||||
$entity_type_first = $entity_type;
|
||||
$field_name_first = $field_name;
|
||||
$image_context['entity'] = reset($entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make it easy to access the '1st' entity and its referring image field.
|
||||
reset($image_context['referring_entities']);
|
||||
list($field_name, $field_references) = each($image_context['referring_entities']);
|
||||
reset($field_references);
|
||||
list($entity_type, $entities) = each($field_references);
|
||||
reset($entities);
|
||||
list(, $image_context['entity']) = each($entities);
|
||||
// Make it easy to access the '1st' entity and its referring image field,
|
||||
// part 2: image field.
|
||||
/** @var array|false $image_field */
|
||||
$image_field = field_get_items($entity_type, $image_context['entity'], $field_name);
|
||||
$image_field = field_get_items($entity_type_first, $image_context['entity'], $field_name_first);
|
||||
if ($image_field) {
|
||||
// Get referring item.
|
||||
foreach ($image_field as $image_field_value) {
|
||||
if ($image_field_value['fid'] === $managed_file->fid) {
|
||||
// @todo: file_field as well or just ignore the type of field?
|
||||
$image_context['image_field'] = $image_field_value;
|
||||
break;
|
||||
}
|
||||
@@ -224,6 +230,53 @@ function imagecache_actions_get_image_context($image, $data) {
|
||||
return $image_context;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns information about the context, image style and image effect id, of
|
||||
* the current image effect.
|
||||
*
|
||||
* Note that this information is not alterable, that is, it will not have any
|
||||
* effect on the rest of the derivative image generation process including its
|
||||
* subsequent effects.
|
||||
*
|
||||
* This information is called by effects that may need contextual information or
|
||||
* that allow custom PHP:
|
||||
* - Custom action.
|
||||
* - Text from image alt or title.
|
||||
* - Text with tokens.
|
||||
* - Text from PHP code.
|
||||
*
|
||||
* This information is fetched by traversing the backtrace, looking for known
|
||||
* functions that have the image style or effect as argument..
|
||||
*
|
||||
* @return array
|
||||
* Array with keys 'image_style' and 'image_effect_id' pointing to the current
|
||||
* image style (array) resp. image effect id (int).
|
||||
*/
|
||||
function imagecache_actions_get_image_effect_context() {
|
||||
$result = array();
|
||||
$backtrace = debug_backtrace();
|
||||
|
||||
foreach ($backtrace as $function_call) {
|
||||
if ($function_call['function'] && $function_call['function'] === 'image_effect_apply') {
|
||||
$result['image_effect_id'] = isset($function_call['args'][1]['ieid']) ? $function_call['args'][1]['ieid'] : NULL;
|
||||
}
|
||||
else if ($function_call['function'] && $function_call['function'] === 'image_style_create_derivative') {
|
||||
$result['image_style'] = isset($function_call['args'][0]) ? $function_call['args'][0] : NULL;
|
||||
}
|
||||
|
||||
if (count($result) === 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$result += array(
|
||||
'image_effect_id' => NULL,
|
||||
'image_style' => NULL,
|
||||
);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given two imageapi objects with dimensions, and some positioning values,
|
||||
* calculate a new x,y for the layer to be placed at.
|
||||
@@ -369,11 +422,14 @@ function imagecache_actions_calculate_offset($keyword, $value, $base_size, $laye
|
||||
}
|
||||
|
||||
// Handle % values.
|
||||
if (substr($value, strlen($value) - 1, 1) == '%') {
|
||||
$value = intval($value / 100 * $base_size);
|
||||
if (substr($value, -1) === '%') {
|
||||
// Explicitly convert $value to prevent warnings in PHP 7.1.
|
||||
$value = intval((int) $value / 100 * $base_size);
|
||||
$offset = -1 * ($layer_size / 2);
|
||||
}
|
||||
$value = $base + ($direction * $value);
|
||||
// $value may contain 'px' at the end: explicitly convert to prevent warnings
|
||||
// in PHP 7.1.
|
||||
$value = $base + ($direction * (int) $value);
|
||||
|
||||
// Add any extra offset to position the item.
|
||||
return $value + $offset;
|
||||
@@ -389,16 +445,16 @@ function imagecache_actions_calculate_offset($keyword, $value, $base_size, $laye
|
||||
* A string specifing an RGB color in the formats:
|
||||
* '#ABC','ABC','#ABCD','ABCD','#AABBCC','AABBCC','#AABBCCDD','AABBCCDD'
|
||||
*
|
||||
* @return array
|
||||
* @return array|false
|
||||
* An array with four elements for red, green, blue, and alpha.
|
||||
*/
|
||||
function imagecache_actions_hex2rgba($hex) {
|
||||
$hex = ltrim($hex, '#');
|
||||
if (preg_match('/^[0-9a-f]{3}$/i', $hex)) {
|
||||
// 'FA3' is the same as 'FFAA33' so r=FF, g=AA, b=33
|
||||
$r = str_repeat($hex{0}, 2);
|
||||
$g = str_repeat($hex{1}, 2);
|
||||
$b = str_repeat($hex{2}, 2);
|
||||
$r = str_repeat($hex[0], 2);
|
||||
$g = str_repeat($hex[1], 2);
|
||||
$b = str_repeat($hex[2], 2);
|
||||
$a = '0';
|
||||
}
|
||||
elseif (preg_match('/^[0-9a-f]{6}$/i', $hex)) {
|
||||
@@ -412,10 +468,10 @@ function imagecache_actions_hex2rgba($hex) {
|
||||
}
|
||||
elseif (preg_match('/^[0-9a-f]{4}$/i', $hex)) {
|
||||
// 'FA37' is the same as 'FFAA3377' so r=FF, g=AA, b=33, a=77
|
||||
$r = str_repeat($hex{0}, 2);
|
||||
$g = str_repeat($hex{1}, 2);
|
||||
$b = str_repeat($hex{2}, 2);
|
||||
$a = str_repeat($hex{3}, 2);
|
||||
$r = str_repeat($hex[0], 2);
|
||||
$g = str_repeat($hex[1], 2);
|
||||
$b = str_repeat($hex[2], 2);
|
||||
$a = str_repeat($hex[3], 2);
|
||||
}
|
||||
else {
|
||||
// error: invalid hex string, @todo: set form error.
|
||||
@@ -468,12 +524,13 @@ function imagecache_actions_keyword_filter($value, $base_size, $layer_size) {
|
||||
* Computes a length based on a length specification and an actual length.
|
||||
*
|
||||
* Examples:
|
||||
* (50, 400) returns 50; (50%, 400) returns 200;
|
||||
* (50, 400) returns 50; (50px, 400) returns 50; (50%, 400) returns 200;
|
||||
* (50, null) returns 50; (50%, null) returns null;
|
||||
* (null, null) returns null; (null, 100) returns null.
|
||||
*
|
||||
* @param string|null $length_specification
|
||||
* The length specification. An integer constant or a % specification.
|
||||
* The length specification. An integer constant optionally followed by 'px'
|
||||
* or '%'.
|
||||
* @param int|null $current_length
|
||||
* The current length. May be null.
|
||||
*
|
||||
@@ -483,5 +540,9 @@ function imagecache_actions_percent_filter($length_specification, $current_lengt
|
||||
if (strpos($length_specification, '%') !== FALSE) {
|
||||
$length_specification = $current_length !== NULL ? str_replace('%', '', $length_specification) * 0.01 * $current_length : NULL;
|
||||
}
|
||||
else {
|
||||
// Strips 'px' if available.
|
||||
$length_specification = (int) $length_specification;
|
||||
}
|
||||
return $length_specification;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user