|
@@ -1,14 +1,14 @@
|
|
|
<?php
|
|
|
/**
|
|
|
- * @file Helper functions for the text2canvas action for imagecache
|
|
|
+ * @file Helper functions for the canvas actions for imagecache
|
|
|
*
|
|
|
* @author Dan Morrison http://coders.co.nz
|
|
|
*
|
|
|
* Individually configurable rounded corners logic contributed by canaryMason
|
|
|
- * 2009 03 http://drupal.org/node/402112
|
|
|
+ * 2009 03 https://drupal.org/node/402112
|
|
|
*
|
|
|
* Better algorithm for trimming rounded corners from donquixote
|
|
|
- * 2009 09 http://drupal.org/node/564036
|
|
|
+ * 2009 09 https://drupal.org/node/564036
|
|
|
*
|
|
|
*/
|
|
|
|
|
@@ -22,18 +22,16 @@ if (!function_exists('imagecache_actions_keyword_filter')) {
|
|
|
module_load_include('inc', 'imagecache_actions', 'utility');
|
|
|
}
|
|
|
|
|
|
-////////////////////////////////////////////////
|
|
|
-// IMAGEMASK
|
|
|
-
|
|
|
/**
|
|
|
- * Implements the form callback for the image mask effect.
|
|
|
+ * Image effect form callback for the image mask effect.
|
|
|
*
|
|
|
* @param array $data
|
|
|
- * array of settings for this action.
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
* @return array
|
|
|
- * A form definition.
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
-function canvasactions_imagemask_form($data) {
|
|
|
+function canvasactions_imagemask_form(array $data) {
|
|
|
// @todo: add offset/positioning/scaling support - currently the mask is applied to the supplied image without resizing and positioned at (0,0)
|
|
|
$form = array();
|
|
|
$form['effect_help_text'] = array(
|
|
@@ -52,22 +50,31 @@ function canvasactions_imagemask_form($data) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements the summary theme function for the image mask effect.
|
|
|
+ * Implements theme_hook() for the image mask 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_imagemask_summary($variables) {
|
|
|
+function theme_canvasactions_imagemask_summary(array $variables) {
|
|
|
$data = $variables['data'];
|
|
|
return 'file: ' . $data['path'];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implement the effect callback for the image mask effect.
|
|
|
+ * Image effect callback for the image mask effect.
|
|
|
*
|
|
|
- * @param object $image
|
|
|
+ * @param stdClass $image
|
|
|
* @param array $data
|
|
|
*
|
|
|
* @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_imagemask_image(&$image, $data = array()) {
|
|
|
+function canvasactions_imagemask_effect(stdClass $image, array $data) {
|
|
|
$mask = imagecache_actions_image_load($data['path'], $image->toolkit);
|
|
|
if ($mask) {
|
|
|
// @todo: (sydneyshan) Consider best way to add offset support - I assume we
|
|
@@ -83,21 +90,24 @@ function canvasactions_imagemask_image(&$image, $data = array()) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements the image mask effect using the GD toolkit.
|
|
|
+ * GD toolkit specific implementation of the image mask effect.
|
|
|
*
|
|
|
- * $image object
|
|
|
+ * @param stdClass $image
|
|
|
* Image object containing the GD image resource to operate on.
|
|
|
- * $mask object
|
|
|
+ * @param stdClass $mask
|
|
|
* An image object containing the image to use as mask.
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function image_gd_imagemask($image, $mask) {
|
|
|
+function image_gd_imagemask(stdClass $image, stdClass $mask) {
|
|
|
$newPicture = imagecreatetruecolor($image->info['width'], $image->info['height']);
|
|
|
imagesavealpha($newPicture, TRUE);
|
|
|
imagealphablending($newPicture, TRUE);
|
|
|
$transparent = imagecolorallocatealpha($newPicture, 0, 0, 0, 127);
|
|
|
imagefill($newPicture, 0, 0, $transparent);
|
|
|
|
|
|
- // Perform pixel-based alpha map application
|
|
|
+ // Perform pixel-based alpha map application.
|
|
|
for ($x = 0; $x < $image->info['width']; $x++) {
|
|
|
for ($y = 0; $y < $image->info['height']; $y++) {
|
|
|
// Deal with images with mismatched sizes
|
|
@@ -113,7 +123,7 @@ function image_gd_imagemask($image, $mask) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Copy back to original picture
|
|
|
+ // Copy back to original picture.
|
|
|
imagedestroy($image->resource);
|
|
|
$image->resource = $newPicture;
|
|
|
|
|
@@ -122,30 +132,32 @@ function image_gd_imagemask($image, $mask) {
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * Implements the image mask effect using the imagemagick toolkit.
|
|
|
+ * Imagemagick toolkit specific implementation of the image mask effect.
|
|
|
*
|
|
|
- * $image object
|
|
|
- * Image object containing a.o. the image to operate on.
|
|
|
- * $mask object
|
|
|
+ * @param stdClass $image
|
|
|
+ * Image object containing the image resource to operate on.
|
|
|
+ * @param stdClass $mask
|
|
|
* An image object containing the image to use as mask.
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function image_imagemagick_imagemask($image, $mask) {
|
|
|
- $image->ops[] = escapeshellarg($mask->source) . ' -alpha Off -compose CopyOpacity -composite';
|
|
|
+function image_imagemagick_imagemask(stdClass $image, stdClass $mask) {
|
|
|
+ $image->ops[] = escapeshellarg($mask->source);
|
|
|
+ $image->ops[] = '-alpha Off -compose CopyOpacity -composite';
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
-////////////////////////////////////////////////
|
|
|
-
|
|
|
-
|
|
|
/**
|
|
|
- * Implementation of imagecache_hook_form()
|
|
|
+ * Image effect form callback for the define canvas effect.
|
|
|
*
|
|
|
- * Settings for preparing a canvas.
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
*
|
|
|
- * @param $data array of settings for this action
|
|
|
- * @return a form definition
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
-function canvasactions_definecanvas_form($data) {
|
|
|
+function canvasactions_definecanvas_form(array $data) {
|
|
|
module_load_include('inc', 'imagecache_actions', 'utility-color');
|
|
|
$defaults = array(
|
|
|
'RGB' => array(
|
|
@@ -165,13 +177,12 @@ function canvasactions_definecanvas_form($data) {
|
|
|
'bottomdiff' => '',
|
|
|
),
|
|
|
);
|
|
|
- $data = array_merge($defaults, (array) $data);
|
|
|
+ $data += $defaults;
|
|
|
|
|
|
$form = array(
|
|
|
'RGB' => imagecache_rgb_form($data['RGB']),
|
|
|
'help' => array(
|
|
|
- '#type' => 'markup',
|
|
|
- '#value' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'),
|
|
|
+ '#markup' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'),
|
|
|
'#prefix' => '<p>',
|
|
|
'#suffix' => '</p>',
|
|
|
),
|
|
@@ -188,8 +199,7 @@ function canvasactions_definecanvas_form($data) {
|
|
|
'#collapsible' => TRUE,
|
|
|
'#title' => 'Exact size',
|
|
|
'help' => array(
|
|
|
- '#type' => 'markup',
|
|
|
- '#value' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'),
|
|
|
+ '#markup' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'),
|
|
|
'#prefix' => '<p>',
|
|
|
'#suffix' => '</p>',
|
|
|
),
|
|
@@ -218,8 +228,9 @@ function canvasactions_definecanvas_form($data) {
|
|
|
'#collapsible' => TRUE,
|
|
|
'#title' => t('Relative size'),
|
|
|
'help' => array(
|
|
|
- '#type' => 'markup',
|
|
|
- '#value' => '<p>' . t('Set the canvas to a relative size, based on the current image dimensions. Use to add simple borders or expand by a fixed amount. Negative values may crop the image.') . '</p>',
|
|
|
+ '#markup' => t('Set the canvas to a relative size, based on the current image dimensions. Use to add simple borders or expand by a fixed amount. Negative values may crop the image.'),
|
|
|
+ '#prefix' => '<p>',
|
|
|
+ '#suffix' => '</p>',
|
|
|
),
|
|
|
'leftdiff' => array(
|
|
|
'#type' => 'textfield',
|
|
@@ -258,10 +269,19 @@ function canvasactions_definecanvas_form($data) {
|
|
|
return $form;
|
|
|
}
|
|
|
|
|
|
+/** @noinspection PhpDocMissingThrowsInspection */
|
|
|
/**
|
|
|
- * Implementation of theme_hook() for imagecache_ui.module
|
|
|
+ * Implements theme_hook() for the define canvas 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_definecanvas_summary($variables) {
|
|
|
+function theme_canvasactions_definecanvas_summary(array $variables) {
|
|
|
$data = $variables['data'];
|
|
|
if ($data['exact']['width'] || $data['exact']['height']) {
|
|
|
$w = !empty($data['exact']['width']) ? $data['exact']['width'] : '100%';
|
|
@@ -276,28 +296,22 @@ function theme_canvasactions_definecanvas_summary($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;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implementation of hook_image()
|
|
|
- *
|
|
|
- * Creates a solid background canvas
|
|
|
- *
|
|
|
- * Process the imagecache action on the passed image
|
|
|
- *
|
|
|
- * @param $image
|
|
|
- * array defining an image file, including :
|
|
|
- *
|
|
|
- * $image- >source as the filename,
|
|
|
+ * Image effect callback for the define canvas effect.
|
|
|
*
|
|
|
- * $image->info array
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
*
|
|
|
- * $image->resource handle on the image object
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_definecanvas_effect($image, $data) {
|
|
|
+function canvasactions_definecanvas_effect(stdClass $image, array $data) {
|
|
|
// May be given either exact or relative dimensions.
|
|
|
if ($data['exact']['width'] || $data['exact']['height']) {
|
|
|
// Allows only one dimension to be used if the other is unset.
|
|
@@ -308,69 +322,53 @@ function canvasactions_definecanvas_effect($image, $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'];
|
|
|
+ // Calculate relative size.
|
|
|
+ $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)
|
|
|
+ // Convert 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);
|
|
|
}
|
|
|
|
|
|
- // All the maths is done, now defer to the api toolkits;
|
|
|
- $data['targetsize'] = $targetsize;
|
|
|
+ // All the math is done, now defer to the toolkit in use.
|
|
|
+ $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;
|
|
|
}
|
|
|
|
|
|
-function canvasactions_definecanvas_dimensions(array &$dimensions, array $data) {
|
|
|
- // May be given either exact or relative dimensions.
|
|
|
- if ($data['exact']['width'] || $data['exact']['height']) {
|
|
|
- // Allows only one dimension to be used if the other is unset.
|
|
|
- if (!$data['exact']['width']) {
|
|
|
- $data['exact']['width'] = $dimensions['width'];
|
|
|
- }
|
|
|
- if (!$data['exact']['height']) {
|
|
|
- $data['exact']['height'] = $dimensions['height'];
|
|
|
- }
|
|
|
-
|
|
|
- $dimensions['width'] = imagecache_actions_percent_filter($data['exact']['width'], $dimensions['width']);
|
|
|
- $dimensions['height'] = imagecache_actions_percent_filter($data['exact']['height'], $dimensions['height']);
|
|
|
- }
|
|
|
- else {
|
|
|
- // calculate relative size
|
|
|
- $dimensions['width'] = $dimensions['width'] + $data['relative']['leftdiff'] + $data['relative']['rightdiff'];
|
|
|
- $dimensions['height'] = $dimensions['height'] + $data['relative']['topdiff'] + $data['relative']['bottomdiff'];
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
- * Draw a color (or transparency) behind an image
|
|
|
+ * GD toolkit specific implementation of the define canvas effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
+ * The parameters for this effect. $data['targetsize'] is an array expected to
|
|
|
+ * contain a width, height and a left, top.
|
|
|
*
|
|
|
- * $targetsize is an array expected to contain a width,height and a left,top
|
|
|
- * offset.
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function image_gd_definecanvas($image, $data = array()) {
|
|
|
- $targetsize = $data['targetsize'];
|
|
|
+function image_gd_definecanvas(stdClass $image, array $data) {
|
|
|
+ $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);
|
|
@@ -379,24 +377,22 @@ function image_gd_definecanvas($image, $data = array()) {
|
|
|
$background = imagecolorallocatealpha($newcanvas, $RGB['red'], $RGB['green'], $RGB['blue'], $RGB['alpha']);
|
|
|
}
|
|
|
else {
|
|
|
- // No color, attempt transparency, assume white
|
|
|
+ // No color, attempt transparency, assume white.
|
|
|
$background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127);
|
|
|
}
|
|
|
- imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background);
|
|
|
- # imagealphablending($newcanvas, TRUE);
|
|
|
+ imagefilledrectangle($newcanvas, 0, 0, $target_size['width'], $target_size['height'], $background);
|
|
|
|
|
|
if ($data['under']) {
|
|
|
- $canvas_object = (object) array(
|
|
|
- 'resource' => $newcanvas,
|
|
|
- 'info' => array(
|
|
|
- 'width' => $targetsize['width'],
|
|
|
- 'height' => $targetsize['height'],
|
|
|
+ $canvas_object = new stdClass();
|
|
|
+ $canvas_object->resource = $newcanvas;
|
|
|
+ $canvas_object->info = array(
|
|
|
+ 'width' => $target_size['width'],
|
|
|
+ 'height' => $target_size['height'],
|
|
|
'mime_type' => $image->info['mime_type'],
|
|
|
'extension' => $image->info['extension'],
|
|
|
- ),
|
|
|
- 'toolkit' => $image->toolkit,
|
|
|
- );
|
|
|
- image_overlay($image, $canvas_object, $targetsize['left'], $targetsize['top'], 100, TRUE);
|
|
|
+ );
|
|
|
+ $canvas_object->toolkit = $image->toolkit;
|
|
|
+ image_overlay($image, $canvas_object, $target_size['left'], $target_size['top'], 100, TRUE);
|
|
|
}
|
|
|
else {
|
|
|
$image->resource = $newcanvas;
|
|
@@ -405,45 +401,83 @@ function image_gd_definecanvas($image, $data = array()) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Draw a color (or transparency) behind an image
|
|
|
- * $targetsize is an array expected to contain a width,height and a left,top
|
|
|
- * offset.
|
|
|
+ * Imagemagick toolkit specific implementation of the define canvas effect.
|
|
|
*
|
|
|
- * See http://www.imagemagick.org/script/command-line-options.php#extent
|
|
|
- * @todo: reset gravity?
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
+ * The parameters for this effect. $data['targetsize'] is an array expected to
|
|
|
+ * contain a width, height and a left, top.
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
+ *
|
|
|
+ * @see http://www.imagemagick.org/script/command-line-options.php#extent
|
|
|
*/
|
|
|
-function image_imagemagick_definecanvas($image, $data = array()) {
|
|
|
- $backgroundcolor = $data['RGB']['HEX'] != '' ? '#' . $data['RGB']['HEX'] : 'None';
|
|
|
+function image_imagemagick_definecanvas(stdClass $image, $data) {
|
|
|
+ // Reset any gravity settings from earlier effects.
|
|
|
+ $image->ops[] = '-gravity None';
|
|
|
+
|
|
|
+ $backgroundcolor = $data['RGB']['HEX'] != '' ? '#' . ltrim($data['RGB']['HEX'], '#') : 'None';
|
|
|
$image->ops[] = '-background ' . escapeshellarg($backgroundcolor);
|
|
|
|
|
|
$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 $geometry";
|
|
|
+ $image->ops[] = '-extent ' . escapeshellarg($geometry);
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
-////////////////////////////////////////////////
|
|
|
+/**
|
|
|
+ * Image dimensions callback for the define canvas effect.
|
|
|
+ *
|
|
|
+ * @param array $dimensions
|
|
|
+ * Dimensions to be modified - an associative array containing the items
|
|
|
+ * 'width' and 'height' (in pixels).
|
|
|
+ * @param array $data
|
|
|
+ * An associative array containing the effect data.
|
|
|
+ */
|
|
|
+function canvasactions_definecanvas_dimensions(array &$dimensions, array $data) {
|
|
|
+ // May be given either exact or relative dimensions.
|
|
|
+ if ($data['exact']['width'] || $data['exact']['height']) {
|
|
|
+ // Allows only one dimension to be used if the other is unset.
|
|
|
+ if (!$data['exact']['width']) {
|
|
|
+ $data['exact']['width'] = $dimensions['width'];
|
|
|
+ }
|
|
|
+ if (!$data['exact']['height']) {
|
|
|
+ $data['exact']['height'] = $dimensions['height'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $dimensions['width'] = imagecache_actions_percent_filter($data['exact']['width'], $dimensions['width']);
|
|
|
+ $dimensions['height'] = imagecache_actions_percent_filter($data['exact']['height'], $dimensions['height']);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // Calculate relative sizes (only possible if we have the current size).
|
|
|
+ if ($dimensions['width'] !== NULL) {
|
|
|
+ $dimensions['width'] = $dimensions['width'] + (int) $data['relative']['leftdiff'] + (int) $data['relative']['rightdiff'];
|
|
|
+ }
|
|
|
+ if ($dimensions['height'] !== NULL) {
|
|
|
+ $dimensions['height'] = $dimensions['height'] + (int) $data['relative']['topdiff'] + (int) $data['relative']['bottomdiff'];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
- * Place a given image under the current canvas
|
|
|
+ * Image effect form callback for the underlay (background) effect.
|
|
|
*
|
|
|
- * Implementation of imagecache_hook_form()
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
*
|
|
|
- * @param $data array of settings for this action
|
|
|
- * @return a form definition
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
-function canvasactions_canvas2file_form($data) {
|
|
|
-// if (image_get_toolkit() != 'gd') {
|
|
|
-// drupal_set_message('Overlays are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning');
|
|
|
-// }
|
|
|
-
|
|
|
+function canvasactions_canvas2file_form(array $data) {
|
|
|
$defaults = array(
|
|
|
'xpos' => '0',
|
|
|
'ypos' => '0',
|
|
@@ -484,7 +518,15 @@ function canvasactions_canvas2file_form($data) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implementation of theme_hook() for imagecache_ui.module
|
|
|
+ * Implements theme_hook() for the underlay (background) 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_canvas2file_summary($variables) {
|
|
|
$data = $variables['data'];
|
|
@@ -493,17 +535,15 @@ function theme_canvasactions_canvas2file_summary($variables) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Place the source image on the current background
|
|
|
+ * Image effect callback for the underlay (background) effect.
|
|
|
*
|
|
|
- * Implementation of hook_image()
|
|
|
- *
|
|
|
- * Note - this is currently incompatable with imagemagick, due to the way it
|
|
|
- * addresses $image->resource directly - a gd only thing.
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
*
|
|
|
- * @param $image
|
|
|
- * @param $data
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_canvas2file_image(&$image, $data = array()) {
|
|
|
+function canvasactions_canvas2file_effect(stdClass $image, array $data) {
|
|
|
$underlay = imagecache_actions_image_load($data['path'], $image->toolkit);
|
|
|
if ($underlay) {
|
|
|
// To handle odd sizes, we will resize/crop the background image to the
|
|
@@ -511,7 +551,7 @@ function canvasactions_canvas2file_image(&$image, $data = array()) {
|
|
|
// imagecopymerge, and the watermark library both do not allow overlays to
|
|
|
// be bigger than the target.
|
|
|
|
|
|
- // Adjust size
|
|
|
+ // Adjust size.
|
|
|
$crop_rules = array(
|
|
|
'xoffset' => 0,
|
|
|
'yoffset' => 0,
|
|
@@ -527,7 +567,7 @@ function canvasactions_canvas2file_image(&$image, $data = array()) {
|
|
|
// which will produce a 'cropped' image larger than the original.
|
|
|
// In this case, we need to calculate the position of the bg image
|
|
|
// in relation to the space it will occupy under the top layer
|
|
|
- #$crop_rules['xoffset'] = $underlay->info['width'] - $image->info['width'] ;
|
|
|
+ //$crop_rules['xoffset'] = $underlay->info['width'] - $image->info['width'] ;
|
|
|
|
|
|
$crop_rules['width'] = $image->info['width'];
|
|
|
$crop_rules['height'] = $image->info['height'];
|
|
@@ -549,14 +589,14 @@ function canvasactions_canvas2file_image(&$image, $data = array()) {
|
|
|
|
|
|
// Crop both before processing to avoid unwanted processing.
|
|
|
image_crop_effect($underlay, $crop_rules);
|
|
|
- # BUG - this doesn't position either
|
|
|
+ // @todo: BUG - this doesn't position either
|
|
|
// Actually this fails because imagecache_crop fills it with solid color when 'cropping' to a larger size.
|
|
|
- #imagecache_crop_image($image, $crop_rules);
|
|
|
- #dpm(get_defined_vars());
|
|
|
- // This func modifies the underlay image by ref, placing the current canvas on it
|
|
|
+ //imagecache_crop_image($image, $crop_rules);
|
|
|
+ //dpm(get_defined_vars());
|
|
|
+ // 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;
|
|
|
+ //$image->resource = $underlay->resource;
|
|
|
+ //$image = $underlay; //@todo: this is a no-op.
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
@@ -564,12 +604,12 @@ function canvasactions_canvas2file_image(&$image, $data = array()) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Image dimensions callback; canvas2file (underlay/background).
|
|
|
+ * Image dimensions callback for the underlay (background) effect.
|
|
|
*
|
|
|
* @param array $dimensions
|
|
|
* Dimensions to be modified - an associative array containing the items
|
|
|
* 'width' and 'height' (in pixels).
|
|
|
- * @param $data
|
|
|
+ * @param array $data
|
|
|
* An associative array containing the effect data.
|
|
|
*/
|
|
|
function canvasactions_canvas2file_dimensions(array &$dimensions, array $data) {
|
|
@@ -586,40 +626,50 @@ function canvasactions_canvas2file_dimensions(array &$dimensions, array $data) {
|
|
|
$dimensions['height'] = $underlay->info['height'];
|
|
|
break;
|
|
|
case 'minimum':
|
|
|
- $dimensions['width'] = isset($dimensions['width']) ? min($underlay->info['width'], $dimensions['width']) : NULL;
|
|
|
- $dimensions['height'] = isset($dimensions['height']) ? min($underlay->info['height'], $dimensions['height']) : NULL;
|
|
|
+ if ($dimensions['width'] !== NULL) {
|
|
|
+ $dimensions['width'] = min($underlay->info['width'], $dimensions['width']);
|
|
|
+ }
|
|
|
+ if ($dimensions['height'] !== NULL) {
|
|
|
+ $dimensions['height'] = min($underlay->info['height'], $dimensions['height']);
|
|
|
+ }
|
|
|
break;
|
|
|
case 'maximum':
|
|
|
- $dimensions['width'] = isset($dimensions['width']) ? max($underlay->info['width'], $dimensions['width']) : NULL;
|
|
|
- $dimensions['height'] = isset($dimensions['height']) ? max($underlay->info['height'], $dimensions['height']) : NULL;
|
|
|
- break;
|
|
|
+ if ($dimensions['width'] !== NULL) {
|
|
|
+ $dimensions['width'] = max($underlay->info['width'], $dimensions['width']);
|
|
|
+ }
|
|
|
+ if ($dimensions['height'] !== NULL) {
|
|
|
+ $dimensions['height'] = max($underlay->info['height'], $dimensions['height']);
|
|
|
+ }
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * Place a given image on top of the current canvas
|
|
|
+ * Image effect form callback for the overlay (watermark) effect.
|
|
|
*
|
|
|
- * Implementation of imagecache_hook_form()
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
*
|
|
|
- * @param $data array of settings for this action
|
|
|
- * @return a form definition
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
-function canvasactions_file2canvas_form($data) {
|
|
|
+function canvasactions_file2canvas_form(array $data) {
|
|
|
|
|
|
$defaults = array(
|
|
|
'xpos' => '',
|
|
|
'ypos' => '',
|
|
|
'alpha' => '100',
|
|
|
+ 'scale' => '',
|
|
|
'path' => '',
|
|
|
);
|
|
|
$data = array_merge($defaults, (array) $data);
|
|
|
|
|
|
$form = array(
|
|
|
'help' => array(
|
|
|
- '#type' => 'markup',
|
|
|
- '#value' => t('Note that using a transparent overlay that is larger than the source image may result in unwanted results - a solid background.'),
|
|
|
+ '#markup' => t('Note that using a non transparent overlay that is larger than the source image may result in unwanted results - a solid background.'),
|
|
|
),
|
|
|
);
|
|
|
$form += imagecache_actions_pos_form($data);
|
|
@@ -627,8 +677,19 @@ function canvasactions_file2canvas_form($data) {
|
|
|
'#type' => 'textfield',
|
|
|
'#title' => t('opacity'),
|
|
|
'#default_value' => $data['alpha'],
|
|
|
+ '#field_suffix' => t('%'),
|
|
|
'#size' => 6,
|
|
|
'#description' => t('Opacity: 0-100. <b>Warning:</b> Due to a limitation in the GD toolkit, using an opacity other than 100% requires the system to use an algorithm that\'s much slower than the built-in functions. If you want partial transparency, you are better to use an already-transparent png as the overlay source image.'),
|
|
|
+ '#element_validate' => array('imagecache_actions_validate_number_non_negative'),
|
|
|
+ );
|
|
|
+ $form['scale'] = array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('scale'),
|
|
|
+ '#default_value' => $data['scale'],
|
|
|
+ '#field_suffix' => t('%'),
|
|
|
+ '#size' => 6,
|
|
|
+ '#description' => t('Scales the overlay with respect to the source, thus not its own dimensions. Leave empty to use the original size of overlay image.'),
|
|
|
+ '#element_validate' => array('imagecache_actions_validate_number_positive'),
|
|
|
);
|
|
|
$form['path'] = array(
|
|
|
'#type' => 'textfield',
|
|
@@ -641,25 +702,41 @@ function canvasactions_file2canvas_form($data) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implementation of theme_hook() for imagecache_ui.module
|
|
|
+ * Implements theme_hook() for the overlay (watermark) 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_file2canvas_summary($variables) {
|
|
|
+function theme_canvasactions_file2canvas_summary(array $variables) {
|
|
|
$data = $variables['data'];
|
|
|
- return '<strong>' . $data['path'] . '</strong> x:' . $data['xpos'] . ', y:' . $data['ypos'] . ' alpha:' . (@$data['alpha'] ? $data['alpha'] : 100) . '%';
|
|
|
+ return '<strong>' . $data['path'] . '</strong>, x:' . $data['xpos'] . ', y:' . $data['ypos'] . ', alpha:' . (!empty($data['alpha']) ? $data['alpha'] : 100) . '%' . ', scale:' . (!empty($data['scale']) ? $data['scale'].'%' : '-');
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Place the source image on the current background
|
|
|
- *
|
|
|
- * Implementation of hook_image()
|
|
|
+ * Image effect callback for the overlay (watermark) image effect.
|
|
|
*
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
*
|
|
|
- * @param $image
|
|
|
- * @param $data
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_file2canvas_image($image, $data = array()) {
|
|
|
+function canvasactions_file2canvas_effect(stdClass $image, array $data) {
|
|
|
$overlay = imagecache_actions_image_load($data['path']);
|
|
|
if ($overlay) {
|
|
|
+ if (!empty($data['scale']) && $data['scale'] > 0) {
|
|
|
+ // Scale the overlay with respect to the dimensions of the source being
|
|
|
+ // overlaid. To maintain the aspect ratio, only the width of the overlay
|
|
|
+ // is scaled like that, the height of the overlay follows the aspect
|
|
|
+ // ratio (that is why we use image_scale instead of image_resize).
|
|
|
+ $overlay_w = $image->info['width'] * $data['scale'] / 100;
|
|
|
+ image_scale($overlay, $overlay_w, NULL, TRUE);
|
|
|
+ }
|
|
|
if (!isset($data['alpha'])) {
|
|
|
$data['alpha'] = 100;
|
|
|
}
|
|
@@ -668,17 +745,15 @@ function canvasactions_file2canvas_image($image, $data = array()) {
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
-///////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/**
|
|
|
- * Place the source image on top of the current canvas
|
|
|
- *
|
|
|
- * Implementation of imagecache_hook_form()
|
|
|
- *
|
|
|
+ * Image effect form callback for the overlay: source image to canvas effect.
|
|
|
*
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
*
|
|
|
- * @param $data array of settings for this action
|
|
|
- * @return a form definition
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
function canvasactions_source2canvas_form($data) {
|
|
|
$defaults = array(
|
|
@@ -700,53 +775,64 @@ function canvasactions_source2canvas_form($data) {
|
|
|
return $form;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
- * Implementation of theme_hook() for imagecache_ui.module
|
|
|
+ * Implements theme_hook() for the overlay: source img to canvas 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_source2canvas_summary($variables) {
|
|
|
+function theme_canvasactions_source2canvas_summary(array $variables) {
|
|
|
$data = $variables['data'];
|
|
|
return 'xpos:' . $data['xpos'] . ', ypos:' . $data['ypos'] . ' alpha:' . $data['alpha'] . '%';
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Place the source image on the current background
|
|
|
- *
|
|
|
- * Implementation of hook_image()
|
|
|
+ * Image effect callback for the overlay: source image to canvas effect.
|
|
|
*
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
*
|
|
|
- * @param $image
|
|
|
- * @param $data
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_source2canvas_image($image, $data = array()) {
|
|
|
+function canvasactions_source2canvas_effect(stdClass $image, array $data) {
|
|
|
$overlay = image_load($image->source, $image->toolkit);
|
|
|
return image_overlay($image, $overlay, $data['xpos'], $data['ypos'], $data['alpha']);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/**
|
|
|
- * Implements the image effect form callback for the aspect switcher effect.
|
|
|
+ * Image effect form callback for the aspect switcher effect.
|
|
|
*
|
|
|
* @param array $data
|
|
|
- * Array of settings for this action
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
* @return array
|
|
|
- * The form definition
|
|
|
+ * The form definition for this effect.
|
|
|
*/
|
|
|
-function canvasactions_aspect_form($data) {
|
|
|
+function canvasactions_aspect_form(array $data) {
|
|
|
$defaults = array(
|
|
|
'ratio_adjustment' => 1,
|
|
|
- 'portrait' => NULL,
|
|
|
- 'landscape' => NULL,
|
|
|
+ 'portrait' => '',
|
|
|
+ 'landscape' => '',
|
|
|
);
|
|
|
$data = array_merge($defaults, (array) $data);
|
|
|
|
|
|
$form = array(
|
|
|
'help' => array(
|
|
|
- '#type' => 'markup',
|
|
|
- '#value' => t('You must create the two presets to use <em>before</em> enabling this process.'),
|
|
|
+ '#markup' => t('You must create the two presets to use <em>before</em> enabling this process.'),
|
|
|
)
|
|
|
);
|
|
|
|
|
|
- $styles = image_style_options(TRUE);
|
|
|
+ // The PASS_THROUGH parameter is new as of D7.23, and is added here to prevent
|
|
|
+ // image_style_options() from double-encoding the human-readable image style
|
|
|
+ // name, since the form API will already sanitize options in a select list.
|
|
|
+ $styles = image_style_options(TRUE, PASS_THROUGH);
|
|
|
// @todo: remove the current style to prevent (immediate) recursion?
|
|
|
|
|
|
$form['portrait'] = array(
|
|
@@ -782,30 +868,39 @@ If n < 1 then blunt portraits will be treated as landscape.
|
|
|
|
|
|
|
|
|
/**
|
|
|
- * Implements the summary theme callback for the aspect switcher effect.
|
|
|
+ * Implements theme_hook() for the aspect switcher 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_aspect_summary($variables) {
|
|
|
+function theme_canvasactions_aspect_summary(array $variables) {
|
|
|
$data = $variables['data'];
|
|
|
- $ratio_adjustment = '';
|
|
|
+
|
|
|
+ $label = imagecache_actions_get_style_label($data['portrait']);
|
|
|
+ $output = t('Portrait size: %label', array('%label' => $label));
|
|
|
+ $label = imagecache_actions_get_style_label($data['landscape']);
|
|
|
+ $output .= ', ' . t('Landscape size: %label', array('%label' => $label));
|
|
|
if ($data['ratio_adjustment'] != 1) {
|
|
|
- $ratio_adjustment = " (switch at 1:{$data['ratio_adjustment']})";
|
|
|
+ $output .= ', ' . t("(switch at 1:@ratio_adjustment)", array('@ratio_adjustment' => $data['ratio_adjustment']));
|
|
|
}
|
|
|
- return 'Portrait size: <strong>' . $data['portrait'] . '</strong>. Landscape size: <strong>' . $data['landscape'] . '</strong>' . $ratio_adjustment;
|
|
|
+ return trim($output);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements the image effect callback for the aspect switcher effect.
|
|
|
+ * Image effect callback for the aspect switcher effect.
|
|
|
*
|
|
|
- * @param object $image
|
|
|
+ * @param stdClass $image
|
|
|
* @param array $data
|
|
|
*
|
|
|
- * @return bool
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
*/
|
|
|
-function canvasactions_aspect_image($image, $data = array()) {
|
|
|
+function canvasactions_aspect_effect(stdClass $image, array $data) {
|
|
|
$ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
|
|
|
$aspect = $image->info['width'] / $image->info['height'];
|
|
|
|
|
@@ -821,7 +916,7 @@ function canvasactions_aspect_image($image, $data = array()) {
|
|
|
|
|
|
if (empty($style)) {
|
|
|
// Required preset has gone missing?
|
|
|
- watchdog('imagecache_canvasactions', "When running 'aspect' action, I was unable to load sub-action %style_name. Either it's been deleted or the DB needs an update", array('%style_name' => $style_name), WATCHDOG_ERROR);
|
|
|
+ watchdog('imagecache_actions', "When running 'aspect' action, I was unable to load sub-action %style_name. Either it's been deleted or the DB needs an update", array('%style_name' => $style_name), WATCHDOG_ERROR);
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
@@ -833,7 +928,7 @@ function canvasactions_aspect_image($image, $data = array()) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Implements the dimension callback for the aspect switcher effect.
|
|
|
+ * Image dimensions callback for the aspect switcher effect.
|
|
|
*
|
|
|
* @param array $dimensions
|
|
|
* Dimensions to be modified - an associative array containing the items
|
|
@@ -843,10 +938,756 @@ function canvasactions_aspect_image($image, $data = array()) {
|
|
|
*/
|
|
|
function canvasactions_aspect_dimensions(array &$dimensions, array $data) {
|
|
|
if (empty($dimensions['width']) || empty($dimensions['height'])) {
|
|
|
- return;
|
|
|
+ // 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;
|
|
|
+ image_style_transform_dimensions($data['landscape'], $landscape_dimensions);
|
|
|
+ image_style_transform_dimensions($data['portrait'], $portrait_dimensions);
|
|
|
+ if ($landscape_dimensions == $portrait_dimensions) {
|
|
|
+ $dimensions = $landscape_dimensions;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $dimensions['width'] = $dimensions['height'] = NULL;
|
|
|
+ }
|
|
|
}
|
|
|
- $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
|
|
|
- $aspect = $dimensions['width'] / $dimensions['height'];
|
|
|
- $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
|
|
|
- image_style_transform_dimensions($style_name, $dimensions);
|
|
|
+ else {
|
|
|
+ $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
|
|
|
+ $aspect = $dimensions['width'] / $dimensions['height'];
|
|
|
+ $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
|
|
|
+ image_style_transform_dimensions($style_name, $dimensions);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image effect form callback for the resize percent effect.
|
|
|
+ *
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
+ */
|
|
|
+function canvasactions_resizepercent_form(array $data) {
|
|
|
+ $defaults = array(
|
|
|
+ 'width' => '',
|
|
|
+ 'height' => '',
|
|
|
+ );
|
|
|
+ $data = array_merge($defaults, (array) $data);
|
|
|
+
|
|
|
+ $form['#element_validate'] = array('image_effect_scale_validate');
|
|
|
+
|
|
|
+ $form['width'] = array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('Width'),
|
|
|
+ '#default_value' => !empty($data['width']) ? (float) $data['width'] : '',
|
|
|
+ '#field_suffix' => ' ' . t('percent'),
|
|
|
+ '#required' => FALSE,
|
|
|
+ '#size' => 10,
|
|
|
+ '#element_validate' => array('canvasactions_resizepercent_validate'),
|
|
|
+ '#allow_negative' => FALSE,
|
|
|
+ );
|
|
|
+ $form['height'] = array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('Height'),
|
|
|
+ '#default_value' => !empty($data['height']) ? (float) $data['height'] : '',
|
|
|
+ '#field_suffix' => ' ' . t('percent'),
|
|
|
+ '#required' => FALSE,
|
|
|
+ '#size' => 10,
|
|
|
+ '#element_validate' => array('canvasactions_resizepercent_validate'),
|
|
|
+ '#allow_negative' => FALSE,
|
|
|
+ );
|
|
|
+
|
|
|
+ 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);
|
|
|
+ if (!form_get_error($element)) {
|
|
|
+ if ($element['#value'] != '' && (float) $element['#value'] <= 0) {
|
|
|
+ form_error($element, t('!name must be a positive number.', array('!name' => $element['#title'])));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Calculate percent based on input, fallback if only one value is provided.
|
|
|
+ *
|
|
|
+ * @param array $data
|
|
|
+ *
|
|
|
+ * @return float[]|FALSE
|
|
|
+ */
|
|
|
+function _canvasactions_resizepercent_calculate_percent(array $data) {
|
|
|
+ // Fallback if only one value is provided.
|
|
|
+ if (empty($data['height'])) {
|
|
|
+ if (empty($data['width'])) {
|
|
|
+ return FALSE;
|
|
|
+ }
|
|
|
+ $data['height'] = $data['width'];
|
|
|
+ }
|
|
|
+ else if (empty($data['width'])) {
|
|
|
+ $data['width'] = $data['height'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get percentage values in decimal values.
|
|
|
+ $data['width'] = (float) $data['width'] / 100;
|
|
|
+ $data['height'] = (float) $data['height'] / 100;
|
|
|
+
|
|
|
+ return $data;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements theme_hook() for the resize percent 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_resizepercent_summary(array $variables) {
|
|
|
+ $data = _canvasactions_resizepercent_calculate_percent($variables['data']);
|
|
|
+ if (!$data) {
|
|
|
+ return t('Invalid effect data');
|
|
|
+ }
|
|
|
+ if ($data['width'] != $data['height']) {
|
|
|
+ return t('@width%x@height%', array('@width' => 100 * $data['width'], '@height' => 100 * $data['height']));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return t('scale to @percent%', array('@percent' => (float) 100 * $data['height']));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image effect callback for the resize percent effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
+ */
|
|
|
+function canvasactions_resizepercent_effect(stdClass $image, array $data) {
|
|
|
+ $data = _canvasactions_resizepercent_calculate_percent($data);
|
|
|
+
|
|
|
+ $data['width'] = (int) round($image->info['width'] * $data['width']);
|
|
|
+ $data['height'] = (int) round($image->info['height'] * $data['height']);
|
|
|
+
|
|
|
+ return image_resize_effect($image, $data);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image dimensions callback for the resize percent effect.
|
|
|
+ *
|
|
|
+ * @param array $dimensions
|
|
|
+ * Dimensions to be modified - an associative array containing the items
|
|
|
+ * 'width' and 'height' (in pixels).
|
|
|
+ * @param array $data
|
|
|
+ * An associative array containing the effect data.
|
|
|
+ */
|
|
|
+function canvasactions_resizepercent_dimensions(array &$dimensions, array $data) {
|
|
|
+ $data = _canvasactions_resizepercent_calculate_percent($data);
|
|
|
+
|
|
|
+ $dimensions['width'] = (int) round($dimensions['width'] * $data['width']);
|
|
|
+ $dimensions['height'] = (int) round($dimensions['height'] * $data['height']);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image effect form callback for the blur effect.
|
|
|
+ *
|
|
|
+ * @param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
+ * @return array
|
|
|
+ * The form definition for this effect.
|
|
|
+ */
|
|
|
+function canvasactions_blur_form(array $data) {
|
|
|
+ $form['intensity'] = array(
|
|
|
+ '#type' => 'textfield',
|
|
|
+ '#title' => t('Blur intensity'),
|
|
|
+ '#description' => t('A higher intensity results in more blur. The larger the image, the larger value you need to get a really blurred image, think 50 to 100 for 600x400 images.'),
|
|
|
+ '#size' => 5,
|
|
|
+ '#default_value' => isset($data['intensity']) ? (int) $data['intensity'] : 2,
|
|
|
+ '#element_validate' => array('element_validate_integer_positive'),
|
|
|
+ );
|
|
|
+ return $form;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Implements theme_hook() for the underlay (background) 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_blur_summary($variables) {
|
|
|
+ return t('Intensity: @intensity', array('@intensity' => $variables['data']['intensity']));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image effect callback for the resize percent effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ * true on success, false otherwise.
|
|
|
+ */
|
|
|
+function canvasactions_blur_effect(stdClass $image, array $data) {
|
|
|
+ return image_toolkit_invoke('blur', $image, $data);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * GD toolkit specific implementation of the blur effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param int $intensity
|
|
|
+ * The number of times to apply the blur filter.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ * True on success, false otherwise.
|
|
|
+ */
|
|
|
+function image_gd_blur(stdClass $image, $intensity) {
|
|
|
+ $intensity = (int) $intensity;
|
|
|
+ $result = TRUE;
|
|
|
+ $i = 0;
|
|
|
+ while ($result && $i++ < $intensity) {
|
|
|
+ $result = imagefilter($image->resource, IMG_FILTER_GAUSSIAN_BLUR);
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Imagemagick toolkit specific implementation of the blur effect.
|
|
|
+ *
|
|
|
+ * See http://www.imagemagick.org/Usage/blur/.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param int $intensity
|
|
|
+ * The "intensity" of the blur effect.
|
|
|
+ *
|
|
|
+ * @return boolean
|
|
|
+ * True on success, false otherwise.
|
|
|
+ */
|
|
|
+function image_imagemagick_blur(stdClass $image, $intensity) {
|
|
|
+ // To get similar results asd with the GD factor, we use a formula to alter
|
|
|
+ // the intensity into the sigma value that is passed to IM.
|
|
|
+ $sigma = 4.0 + 0.8 * $intensity;
|
|
|
+ $image->ops[] = '-blur ' . escapeshellarg(sprintf('0x%f', $sigma));
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Builds the interlace form.
|
|
|
+ *
|
|
|
+ * This effect has no options, only some help text, so the form is displayed
|
|
|
+ * anyway.
|
|
|
+ */
|
|
|
+function canvasactions_interlace_form() {
|
|
|
+ $form = array();
|
|
|
+ $form['help'] = array(
|
|
|
+ '#markup' => '<p><strong>There are no user-configurable options for this process.</strong></p>
|
|
|
+ <p>This effect will save the derivative image in an interlace / progressive way
|
|
|
+ which might improve perceived performance, especially for large images.
|
|
|
+ File size and loading speed will not change, but the user will pretty quickly
|
|
|
+ see a "degraded" copy of the entire image instead of a clear copy of the upper
|
|
|
+ part of the image.</p>
|
|
|
+ <p>Wikipedia: <a href="https://en.wikipedia.org/wiki/Interlacing_(bitmaps)">Interlacing (bitmaps)</a></p>',
|
|
|
+ );
|
|
|
+ return $form;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Image effect callback for the Interlace / Progressive effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * @param array $data
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
+ */
|
|
|
+function canvasactions_interlace_effect(stdClass $image, array $data) {
|
|
|
+ return image_toolkit_invoke('interlace', $image, array($data));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * GD toolkit specific implementation of the image interlace effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * Image object containing the GD image resource to operate on.
|
|
|
+ * param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
+ */
|
|
|
+function image_gd_interlace($image/*, array $data*/) {
|
|
|
+ imageinterlace($image->resource, 1);
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Imagemagick toolkit specific implementation of the image interlace effect.
|
|
|
+ *
|
|
|
+ * @param stdClass $image
|
|
|
+ * Image object containing the image resource to operate on.
|
|
|
+ * param array $data
|
|
|
+ * The current configuration for this image effect.
|
|
|
+ *
|
|
|
+ * @return bool
|
|
|
+ * true on success, false otherwise.
|
|
|
+ */
|
|
|
+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'))));
|
|
|
}
|