| 1 |
<?php |
<?php |
| 2 |
// $Id: canvasactions.inc,v 1.1.4.16 2009/08/31 02:35:13 dman Exp $ |
// $Id: canvasactions.inc,v 1.1.4.17 2009/08/31 04:12:20 dman Exp $ |
| 3 |
/** |
/** |
| 4 |
* @file Helper functions for the text2canvas action for imagecache |
* @file Helper functions for the text2canvas action for imagecache |
| 5 |
* |
* |
| 6 |
* @author Dan Morrison http://coders.co.nz |
* @author Dan Morrison http://coders.co.nz |
| 7 |
* |
* |
| 8 |
* Individually configurable rounded corners logic contributed by canaryMason |
* Individually configurable rounded corners logic contributed by canaryMason |
| 9 |
* 2009 03 http://drupal.org/node/402112 |
* 2009 03 http://drupal.org/node/402112 |
| 10 |
* |
* |
| 11 |
* Better algorithm for trimming rounded corners from donquixote |
* Better algorithm for trimming rounded corners from donquixote |
| 12 |
* 2009 09 http://drupal.org/node/564036 |
* 2009 09 http://drupal.org/node/564036 |
| 13 |
* |
* |
| 14 |
*/ |
*/ |
| 15 |
|
|
| 16 |
/** |
/** |
| 17 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 18 |
* |
* |
| 19 |
* Settings for preparing a canvas. |
* Settings for preparing a canvas. |
| 20 |
* |
* |
| 21 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 22 |
* @return a form definition |
* @return a form definition |
| 23 |
*/ |
*/ |
| 24 |
function canvasactions_definecanvas_form($action) { |
function canvasactions_definecanvas_form($action) { |
| 25 |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
| 26 |
drupal_set_message('Define Canvas not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
drupal_set_message('Define Canvas not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
| 27 |
} |
} |
| 28 |
$defaults = array( |
$defaults = array( |
| 29 |
'RGB' => array( |
'RGB' => array( |
| 30 |
'HEX' => '#333333', |
'HEX' => '#333333', |
| 31 |
), |
), |
| 32 |
'under' => TRUE, |
'under' => TRUE, |
| 33 |
'exact' => array( |
'exact' => array( |
| 34 |
'width' => '', |
'width' => '', |
| 35 |
'height' => '', |
'height' => '', |
| 36 |
'xpos' => 'center', |
'xpos' => 'center', |
| 37 |
'ypos' => 'center', |
'ypos' => 'center', |
| 38 |
), |
), |
| 39 |
'relative' => array( |
'relative' => array( |
| 40 |
'leftdiff' => '', |
'leftdiff' => '', |
| 41 |
'rightdiff' => '', |
'rightdiff' => '', |
| 42 |
'topdiff' => '', |
'topdiff' => '', |
| 43 |
'bottomdiff' => '', |
'bottomdiff' => '', |
| 44 |
), |
), |
| 45 |
); |
); |
| 46 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 47 |
|
|
| 48 |
$form = array( |
$form = array( |
| 49 |
'RGB' => imagecache_rgb_form($action['RGB']), |
'RGB' => imagecache_rgb_form($action['RGB']), |
| 50 |
'help' => array( |
'help' => array( |
| 51 |
'#type' => 'markup', |
'#type' => 'markup', |
| 52 |
'#value' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'), |
'#value' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'), |
| 53 |
'#prefix' => '<p>', '#suffix' => '</p>', |
'#prefix' => '<p>', '#suffix' => '</p>', |
| 54 |
), |
), |
| 55 |
'under' => array( |
'under' => array( |
| 56 |
'#type' => 'checkbox', |
'#type' => 'checkbox', |
| 57 |
'#title' => t('Resize canvas <em>under</em> image (possibly cropping)'), |
'#title' => t('Resize canvas <em>under</em> image (possibly cropping)'), |
| 58 |
'#default_value' => $action['under'], |
'#default_value' => $action['under'], |
| 59 |
'#description' => t('If <em>not</em> set, this will create a solid flat layer, probably totally obscuring the source image'), |
'#description' => t('If <em>not</em> set, this will create a solid flat layer, probably totally obscuring the source image'), |
| 60 |
), |
), |
| 61 |
); |
); |
| 62 |
$form['info'] = array('#value' => t('Enter values in ONLY ONE of the below options. Either exact or relative. Most values are optional - you can adjust only one dimension as needed. If no useful values are set, the current base image size will be used.')); |
$form['info'] = array('#value' => t('Enter values in ONLY ONE of the below options. Either exact or relative. Most values are optional - you can adjust only one dimension as needed. If no useful values are set, the current base image size will be used.')); |
| 63 |
$form['exact'] = array( |
$form['exact'] = array( |
| 64 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 65 |
'#collapsible' => TRUE, |
'#collapsible' => TRUE, |
| 66 |
'#title' => 'Exact size', |
'#title' => 'Exact size', |
| 67 |
'help' => array( |
'help' => array( |
| 68 |
'#type' => 'markup', |
'#type' => 'markup', |
| 69 |
'#value' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'), |
'#value' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'), |
| 70 |
'#prefix' => '<p>', '#suffix' => '</p>', |
'#prefix' => '<p>', '#suffix' => '</p>', |
| 71 |
), |
), |
| 72 |
|
|
| 73 |
'width' => array( |
'width' => array( |
| 74 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 75 |
'#title' => t('Width'), |
'#title' => t('Width'), |
| 76 |
'#default_value' => $action['exact']['width'], |
'#default_value' => $action['exact']['width'], |
| 77 |
'#description' => t('Enter a value in pixels or percent'), |
'#description' => t('Enter a value in pixels or percent'), |
| 78 |
'#size' => 5, |
'#size' => 5, |
| 79 |
), |
), |
| 80 |
'height' => array( |
'height' => array( |
| 81 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 82 |
'#title' => t('Height'), |
'#title' => t('Height'), |
| 83 |
'#default_value' => $action['exact']['height'], |
'#default_value' => $action['exact']['height'], |
| 84 |
'#description' => t('Enter a value in pixels or percent'), |
'#description' => t('Enter a value in pixels or percent'), |
| 85 |
'#size' => 5, |
'#size' => 5, |
| 86 |
), |
), |
| 87 |
); |
); |
| 88 |
$form['exact'] = array_merge($form['exact'], imagecacheactions_pos_form($action['exact'])); |
$form['exact'] = array_merge($form['exact'], imagecacheactions_pos_form($action['exact'])); |
| 89 |
if (! $action['exact']['width'] && !$action['exact']['height']) { |
if (! $action['exact']['width'] && !$action['exact']['height']) { |
| 90 |
$form['exact']['#collapsed'] = TRUE; |
$form['exact']['#collapsed'] = TRUE; |
| 91 |
} |
} |
| 92 |
|
|
| 93 |
$form['relative'] = array( |
$form['relative'] = array( |
| 94 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 95 |
'#collapsible' => TRUE, |
'#collapsible' => TRUE, |
| 96 |
'#title' => t('Relative size'), |
'#title' => t('Relative size'), |
| 97 |
'help' => array( |
'help' => array( |
| 98 |
'#type' => 'markup', |
'#type' => 'markup', |
| 99 |
'#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>', |
'#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>', |
| 100 |
), |
), |
| 101 |
'leftdiff' => array( |
'leftdiff' => array( |
| 102 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 103 |
'#title' => t('left difference'), |
'#title' => t('left difference'), |
| 104 |
'#default_value' => $action['relative']['leftdiff'], |
'#default_value' => $action['relative']['leftdiff'], |
| 105 |
'#size' => 6, |
'#size' => 6, |
| 106 |
'#description' => t('Enter an offset in pixels.'), |
'#description' => t('Enter an offset in pixels.'), |
| 107 |
), |
), |
| 108 |
'rightdiff' => array( |
'rightdiff' => array( |
| 109 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 110 |
'#title' => t('right difference'), |
'#title' => t('right difference'), |
| 111 |
'#default_value' => $action['relative']['rightdiff'], |
'#default_value' => $action['relative']['rightdiff'], |
| 112 |
'#size' => 6, |
'#size' => 6, |
| 113 |
'#description' => t('Enter an offset in pixels.'), |
'#description' => t('Enter an offset in pixels.'), |
| 114 |
), |
), |
| 115 |
'topdiff' => array( |
'topdiff' => array( |
| 116 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 117 |
'#title' => t('top difference'), |
'#title' => t('top difference'), |
| 118 |
'#default_value' => $action['relative']['topdiff'] , |
'#default_value' => $action['relative']['topdiff'] , |
| 119 |
'#size' => 6, |
'#size' => 6, |
| 120 |
'#description' => t('Enter an offset in pixels.'), |
'#description' => t('Enter an offset in pixels.'), |
| 121 |
), |
), |
| 122 |
'bottomdiff' => array( |
'bottomdiff' => array( |
| 123 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 124 |
'#title' => t('bottom difference'), |
'#title' => t('bottom difference'), |
| 125 |
'#default_value' => $action['relative']['bottomdiff'], |
'#default_value' => $action['relative']['bottomdiff'], |
| 126 |
'#size' => 6, |
'#size' => 6, |
| 127 |
'#description' => t('Enter an offset in pixels.'), |
'#description' => t('Enter an offset in pixels.'), |
| 128 |
), |
), |
| 129 |
); |
); |
| 130 |
if (! $action['relative']['leftdiff'] && !$action['relative']['rightdiff'] && !$action['relative']['topdiff'] && !$action['relative']['bottomdiff']) { |
if (! $action['relative']['leftdiff'] && !$action['relative']['rightdiff'] && !$action['relative']['topdiff'] && !$action['relative']['bottomdiff']) { |
| 131 |
$form['relative']['#collapsed'] = TRUE; |
$form['relative']['#collapsed'] = TRUE; |
| 132 |
} |
} |
| 133 |
|
|
| 134 |
$form['#submit'][] = 'canvasactions_definecanvas_form_submit'; |
$form['#submit'][] = 'canvasactions_definecanvas_form_submit'; |
| 135 |
return $form; |
return $form; |
| 136 |
} |
} |
| 137 |
|
|
| 138 |
/** |
/** |
| 139 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 140 |
*/ |
*/ |
| 141 |
function theme_canvasactions_definecanvas($element) { |
function theme_canvasactions_definecanvas($element) { |
| 142 |
$action = $element['#value']; |
$action = $element['#value']; |
| 143 |
if ($action['exact']['width'] || $action['exact']['width']) { |
if ($action['exact']['width'] || $action['exact']['width']) { |
| 144 |
$output = $action['exact']['width'] .'x'. $action['exact']['height']; |
$output = $action['exact']['width'] .'x'. $action['exact']['height']; |
| 145 |
$output .= " (". $action['exact']['xpos'] .', '. $action['exact']['ypos'] .") "; |
$output .= " (". $action['exact']['xpos'] .', '. $action['exact']['ypos'] .") "; |
| 146 |
} |
} |
| 147 |
else { |
else { |
| 148 |
$output = ' left:'. $action['relative']['leftdiff']; |
$output = ' left:'. $action['relative']['leftdiff']; |
| 149 |
$output .= ' right:'. $action['relative']['rightdiff']; |
$output .= ' right:'. $action['relative']['rightdiff']; |
| 150 |
$output .= ' top:'. $action['relative']['topdiff']; |
$output .= ' top:'. $action['relative']['topdiff']; |
| 151 |
$output .= ' bottom:'. $action['relative']['bottomdiff']; |
$output .= ' bottom:'. $action['relative']['bottomdiff']; |
| 152 |
} |
} |
| 153 |
$output .= theme_imagecacheactions_rgb($action['RGB']); |
$output .= theme_imagecacheactions_rgb($action['RGB']); |
| 154 |
$output .= ($action['under']) ? t(" <b>under</b> image ") : t(" <b>over</b> image "); |
$output .= ($action['under']) ? t(" <b>under</b> image ") : t(" <b>over</b> image "); |
| 155 |
return $output ; |
return $output ; |
| 156 |
} |
} |
| 157 |
|
|
| 158 |
/** |
/** |
| 159 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 160 |
* |
* |
| 161 |
* Creates a solid background canvas |
* Creates a solid background canvas |
| 162 |
* |
* |
| 163 |
* Process the imagecache action on the passed image |
* Process the imagecache action on the passed image |
| 164 |
* |
* |
| 165 |
* @param $image |
* @param $image |
| 166 |
* array defining an image file, including : |
* array defining an image file, including : |
| 167 |
* |
* |
| 168 |
* $image- >source as the filename, |
* $image- >source as the filename, |
| 169 |
* |
* |
| 170 |
* $image->info array |
* $image->info array |
| 171 |
* |
* |
| 172 |
* $image->resource handle on the image object |
* $image->resource handle on the image object |
| 173 |
*/ |
*/ |
| 174 |
function canvasactions_definecanvas_image(&$image, $action = array()) { |
function canvasactions_definecanvas_image(&$image, $action = array()) { |
| 175 |
if ($image->toolkit != 'imageapi_gd') { |
if ($image->toolkit != 'imageapi_gd') { |
| 176 |
drupal_set_message("Unable to define canvas with {$image->toolkit}"); |
drupal_set_message("Unable to define canvas with {$image->toolkit}"); |
| 177 |
return FALSE; |
return FALSE; |
| 178 |
} |
} |
| 179 |
|
|
| 180 |
// May be given either exact or relative dimensions. |
// May be given either exact or relative dimensions. |
| 181 |
if ($action['exact']['width'] || $action['exact']['width']) { |
if ($action['exact']['width'] || $action['exact']['width']) { |
| 182 |
// Allows only one dimension to be used if the other is unset. |
// Allows only one dimension to be used if the other is unset. |
| 183 |
if (! $action['exact']['width']) $action['exact']['width'] = $image->info['width']; |
if (! $action['exact']['width']) $action['exact']['width'] = $image->info['width']; |
| 184 |
if (! $action['exact']['height']) $action['exact']['height'] = $image->info['height']; |
if (! $action['exact']['height']) $action['exact']['height'] = $image->info['height']; |
| 185 |
|
|
| 186 |
$targetsize['width'] = _imagecache_percent_filter($action['exact']['width'], $image->info['width']); |
$targetsize['width'] = _imagecache_percent_filter($action['exact']['width'], $image->info['width']); |
| 187 |
$targetsize['height'] = _imagecache_percent_filter($action['exact']['height'], $image->info['height']); |
$targetsize['height'] = _imagecache_percent_filter($action['exact']['height'], $image->info['height']); |
| 188 |
|
|
| 189 |
$targetsize['left'] = _imagecache_keyword_filter($action['exact']['xpos'], $targetsize['width'], $image->info['width']); |
$targetsize['left'] = _imagecache_keyword_filter($action['exact']['xpos'], $targetsize['width'], $image->info['width']); |
| 190 |
$targetsize['top'] = _imagecache_keyword_filter($action['exact']['ypos'], $targetsize['height'], $image->info['height']); |
$targetsize['top'] = _imagecache_keyword_filter($action['exact']['ypos'], $targetsize['height'], $image->info['height']); |
| 191 |
|
|
| 192 |
} |
} |
| 193 |
else { |
else { |
| 194 |
// calculate relative size |
// calculate relative size |
| 195 |
$targetsize['width'] = $image->info['width'] + $action['relative']['leftdiff'] + $action['relative']['rightdiff']; |
$targetsize['width'] = $image->info['width'] + $action['relative']['leftdiff'] + $action['relative']['rightdiff']; |
| 196 |
$targetsize['height'] = $image->info['height'] + $action['relative']['topdiff'] + $action['relative']['bottomdiff']; |
$targetsize['height'] = $image->info['height'] + $action['relative']['topdiff'] + $action['relative']['bottomdiff']; |
| 197 |
$targetsize['left'] = $action['relative']['leftdiff']; |
$targetsize['left'] = $action['relative']['leftdiff']; |
| 198 |
$targetsize['top'] = $action['relative']['topdiff']; |
$targetsize['top'] = $action['relative']['topdiff']; |
| 199 |
} |
} |
| 200 |
|
|
| 201 |
$newcanvas = imagecreatetruecolor($targetsize['width'], $targetsize['height']); |
$newcanvas = imagecreatetruecolor($targetsize['width'], $targetsize['height']); |
| 202 |
$RGB = $action['RGB']; |
$RGB = $action['RGB']; |
| 203 |
|
|
| 204 |
// convert from hex (as it is stored in the UI) |
// convert from hex (as it is stored in the UI) |
| 205 |
if ($RGB['HEX'] && $deduced = hex_to_rgb($RGB['HEX'])) { |
if ($RGB['HEX'] && $deduced = hex_to_rgb($RGB['HEX'])) { |
| 206 |
$RGB = array_merge($RGB, $deduced); |
$RGB = array_merge($RGB, $deduced); |
| 207 |
$background = imagecolorallocate($newcanvas, $RGB['red'], $RGB['green'], $RGB['blue']); |
$background = imagecolorallocate($newcanvas, $RGB['red'], $RGB['green'], $RGB['blue']); |
| 208 |
} |
} |
| 209 |
else { |
else { |
| 210 |
// No color, attempt transparency, assume white |
// No color, attempt transparency, assume white |
| 211 |
$background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127); |
$background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127); |
| 212 |
imagesavealpha($newcanvas, TRUE); |
imagesavealpha($newcanvas, TRUE); |
| 213 |
imagealphablending($newcanvas, FALSE); |
imagealphablending($newcanvas, FALSE); |
| 214 |
imagesavealpha($image->resource, TRUE); |
imagesavealpha($image->resource, TRUE); |
| 215 |
} |
} |
| 216 |
imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background); |
imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background); |
| 217 |
|
|
| 218 |
# imagealphablending($newcanvas, TRUE); |
# imagealphablending($newcanvas, TRUE); |
| 219 |
|
|
| 220 |
if ($action['under']) { |
if ($action['under']) { |
| 221 |
$canvas_object = (object) array( |
$canvas_object = (object) array( |
| 222 |
'resource' => $newcanvas, |
'resource' => $newcanvas, |
| 223 |
'info' => array( |
'info' => array( |
| 224 |
'width' => $targetsize['width'], |
'width' => $targetsize['width'], |
| 225 |
'height' => $targetsize['height'], |
'height' => $targetsize['height'], |
| 226 |
'mime_type' => 'image/png', |
'mime_type' => 'image/png', |
| 227 |
), |
), |
| 228 |
'toolkit' => $image->toolkit, |
'toolkit' => $image->toolkit, |
| 229 |
); |
); |
| 230 |
imageapi_image_overlay($canvas_object, $image, $targetsize['left'], $targetsize['top'], 100, TRUE); |
imageapi_image_overlay($canvas_object, $image, $targetsize['left'], $targetsize['top'], 100, TRUE); |
| 231 |
|
|
| 232 |
# require_once('watermark.inc'); |
# require_once('watermark.inc'); |
| 233 |
# $watermark = new watermark(); |
# $watermark = new watermark(); |
| 234 |
# $image->resource = $watermark->create_watermark($newcanvas, $image->resource, $targetsize['left'], $targetsize['top'], 100); |
# $image->resource = $watermark->create_watermark($newcanvas, $image->resource, $targetsize['left'], $targetsize['top'], 100); |
| 235 |
# imagesavealpha($image->resource, TRUE); |
# imagesavealpha($image->resource, TRUE); |
| 236 |
} |
} |
| 237 |
else { |
else { |
| 238 |
$image->resource = $newcanvas ; |
$image->resource = $newcanvas ; |
| 239 |
} |
} |
| 240 |
|
|
| 241 |
$image->info['width'] = $targetsize['width']; |
$image->info['width'] = $targetsize['width']; |
| 242 |
$image->info['height'] = $targetsize['height']; |
$image->info['height'] = $targetsize['height']; |
| 243 |
return TRUE; |
return TRUE; |
| 244 |
} |
} |
| 245 |
|
|
| 246 |
//////////////////////////////////////////////// |
//////////////////////////////////////////////// |
| 247 |
|
|
| 248 |
/** |
/** |
| 249 |
* Place a given image under the current canvas |
* Place a given image under the current canvas |
| 250 |
* |
* |
| 251 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 252 |
* |
* |
| 253 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 254 |
* @return a form definition |
* @return a form definition |
| 255 |
*/ |
*/ |
| 256 |
function canvasactions_canvas2file_form($action) { |
function canvasactions_canvas2file_form($action) { |
| 257 |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
| 258 |
drupal_set_message('Overlays are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
drupal_set_message('Overlays are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
| 259 |
} |
} |
| 260 |
|
|
| 261 |
$defaults = array( |
$defaults = array( |
| 262 |
'xpos' => '0', |
'xpos' => '0', |
| 263 |
'ypos' => '0', |
'ypos' => '0', |
| 264 |
'alpha' => '100', |
'alpha' => '100', |
| 265 |
'path' => '', |
'path' => '', |
| 266 |
'dimensions' => 'original', |
'dimensions' => 'original', |
| 267 |
); |
); |
| 268 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 269 |
|
|
| 270 |
$form = imagecacheactions_pos_form($action); |
$form = imagecacheactions_pos_form($action); |
| 271 |
$form['alpha'] = array( |
$form['alpha'] = array( |
| 272 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 273 |
'#title' => t('opacity'), |
'#title' => t('opacity'), |
| 274 |
'#default_value' => $action['alpha'], |
'#default_value' => $action['alpha'], |
| 275 |
'#size' => 6, |
'#size' => 6, |
| 276 |
'#description' => t('Opacity: 0-100. Be aware that values other than 100% may be slow to process.'), |
'#description' => t('Opacity: 0-100. Be aware that values other than 100% may be slow to process.'), |
| 277 |
); |
); |
| 278 |
$form['path'] = array( |
$form['path'] = array( |
| 279 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 280 |
'#title' => t('file name'), |
'#title' => t('file name'), |
| 281 |
'#default_value' => $action['path'], |
'#default_value' => $action['path'], |
| 282 |
'#description' => t('File may be in the "files/" folder, or relative to the Drupal siteroot.'), |
'#description' => t('File may be in the "files/" folder, or relative to the Drupal siteroot.'), |
| 283 |
'#element_validate' => array('canvasactions_file2canvas_validate_file'), |
'#element_validate' => array('canvasactions_file2canvas_validate_file'), |
| 284 |
); |
); |
| 285 |
$form['dimensions'] = array( |
$form['dimensions'] = array( |
| 286 |
'#type' => 'radios', |
'#type' => 'radios', |
| 287 |
'#title' => t('final dimensions'), |
'#title' => t('final dimensions'), |
| 288 |
'#default_value' => $action['dimensions'], |
'#default_value' => $action['dimensions'], |
| 289 |
'#options' => array('original' => 'original (dimensions are retained)', 'background' => 'background (image will be forced to match the size of the background)', 'minimum' => 'minimum (image may be cropped)', 'maximum' => 'maximum (image may end up with gaps)'), |
'#options' => array('original' => 'original (dimensions are retained)', 'background' => 'background (image will be forced to match the size of the background)', 'minimum' => 'minimum (image may be cropped)', 'maximum' => 'maximum (image may end up with gaps)'), |
| 290 |
'#description' => t('What to do when the background image is a different size from the source image. Backgrounds are not tiled, but may be arbitrarily large.'), |
'#description' => t('What to do when the background image is a different size from the source image. Backgrounds are not tiled, but may be arbitrarily large.'), |
| 291 |
); |
); |
| 292 |
return $form; |
return $form; |
| 293 |
} |
} |
| 294 |
|
|
| 295 |
/** |
/** |
| 296 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 297 |
*/ |
*/ |
| 298 |
function theme_canvasactions_canvas2file($element) { |
function theme_canvasactions_canvas2file($element) { |
| 299 |
$data = $element['#value']; |
$data = $element['#value']; |
| 300 |
return "xpos:{$data['xpos']} , ypos:{$data['ypos']} alpha:{$data['alpha']}%. file path:{$data['path']}, dimensions:{$data['dimensions']}" ; |
return "xpos:{$data['xpos']} , ypos:{$data['ypos']} alpha:{$data['alpha']}%. file path:{$data['path']}, dimensions:{$data['dimensions']}" ; |
| 301 |
} |
} |
| 302 |
|
|
| 303 |
/** |
/** |
| 304 |
* Place the source image on the current background |
* Place the source image on the current background |
| 305 |
* |
* |
| 306 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 307 |
* |
* |
| 308 |
* Note - this is currently incompatable with imagemagick, due to the way it |
* Note - this is currently incompatable with imagemagick, due to the way it |
| 309 |
* addresses $image->resource directly - a gd only thing. |
* addresses $image->resource directly - a gd only thing. |
| 310 |
* |
* |
| 311 |
* @param $image |
* @param $image |
| 312 |
* @param $action |
* @param $action |
| 313 |
*/ |
*/ |
| 314 |
function canvasactions_canvas2file_image(&$image, $action = array()) { |
function canvasactions_canvas2file_image(&$image, $action = array()) { |
| 315 |
// search for full (siteroot) paths, then file dir paths, then relative to the current theme |
// search for full (siteroot) paths, then file dir paths, then relative to the current theme |
| 316 |
$filepath = $action['path']; |
$filepath = $action['path']; |
| 317 |
if (!file_exists($filepath) ) { |
if (!file_exists($filepath) ) { |
| 318 |
$filepath = file_create_path($action['path']); |
$filepath = file_create_path($action['path']); |
| 319 |
} |
} |
| 320 |
if (! file_exists($filepath) ) { |
if (! file_exists($filepath) ) { |
| 321 |
trigger_error("Failed to load underlay image $filepath.", E_USER_ERROR); |
trigger_error("Failed to load underlay image $filepath.", E_USER_ERROR); |
| 322 |
return FALSE; |
return FALSE; |
| 323 |
} |
} |
| 324 |
|
|
| 325 |
$underlay = imageapi_image_open($filepath); |
$underlay = imageapi_image_open($filepath); |
| 326 |
|
|
| 327 |
// To handle odd sizes, we will resize/crop the background image to the desired dimensions before |
// To handle odd sizes, we will resize/crop the background image to the desired dimensions before |
| 328 |
// starting the merge. The built-in imagecopymerge, and the watermark library both do not |
// starting the merge. The built-in imagecopymerge, and the watermark library both do not |
| 329 |
// allow overlays to be bigger than the target. |
// allow overlays to be bigger than the target. |
| 330 |
// Adjust size |
// Adjust size |
| 331 |
$crop_rules = array('xoffset' => 0, 'yoffset' => 0, ); |
$crop_rules = array('xoffset' => 0, 'yoffset' => 0, ); |
| 332 |
if (empty($action['dimensions'])) $action['dimensions'] = 'original'; |
if (empty($action['dimensions'])) $action['dimensions'] = 'original'; |
| 333 |
switch ($action['dimensions']) { |
switch ($action['dimensions']) { |
| 334 |
case 'original' : |
case 'original' : |
| 335 |
$crop_rules['width'] = $image->info['width']; |
$crop_rules['width'] = $image->info['width']; |
| 336 |
$crop_rules['height'] = $image->info['height']; |
$crop_rules['height'] = $image->info['height']; |
| 337 |
break; |
break; |
| 338 |
case 'background' : |
case 'background' : |
| 339 |
$crop_rules['width'] = $underlay->info['width']; |
$crop_rules['width'] = $underlay->info['width']; |
| 340 |
$crop_rules['height'] = $underlay->info['height']; |
$crop_rules['height'] = $underlay->info['height']; |
| 341 |
break; |
break; |
| 342 |
case 'minimum' : |
case 'minimum' : |
| 343 |
$crop_rules['width'] = min($underlay->info['width'], $image->info['width']); |
$crop_rules['width'] = min($underlay->info['width'], $image->info['width']); |
| 344 |
$crop_rules['height'] = min($underlay->info['height'], $image->info['height']); |
$crop_rules['height'] = min($underlay->info['height'], $image->info['height']); |
| 345 |
break; |
break; |
| 346 |
case 'maximum' : |
case 'maximum' : |
| 347 |
$crop_rules['width'] = max($underlay->info['width'], $image->info['width']); |
$crop_rules['width'] = max($underlay->info['width'], $image->info['width']); |
| 348 |
$crop_rules['height'] = max($underlay->info['height'], $image->info['height']); |
$crop_rules['height'] = max($underlay->info['height'], $image->info['height']); |
| 349 |
break; |
break; |
| 350 |
} |
} |
| 351 |
// imageapi crop assumes upsize is legal. |
// imageapi crop assumes upsize is legal. |
| 352 |
imagecache_include_standard_actions(); // ensure the library is loaded. |
imagecache_include_standard_actions(); // ensure the library is loaded. |
| 353 |
|
|
| 354 |
// crop both before processing to avoid unwanted processing. |
// crop both before processing to avoid unwanted processing. |
| 355 |
imagecache_crop_image($underlay, $crop_rules); |
imagecache_crop_image($underlay, $crop_rules); |
| 356 |
// Actually this failes because imagecache_crop fills it with solid color when 'cropping' to a larger size. |
// Actually this failes because imagecache_crop fills it with solid color when 'cropping' to a larger size. |
| 357 |
#imagecache_crop_image($image, $crop_rules); |
#imagecache_crop_image($image, $crop_rules); |
| 358 |
|
|
| 359 |
// This func modifies the underlay image by ref, placing the current canvas on it |
// This func modifies the underlay image by ref, placing the current canvas on it |
| 360 |
if (imageapi_image_overlay($underlay, $image, $action['xpos'], $action['ypos'], $action['alpha'], TRUE)) { |
if (imageapi_image_overlay($underlay, $image, $action['xpos'], $action['ypos'], $action['alpha'], TRUE)) { |
| 361 |
$image->resource = $underlay->resource; |
$image->resource = $underlay->resource; |
| 362 |
return TRUE; |
return TRUE; |
| 363 |
} |
} |
| 364 |
} |
} |
| 365 |
|
|
| 366 |
//////////////////////////////////////////////// |
//////////////////////////////////////////////// |
| 367 |
|
|
| 368 |
|
|
| 369 |
/** |
/** |
| 370 |
* Place a given image on top of the current canvas |
* Place a given image on top of the current canvas |
| 371 |
* |
* |
| 372 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 373 |
* |
* |
| 374 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 375 |
* @return a form definition |
* @return a form definition |
| 376 |
*/ |
*/ |
| 377 |
function canvasactions_file2canvas_form($action) { |
function canvasactions_file2canvas_form($action) { |
| 378 |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
| 379 |
drupal_set_message('Overlays are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
drupal_set_message('Overlays are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
| 380 |
} |
} |
| 381 |
|
|
| 382 |
$defaults = array( |
$defaults = array( |
| 383 |
'xpos' => '', |
'xpos' => '', |
| 384 |
'ypos' => '', |
'ypos' => '', |
| 385 |
'alpha' => '100', |
'alpha' => '100', |
| 386 |
'path' => '', |
'path' => '', |
| 387 |
); |
); |
| 388 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 389 |
|
|
| 390 |
$form = array( |
$form = array( |
| 391 |
'help' => array( |
'help' => array( |
| 392 |
'#type' => 'markup', |
'#type' => 'markup', |
| 393 |
'#value' => t('Note that using a transparent overlay that is larger than the source image may result in unwanted results - a solid background.'), |
'#value' => t('Note that using a transparent overlay that is larger than the source image may result in unwanted results - a solid background.'), |
| 394 |
) |
) |
| 395 |
); |
); |
| 396 |
$form += imagecacheactions_pos_form($action); |
$form += imagecacheactions_pos_form($action); |
| 397 |
$form['alpha'] = array( |
$form['alpha'] = array( |
| 398 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 399 |
'#title' => t('opacity'), |
'#title' => t('opacity'), |
| 400 |
'#default_value' => $action['alpha'], |
'#default_value' => $action['alpha'], |
| 401 |
'#size' => 6, |
'#size' => 6, |
| 402 |
'#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.'), |
'#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.'), |
| 403 |
); |
); |
| 404 |
$form['path'] = array( |
$form['path'] = array( |
| 405 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 406 |
'#title' => t('file name'), |
'#title' => t('file name'), |
| 407 |
'#default_value' => $action['path'], |
'#default_value' => $action['path'], |
| 408 |
'#description' => t('File may be in the "files/" folder, or relative to the Drupal siteroot.'), |
'#description' => t('File may be in the "files/" folder, or relative to the Drupal siteroot.'), |
| 409 |
'#element_validate' => array('canvasactions_file2canvas_validate_file'), |
'#element_validate' => array('canvasactions_file2canvas_validate_file'), |
| 410 |
); |
); |
| 411 |
return $form; |
return $form; |
| 412 |
} |
} |
| 413 |
|
|
| 414 |
|
|
| 415 |
/** |
/** |
| 416 |
* Check if the named file is available |
* Check if the named file is available |
| 417 |
*/ |
*/ |
| 418 |
function canvasactions_file2canvas_validate_file(&$element, &$form_status) { |
function canvasactions_file2canvas_validate_file(&$element, &$form_status) { |
| 419 |
if (! file_exists($element['#value']) && ! file_exists(file_create_path($element['#value'])) ) { |
if (! file_exists($element['#value']) && ! file_exists(file_create_path($element['#value'])) ) { |
| 420 |
form_error($element, t("Unable to find the named file '%filepath' in either the site or the files directory. Please check the path. Use relative paths only.", array('%filepath' => $element['#value'])) ); |
form_error($element, t("Unable to find the named file '%filepath' in either the site or the files directory. Please check the path. Use relative paths only.", array('%filepath' => $element['#value'])) ); |
| 421 |
} |
} |
| 422 |
} |
} |
| 423 |
|
|
| 424 |
/** |
/** |
| 425 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 426 |
*/ |
*/ |
| 427 |
function theme_canvasactions_file2canvas($element) { |
function theme_canvasactions_file2canvas($element) { |
| 428 |
$action = $element['#value']; |
$action = $element['#value']; |
| 429 |
return '<strong>'. basename($action['path']) . '</strong> x:'. $action['xpos'] .', y:'. $action['ypos'] .' alpha:'. $action['alpha'] .'%' ; |
return '<strong>'. basename($action['path']) . '</strong> x:'. $action['xpos'] .', y:'. $action['ypos'] .' alpha:'. $action['alpha'] .'%' ; |
| 430 |
} |
} |
| 431 |
|
|
| 432 |
/** |
/** |
| 433 |
* Place the source image on the current background |
* Place the source image on the current background |
| 434 |
* |
* |
| 435 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 436 |
* |
* |
| 437 |
* |
* |
| 438 |
* @param $image |
* @param $image |
| 439 |
* @param $action |
* @param $action |
| 440 |
*/ |
*/ |
| 441 |
function canvasactions_file2canvas_image(&$image, $action = array()) { |
function canvasactions_file2canvas_image(&$image, $action = array()) { |
| 442 |
// search for full (siteroot) paths, then file dir paths, then relative to the current theme |
// search for full (siteroot) paths, then file dir paths, then relative to the current theme |
| 443 |
if (file_exists($action['path'])) { |
if (file_exists($action['path'])) { |
| 444 |
$overlay = imageapi_image_open($action['path'], $image->toolkit); |
$overlay = imageapi_image_open($action['path'], $image->toolkit); |
| 445 |
} |
} |
| 446 |
else if (file_exists(file_create_path($action['path']))) { |
else if (file_exists(file_create_path($action['path']))) { |
| 447 |
$overlay = imageapi_image_open(file_create_path($action['path']), $image->toolkit); |
$overlay = imageapi_image_open(file_create_path($action['path']), $image->toolkit); |
| 448 |
} |
} |
| 449 |
if (! isset($overlay) || ! $overlay) { |
if (! isset($overlay) || ! $overlay) { |
| 450 |
trigger_error(t("Failed to find overlay image %path for imagecache_actions file-to-canvas action. File was not found in the sites 'files' path or the current theme folder.", array('%path' => $action['path'])), E_USER_WARNING); |
trigger_error(t("Failed to find overlay image %path for imagecache_actions file-to-canvas action. File was not found in the sites 'files' path or the current theme folder.", array('%path' => $action['path'])), E_USER_WARNING); |
| 451 |
return FALSE; |
return FALSE; |
| 452 |
} |
} |
| 453 |
return imageapi_image_overlay($image, $overlay, $action['xpos'], $action['ypos'], $action['alpha']); |
return imageapi_image_overlay($image, $overlay, $action['xpos'], $action['ypos'], $action['alpha']); |
| 454 |
} |
} |
| 455 |
|
|
| 456 |
|
|
| 457 |
/////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////// |
| 458 |
|
|
| 459 |
/** |
/** |
| 460 |
* Place the source image on top of the current canvas |
* Place the source image on top of the current canvas |
| 461 |
* |
* |
| 462 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 463 |
* |
* |
| 464 |
* |
* |
| 465 |
* |
* |
| 466 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 467 |
* @return a form definition |
* @return a form definition |
| 468 |
*/ |
*/ |
| 469 |
function canvasactions_source2canvas_form($action) { |
function canvasactions_source2canvas_form($action) { |
| 470 |
$defaults = array( |
$defaults = array( |
| 471 |
'xpos' => '', |
'xpos' => '', |
| 472 |
'ypos' => '', |
'ypos' => '', |
| 473 |
'alpha' => '100', |
'alpha' => '100', |
| 474 |
'path' => '', |
'path' => '', |
| 475 |
); |
); |
| 476 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 477 |
|
|
| 478 |
$form = imagecacheactions_pos_form($action); |
$form = imagecacheactions_pos_form($action); |
| 479 |
$form['alpha'] = array( |
$form['alpha'] = array( |
| 480 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 481 |
'#title' => t('opacity'), |
'#title' => t('opacity'), |
| 482 |
'#default_value' => $action['alpha'], |
'#default_value' => $action['alpha'], |
| 483 |
'#size' => 6, |
'#size' => 6, |
| 484 |
'#description' => t('Opacity: 0-100.'), |
'#description' => t('Opacity: 0-100.'), |
| 485 |
); |
); |
| 486 |
return $form; |
return $form; |
| 487 |
} |
} |
| 488 |
|
|
| 489 |
|
|
| 490 |
|
|
| 491 |
/** |
/** |
| 492 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 493 |
*/ |
*/ |
| 494 |
function theme_canvasactions_source2canvas($element) { |
function theme_canvasactions_source2canvas($element) { |
| 495 |
$data = $element['#value']; |
$data = $element['#value']; |
| 496 |
return 'xpos:'. $data['xpos'] .', ypos:'. $data['ypos'] .' alpha:'. $data['alpha'] .'%' ; |
return 'xpos:'. $data['xpos'] .', ypos:'. $data['ypos'] .' alpha:'. $data['alpha'] .'%' ; |
| 497 |
} |
} |
| 498 |
|
|
| 499 |
/** |
/** |
| 500 |
* Place the source image on the current background |
* Place the source image on the current background |
| 501 |
* |
* |
| 502 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 503 |
* |
* |
| 504 |
* |
* |
| 505 |
* @param $image |
* @param $image |
| 506 |
* @param $action |
* @param $action |
| 507 |
*/ |
*/ |
| 508 |
function canvasactions_source2canvas_image(&$image, $action = array()) { |
function canvasactions_source2canvas_image(&$image, $action = array()) { |
| 509 |
$overlay = imageapi_image_open($image->source); // this probably means opening the image twice. c'est la vie |
$overlay = imageapi_image_open($image->source); // this probably means opening the image twice. c'est la vie |
| 510 |
return imageapi_image_overlay($image, $overlay, $action['xpos'], $action['ypos'], $action['alpha']); |
return imageapi_image_overlay($image, $overlay, $action['xpos'], $action['ypos'], $action['alpha']); |
| 511 |
} |
} |
| 512 |
|
|
| 513 |
/////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////// |
| 514 |
|
|
| 515 |
/** |
/** |
| 516 |
* Set radius for corner rounding |
* Set radius for corner rounding |
| 517 |
* |
* |
| 518 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 519 |
* |
* |
| 520 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 521 |
* @return a form definition |
* @return a form definition |
| 522 |
*/ |
*/ |
| 523 |
function canvasactions_roundedcorners_form($action) { |
function canvasactions_roundedcorners_form($action) { |
| 524 |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
if (imageapi_default_toolkit() != 'imageapi_gd') { |
| 525 |
drupal_set_message('Rounded corners are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
drupal_set_message('Rounded corners are not currently supported by using imagemagick. This effect requires GD image toolkit only.', 'warning'); |
| 526 |
} |
} |
| 527 |
|
|
| 528 |
drupal_add_js(drupal_get_path('module', 'imagecache_canvasactions') .'/imagecache_actions.jquery.js'); |
drupal_add_js(drupal_get_path('module', 'imagecache_canvasactions') .'/imagecache_actions.jquery.js'); |
| 529 |
$defaults = array( |
$defaults = array( |
| 530 |
'radius' => '16', |
'radius' => '16', |
| 531 |
#'antialias' => TRUE, |
#'antialias' => TRUE, |
| 532 |
'independent_corners_set' => array( |
'independent_corners_set' => array( |
| 533 |
'independent_corners' => FALSE, |
'independent_corners' => FALSE, |
| 534 |
'radii' => array( |
'radii' => array( |
| 535 |
'tl' => 0, |
'tl' => 0, |
| 536 |
'tr' => 0, |
'tr' => 0, |
| 537 |
'bl' => 0, |
'bl' => 0, |
| 538 |
'br' => 0, |
'br' => 0, |
| 539 |
), |
), |
| 540 |
), |
), |
| 541 |
); |
); |
| 542 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 543 |
|
|
| 544 |
$form['radius'] = array( |
$form['radius'] = array( |
| 545 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 546 |
'#title' => t('radius'), |
'#title' => t('radius'), |
| 547 |
'#default_value' => $action['radius'], |
'#default_value' => $action['radius'], |
| 548 |
'#size' => 2, |
'#size' => 2, |
| 549 |
); |
); |
| 550 |
|
|
| 551 |
$form['independent_corners_set'] = array( |
$form['independent_corners_set'] = array( |
| 552 |
'#type' => 'fieldset', |
'#type' => 'fieldset', |
| 553 |
'#title' => t('Individual Corner Values'), |
'#title' => t('Individual Corner Values'), |
| 554 |
'#collapsible' => TRUE, |
'#collapsible' => TRUE, |
| 555 |
'#collapsed' => (! $action['independent_corners_set']['independent_corners']), |
'#collapsed' => (! $action['independent_corners_set']['independent_corners']), |
| 556 |
); |
); |
| 557 |
$form['independent_corners_set']['independent_corners'] = array( |
$form['independent_corners_set']['independent_corners'] = array( |
| 558 |
'#type' => 'checkbox', |
'#type' => 'checkbox', |
| 559 |
'#title' => t('Set Corners Independently'), |
'#title' => t('Set Corners Independently'), |
| 560 |
'#default_value' => $action['independent_corners_set']['independent_corners'], |
'#default_value' => $action['independent_corners_set']['independent_corners'], |
| 561 |
); |
); |
| 562 |
$corners = array( |
$corners = array( |
| 563 |
'tl' => t("Top Left Radius"), |
'tl' => t("Top Left Radius"), |
| 564 |
'tr' => t("Top Right Radius"), |
'tr' => t("Top Right Radius"), |
| 565 |
'bl' => t("Bottom Left Radius"), |
'bl' => t("Bottom Left Radius"), |
| 566 |
'br' => t("Bottom Right Radius"), |
'br' => t("Bottom Right Radius"), |
| 567 |
); |
); |
| 568 |
// Loop over the four corners and create field elements for them. |
// Loop over the four corners and create field elements for them. |
| 569 |
$form['independent_corners_set']['radii'] = array('#type' => 'item', '#id' => 'independent-corners-set', ); |
$form['independent_corners_set']['radii'] = array('#type' => 'item', '#id' => 'independent-corners-set', ); |
| 570 |
foreach ($corners as $attribute => $label) { |
foreach ($corners as $attribute => $label) { |
| 571 |
$form['independent_corners_set']['radii'][$attribute] = array( |
$form['independent_corners_set']['radii'][$attribute] = array( |
| 572 |
'#type' => 'textfield', |
'#type' => 'textfield', |
| 573 |
'#title' => $label, |
'#title' => $label, |
| 574 |
'#default_value' => 0+$action['independent_corners_set']['radii'][$attribute], |
'#default_value' => 0+$action['independent_corners_set']['radii'][$attribute], |
| 575 |
'#size' => 2, |
'#size' => 2, |
| 576 |
); |
); |
| 577 |
} |
} |
| 578 |
/* |
/* |
| 579 |
$form['antialias'] = array( |
$form['antialias'] = array( |
| 580 |
'#type' => 'checkbox', |
'#type' => 'checkbox', |
| 581 |
'#title' => t('antialias'), |
'#title' => t('antialias'), |
| 582 |
'#return_value' => TRUE, |
'#return_value' => TRUE, |
| 583 |
'#default_value' => $action['antialias'], |
'#default_value' => $action['antialias'], |
| 584 |
'#description' => t('Attempt antialias smoothing when drawing the corners'), |
'#description' => t('Attempt antialias smoothing when drawing the corners'), |
| 585 |
); |
); |
| 586 |
*/ |
*/ |
| 587 |
$form['notes'] = array( |
$form['notes'] = array( |
| 588 |
'#type' => 'markup', |
'#type' => 'markup', |
| 589 |
'#value' => t(' |
'#value' => t(' |
| 590 |
Note: the rounded corners effect uses true alpha transparency masking. |
Note: the rounded corners effect uses true alpha transparency masking. |
| 591 |
This means that this effect <b>will fail to be saved</b> on jpegs |
This means that this effect <b>will fail to be saved</b> on jpegs |
| 592 |
<em>unless</em> you either <ul> |
<em>unless</em> you either <ul> |
| 593 |
<li>convert the image to PNG (using the coloractions filter for that),</li> |
<li>convert the image to PNG (using the coloractions filter for that),</li> |
| 594 |
<li>define a canvas underneath it (using canvasactions-define-canvas) or</li> |
<li>define a canvas underneath it (using canvasactions-define-canvas) or</li> |
| 595 |
<li>underlay a solid color (using coloractions-alpha-flatten) or</li> |
<li>underlay a solid color (using coloractions-alpha-flatten) or</li> |
| 596 |
<li>underlay a background image (canvasactions-underlay)</li> |
<li>underlay a background image (canvasactions-underlay)</li> |
| 597 |
</ul> |
</ul> |
| 598 |
as a later part of this imagecache pipeline. |
as a later part of this imagecache pipeline. |
| 599 |
<br/> |
<br/> |
| 600 |
'), |
'), |
| 601 |
); |
); |
| 602 |
|
|
| 603 |
return $form; |
return $form; |
| 604 |
} |
} |
| 605 |
|
|
| 606 |
/** |
/** |
| 607 |
* Trim rounded corners off an image, using an anti-aliasing algorithm. |
* Trim rounded corners off an image, using an anti-aliasing algorithm. |
| 608 |
* |
* |
| 609 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 610 |
* |
* |
| 611 |
* Note, this is not image toolkit-agnostic yet! It just assumes GD. |
* Note, this is not image toolkit-agnostic yet! It just assumes GD. |
| 612 |
* We can abstract it out once we have something else to abstract to. |
* We can abstract it out once we have something else to abstract to. |
| 613 |
* In the meantime just don't. |
* In the meantime just don't. |
| 614 |
* |
* |
| 615 |
* 'handcoded' rounded corners logic contributed by donquixote 2009-08-31 |
* 'handcoded' rounded corners logic contributed by donquixote 2009-08-31 |
| 616 |
* |
* |
| 617 |
* @param $image |
* @param $image |
| 618 |
* @param $action |
* @param $action |
| 619 |
*/ |
*/ |
| 620 |
function canvasactions_roundedcorners_image(&$image, $action = array()) { |
function canvasactions_roundedcorners_image(&$image, $action = array()) { |
| 621 |
if ($image->toolkit != 'imageapi_gd') { |
if ($image->toolkit != 'imageapi_gd') { |
| 622 |
drupal_set_message("Unable to create rounded corners with {$image->toolkit}"); |
drupal_set_message("Unable to create rounded corners with {$image->toolkit}"); |
| 623 |
// Pretend we did anyway, just return the untrimmed version. |
// Pretend we did anyway, just return the untrimmed version. |
| 624 |
return TRUE; |
return TRUE; |
| 625 |
} |
} |
| 626 |
|
|
| 627 |
// Read settings. |
// Read settings. |
| 628 |
$width = $image->info['width']; |
$width = $image->info['width']; |
| 629 |
$height = $image->info['height']; |
$height = $image->info['height']; |
| 630 |
$radius = $action['radius']; |
$radius = $action['radius']; |
| 631 |
$independent_corners = !empty($action['independent_corners_set']['independent_corners']); |
$independent_corners = !empty($action['independent_corners_set']['independent_corners']); |
| 632 |
$corners = array('tl', 'tr', 'bl', 'br'); |
$corners = array('tl', 'tr', 'bl', 'br'); |
| 633 |
|
|
| 634 |
$im = &$image->resource; |
$im = &$image->resource; |
| 635 |
// Prepare drawing on the alpha channel. |
// Prepare drawing on the alpha channel. |
| 636 |
imagesavealpha($im, TRUE); |
imagesavealpha($im, TRUE); |
| 637 |
imagealphablending($im, FALSE); |
imagealphablending($im, FALSE); |
| 638 |
|
|
| 639 |
foreach ($corners as $key) { |
foreach ($corners as $key) { |
| 640 |
if ($independent_corners) { |
if ($independent_corners) { |
| 641 |
$r = $action['independent_corners_set']['radii'][$key]; |
$r = $action['independent_corners_set']['radii'][$key]; |
| 642 |
} |
} |
| 643 |
else { |
else { |
| 644 |
// Use the all-the-same radius setting. |
// Use the all-the-same radius setting. |
| 645 |
$r = $radius; |
$r = $radius; |
| 646 |
} |
} |
| 647 |
|
|
| 648 |
// key can be 'tl', 'tr', 'bl', 'br'. |
// key can be 'tl', 'tr', 'bl', 'br'. |
| 649 |
$is_bottom = ($key{0}=='b'); |
$is_bottom = ($key{0}=='b'); |
| 650 |
$is_right = ($key{1}=='r'); |
$is_right = ($key{1}=='r'); |
| 651 |
|
|
| 652 |
// dx and dy are in "continuous coordinates", |
// dx and dy are in "continuous coordinates", |
| 653 |
// and mark the distance of the pixel middle to the image border. |
// and mark the distance of the pixel middle to the image border. |
| 654 |
for ($dx = .5; $dx < $r; ++$dx) { |
for ($dx = .5; $dx < $r; ++$dx) { |
| 655 |
for ($dy = .5; $dy < $r; ++$dy) { |
for ($dy = .5; $dy < $r; ++$dy) { |
| 656 |
|
|
| 657 |
// ix and iy are in discrete pixel indices, |
// ix and iy are in discrete pixel indices, |
| 658 |
// counting from the top left |
// counting from the top left |
| 659 |
$ix = floor($is_right ? $width-$dx : $dx); |
$ix = floor($is_right ? $width-$dx : $dx); |
| 660 |
$iy = floor($is_bottom ? $height-$dy : $dy); |
$iy = floor($is_bottom ? $height-$dy : $dy); |
| 661 |
|
|
| 662 |
$opacity = _canvasactions_roundedcorners_pixel_opacity($dx, $dy, $r); |
$opacity = _canvasactions_roundedcorners_pixel_opacity($dx, $dy, $r); |
| 663 |
if ($opacity >= 1) { |
if ($opacity >= 1) { |
| 664 |
// we can finish this row, |
// we can finish this row, |
| 665 |
// all following pixels will be fully opaque. |
// all following pixels will be fully opaque. |
| 666 |
break; |
break; |
| 667 |
} |
} |
| 668 |
|
|
| 669 |
// Color lookup at ($ix, $iy). |
// Color lookup at ($ix, $iy). |
| 670 |
$color_ix = imagecolorat($im, $ix, $iy); |
$color_ix = imagecolorat($im, $ix, $iy); |
| 671 |
$color = imagecolorsforindex($im, $color_ix); |
$color = imagecolorsforindex($im, $color_ix); |
| 672 |
|
|
| 673 |
if (isset($rgba['alpha'])) { |
if (isset($rgba['alpha'])) { |
| 674 |
$color['alpha'] = 127 - round($opacity * (127 - $color['alpha'])); |
$color['alpha'] = 127 - round($opacity * (127 - $color['alpha'])); |
| 675 |
} |
} |
| 676 |
else { |
else { |
| 677 |
$color['alpha'] = 127 - round($opacity * 127); |
$color['alpha'] = 127 - round($opacity * 127); |
| 678 |
} |
} |
| 679 |
// Value should not be more than 127, and not less than 0. |
// Value should not be more than 127, and not less than 0. |
| 680 |
$color['alpha'] = ($color['alpha'] > 127) ? 127 : (($color['alpha'] < 0) ? 0 : $color['alpha']); |
$color['alpha'] = ($color['alpha'] > 127) ? 127 : (($color['alpha'] < 0) ? 0 : $color['alpha']); |
| 681 |
$color_ix = imagecolorallocatealpha($im, $color['red'], $color['green'], $color['blue'], $color['alpha']); |
$color_ix = imagecolorallocatealpha($im, $color['red'], $color['green'], $color['blue'], $color['alpha']); |
| 682 |
imagesetpixel($im, $ix, $iy, $color_ix); |
imagesetpixel($im, $ix, $iy, $color_ix); |
| 683 |
} |
} |
| 684 |
} |
} |
| 685 |
} |
} |
| 686 |
return TRUE; |
return TRUE; |
| 687 |
} |
} |
| 688 |
|
|
| 689 |
/** |
/** |
| 690 |
* Calculate the transparency value for a rounded corner pixel |
* Calculate the transparency value for a rounded corner pixel |
| 691 |
* |
* |
| 692 |
* @param $x |
* @param $x |
| 693 |
* distance from pixel center to image border (left or right) |
* distance from pixel center to image border (left or right) |
| 694 |
* should be an integer + 0.5 |
* should be an integer + 0.5 |
| 695 |
* |
* |
| 696 |
* @param $y |
* @param $y |
| 697 |
* distance from pixel center to image border (top or bottom) |
* distance from pixel center to image border (top or bottom) |
| 698 |
* should be an integer + 0.5 |
* should be an integer + 0.5 |
| 699 |
* |
* |
| 700 |
* @param $r |
* @param $r |
| 701 |
* radius of the rounded corner |
* radius of the rounded corner |
| 702 |
* should be an integer |
* should be an integer |
| 703 |
* |
* |
| 704 |
* @return float |
* @return float |
| 705 |
* opacity value between 0 (fully transparent) and 1 (fully opaque). |
* opacity value between 0 (fully transparent) and 1 (fully opaque). |
| 706 |
*/ |
*/ |
| 707 |
function _canvasactions_roundedcorners_pixel_opacity($x, $y, $r) { |
function _canvasactions_roundedcorners_pixel_opacity($x, $y, $r) { |
| 708 |
if ($x < 0 || $y < 0) { |
if ($x < 0 || $y < 0) { |
| 709 |
return 0; |
return 0; |
| 710 |
} |
} |
| 711 |
else if ($x > $r || $y > $r) { |
else if ($x > $r || $y > $r) { |
| 712 |
return 1; |
return 1; |
| 713 |
} |
} |
| 714 |
$dist_2 = ($r-$x)*($r-$x) + ($r-$y)*($r-$y); |
$dist_2 = ($r-$x)*($r-$x) + ($r-$y)*($r-$y); |
| 715 |
$r_2 = $r*$r; |
$r_2 = $r*$r; |
| 716 |
if ($dist_2 > ($r+0.8)*($r+0.8)) { |
if ($dist_2 > ($r+0.8)*($r+0.8)) { |
| 717 |
return 0; |
return 0; |
| 718 |
} |
} |
| 719 |
else if ($dist_2 < ($r-0.8)*($r-0.8)) { |
else if ($dist_2 < ($r-0.8)*($r-0.8)) { |
| 720 |
return 1; |
return 1; |
| 721 |
} |
} |
| 722 |
else { |
else { |
| 723 |
// this pixel needs special analysis. |
// this pixel needs special analysis. |
| 724 |
// thanks to a quite efficient algorithm, we can afford 10x antialiasing :) |
// thanks to a quite efficient algorithm, we can afford 10x antialiasing :) |
| 725 |
$opacity = 0.5; |
$opacity = 0.5; |
| 726 |
if ($x > $y) { |
if ($x > $y) { |
| 727 |
// cut the pixel into 10 vertical "stripes" |
// cut the pixel into 10 vertical "stripes" |
| 728 |
for ($dx=-0.45; $dx<0.5; $dx+=0.1) { |
for ($dx=-0.45; $dx<0.5; $dx+=0.1) { |
| 729 |
// find out where the rounded corner edge intersects with the stripe |
// find out where the rounded corner edge intersects with the stripe |
| 730 |
// this is plain triangle geometry. |
// this is plain triangle geometry. |
| 731 |
$dy = $r - $y - sqrt($r_2 - ($r-$x-$dx)*($r-$x-$dx)); |
$dy = $r - $y - sqrt($r_2 - ($r-$x-$dx)*($r-$x-$dx)); |
| 732 |
$dy = ($dy > 0.5) ? 0.5 : (($dy < -0.5) ? -0.5 : $dy); |
$dy = ($dy > 0.5) ? 0.5 : (($dy < -0.5) ? -0.5 : $dy); |
| 733 |
// count the opaque part of the stripe. |
// count the opaque part of the stripe. |
| 734 |
$opacity -= 0.1 * $dy; |
$opacity -= 0.1 * $dy; |
| 735 |
} |
} |
| 736 |
} |
} |
| 737 |
else { |
else { |
| 738 |
// cut the pixel into 10 horizontal "stripes" |
// cut the pixel into 10 horizontal "stripes" |
| 739 |
for ($dy=-0.45; $dy<0.5; $dy+=0.1) { |
for ($dy=-0.45; $dy<0.5; $dy+=0.1) { |
| 740 |
// this is the math: |
// this is the math: |
| 741 |
// ($r-$x-$dx)^2 + ($r-$y-$dy)^2 = $r^2 |
// ($r-$x-$dx)^2 + ($r-$y-$dy)^2 = $r^2 |
| 742 |
// $dx = $r - $x - sqrt($r^2 - ($r-$y-$dy)^2) |
// $dx = $r - $x - sqrt($r^2 - ($r-$y-$dy)^2) |
| 743 |
$dx = $r - $x - sqrt($r_2 - ($r-$y-$dy)*($r-$y-$dy)); |
$dx = $r - $x - sqrt($r_2 - ($r-$y-$dy)*($r-$y-$dy)); |
| 744 |
$dx = ($dx > 0.5) ? 0.5 : (($dx < -0.5) ? -0.5 : $dx); |
$dx = ($dx > 0.5) ? 0.5 : (($dx < -0.5) ? -0.5 : $dx); |
| 745 |
$opacity -= 0.1 * $dx; |
$opacity -= 0.1 * $dx; |
| 746 |
} |
} |
| 747 |
} |
} |
| 748 |
return ($opacity < 0) ? 0 : (($opacity > 1) ? 1 : $opacity); |
return ($opacity < 0) ? 0 : (($opacity > 1) ? 1 : $opacity); |
| 749 |
} |
} |
| 750 |
} |
} |
| 751 |
|
|
| 752 |
|
|
| 753 |
/** |
/** |
| 754 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 755 |
*/ |
*/ |
| 756 |
function theme_canvasactions_roundedcorners($element) { |
function theme_canvasactions_roundedcorners($element) { |
| 757 |
$data = $element['#value']; |
$data = $element['#value']; |
| 758 |
if (!empty($data['independent_corners_set']['independent_corners'])) { |
if (!empty($data['independent_corners_set']['independent_corners'])) { |
| 759 |
$dimens = join('px | ', $data['independent_corners_set']['radii']) .'px'; |
$dimens = join('px | ', $data['independent_corners_set']['radii']) .'px'; |
| 760 |
} |
} |
| 761 |
else { |
else { |
| 762 |
$dimens = "Radius: {$data['radius']}px"; |
$dimens = "Radius: {$data['radius']}px"; |
| 763 |
} |
} |
| 764 |
return $dimens; |
return $dimens; |
| 765 |
} |
} |
| 766 |
|
|
| 767 |
/////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////// |
| 768 |
|
|
| 769 |
/** |
/** |
| 770 |
* Switch between presets depending on logic |
* Switch between presets depending on logic |
| 771 |
* |
* |
| 772 |
* Implementation of imagecache_hook_form() |
* Implementation of imagecache_hook_form() |
| 773 |
* |
* |
| 774 |
* @param $action array of settings for this action |
* @param $action array of settings for this action |
| 775 |
* @return a form definition |
* @return a form definition |
| 776 |
*/ |
*/ |
| 777 |
function canvasactions_aspect_form($action) { |
function canvasactions_aspect_form($action) { |
| 778 |
$defaults = array( ); |
$defaults = array( ); |
| 779 |
$action = array_merge($defaults, (array)$action); |
$action = array_merge($defaults, (array)$action); |
| 780 |
|
|
| 781 |
$form = array( |
$form = array( |
| 782 |
'help' => array( |
'help' => array( |
| 783 |
'#type' => 'markup', |
'#type' => 'markup', |
| 784 |
'#value' => t('You must create the two presets to use <em>before</em> enabling this process.'), |
'#value' => t('You must create the two presets to use <em>before</em> enabling this process.'), |
| 785 |
) |
) |
| 786 |
); |
); |
| 787 |
|
|
| 788 |
$presets = array(); |
$presets = array(); |
| 789 |
foreach (imagecache_presets(TRUE) as $preset) { |
foreach (imagecache_presets(TRUE) as $preset) { |
| 790 |
$presets[$preset['presetid']] = $preset['presetname']; |
$presets[$preset['presetid']] = $preset['presetname']; |
| 791 |
} |
} |
| 792 |
|
|
| 793 |
$form['portrait'] = array( |
$form['portrait'] = array( |
| 794 |
'#type' => 'select', |
'#type' => 'select', |
| 795 |
'#title' => t('Preset to use if the image is portrait (vertical)'), |
'#title' => t('Preset to use if the image is portrait (vertical)'), |
| 796 |
'#default_value' => $action['portrait'], |
'#default_value' => $action['portrait'], |
| 797 |
'#options' => $presets, |
'#options' => $presets, |
| 798 |
); |
); |
| 799 |
$form['landscape'] = array( |
$form['landscape'] = array( |
| 800 |
'#type' => 'select', |
'#type' => 'select', |
| 801 |
'#title' => t('Preset to use if the image is landscape (horizontal)'), |
'#title' => t('Preset to use if the image is landscape (horizontal)'), |
| 802 |
'#default_value' => $action['landscape'], |
'#default_value' => $action['landscape'], |
| 803 |
'#options' => $presets, |
'#options' => $presets, |
| 804 |
); |
); |
| 805 |
return $form; |
return $form; |
| 806 |
} |
} |
| 807 |
|
|
| 808 |
|
|
| 809 |
/** |
/** |
| 810 |
* Implementation of theme_hook() for imagecache_ui.module |
* Implementation of theme_hook() for imagecache_ui.module |
| 811 |
*/ |
*/ |
| 812 |
function theme_canvasactions_aspect($element) { |
function theme_canvasactions_aspect($element) { |
| 813 |
$action = $element['#value']; |
$action = $element['#value']; |
| 814 |
$presets = imagecache_presets(TRUE); |
$presets = imagecache_presets(TRUE); |
| 815 |
return 'Portrait size: <strong>'. $presets[$action['portrait']]['presetname'] . '</strong>. Landscape size: <strong>'. $presets[$action['landscape']]['presetname'] .'</strong>' ; |
return 'Portrait size: <strong>'. $presets[$action['portrait']]['presetname'] . '</strong>. Landscape size: <strong>'. $presets[$action['landscape']]['presetname'] .'</strong>' ; |
| 816 |
} |
} |
| 817 |
|
|
| 818 |
/** |
/** |
| 819 |
* Choose the action and trigger that. |
* Choose the action and trigger that. |
| 820 |
* |
* |
| 821 |
* Implementation of hook_image() |
* Implementation of hook_image() |
| 822 |
* |
* |
| 823 |
* |
* |
| 824 |
* @param $image |
* @param $image |
| 825 |
* @param $action |
* @param $action |
| 826 |
*/ |
*/ |
| 827 |
function canvasactions_aspect_image(&$image, $action = array()) { |
function canvasactions_aspect_image(&$image, $action = array()) { |
| 828 |
$preset_id = ($image->info['width'] > $image->info['height'] ) ? $action['landscape'] : $action['portrait']; |
$preset_id = ($image->info['width'] > $image->info['height'] ) ? $action['landscape'] : $action['portrait']; |
| 829 |
$preset = imagecache_preset($preset_id); |
$preset = imagecache_preset($preset_id); |
| 830 |
|
|
| 831 |
// Run the preset actions ourself. Cannot invoke a preset from the top as it handles filenames, not image objects. |
// Run the preset actions ourself. Cannot invoke a preset from the top as it handles filenames, not image objects. |
| 832 |
// ripped from imagecache_build_derivative() |
// ripped from imagecache_build_derivative() |
| 833 |
foreach ($preset['actions'] as $sub_action) { |
foreach ($preset['actions'] as $sub_action) { |
| 834 |
_imagecache_apply_action($sub_action, $image); |
_imagecache_apply_action($sub_action, $image); |
| 835 |
} |
} |
| 836 |
return TRUE; |
return TRUE; |
| 837 |
} |
} |
| 838 |
|
|
| 839 |
|
|
| 840 |
/////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////// |