/[drupal]/contributions/modules/imagecache_actions/canvasactions.inc
ViewVC logotype

Diff of /contributions/modules/imagecache_actions/canvasactions.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph | View Patch Patch

revision 1.1.4.17, Mon Aug 31 04:12:20 2009 UTC revision 1.1.4.18, Sat Sep 5 02:11:58 2009 UTC
# Line 1  Line 1 
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  ///////////////////////////////////////////////////////////////////  ///////////////////////////////////////////////////////////////////

Legend:
Removed from v.1.1.4.17  
changed lines
  Added in v.1.1.4.18

  ViewVC Help
Powered by ViewVC 1.1.2