canvasactions.inc 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. <?php
  2. /**
  3. * @file Helper functions for the canvas actions for imagecache
  4. *
  5. * @author Dan Morrison http://coders.co.nz
  6. *
  7. * Individually configurable rounded corners logic contributed by canaryMason
  8. * 2009 03 https://drupal.org/node/402112
  9. *
  10. * Better algorithm for trimming rounded corners from donquixote
  11. * 2009 09 https://drupal.org/node/564036
  12. *
  13. */
  14. if (!function_exists('image_overlay')) {
  15. module_load_include('inc', 'imagecache_actions', 'image_overlay');
  16. }
  17. if (!function_exists('imagecache_actions_pos_form')) {
  18. module_load_include('inc', 'imagecache_actions', 'utility-form');
  19. }
  20. if (!function_exists('imagecache_actions_keyword_filter')) {
  21. module_load_include('inc', 'imagecache_actions', 'utility');
  22. }
  23. /**
  24. * Image effect form callback for the image mask effect.
  25. *
  26. * @param array $data
  27. * The current configuration for this image effect.
  28. *
  29. * @return array
  30. * The form definition for this effect.
  31. */
  32. function canvasactions_imagemask_form(array $data) {
  33. // @todo: add offset/positioning/scaling support - currently the mask is applied to the supplied image without resizing and positioned at (0,0)
  34. $form = array();
  35. $form['effect_help_text'] = array(
  36. '#type' => 'item',
  37. '#title' => t('Image mask'),
  38. '#description' => t('This effect will add (or replace) a transparency channel to your image. The mask file should be a grayscale image where black is fully transparent and white is fully opaque. The referenced mask will be applied to the top left of the image.'),
  39. );
  40. $form['path'] = array(
  41. '#type' => 'textfield',
  42. '#title' => t('Mask file name'),
  43. '#default_value' => isset($data['path']) ? $data['path'] : '',
  44. '#description' => imagecache_actions_file_field_description(),
  45. '#element_validate' => array('imagecache_actions_validate_file'),
  46. );
  47. return $form;
  48. }
  49. /**
  50. * Implements theme_hook() for the image mask effect summary.
  51. *
  52. * @param array $variables
  53. * An associative array containing:
  54. * - data: The current configuration for this image effect.
  55. *
  56. * @return string
  57. * The HTML for the summary of this image effect.
  58. * @ingroup themeable
  59. */
  60. function theme_canvasactions_imagemask_summary(array $variables) {
  61. $data = $variables['data'];
  62. return 'file: ' . $data['path'];
  63. }
  64. /**
  65. * Image effect callback for the image mask effect.
  66. *
  67. * @param stdClass $image
  68. * @param array $data
  69. *
  70. * @return bool
  71. * true on success, false otherwise.
  72. */
  73. function canvasactions_imagemask_effect(stdClass $image, array $data) {
  74. $mask = imagecache_actions_image_load($data['path'], $image->toolkit);
  75. if ($mask) {
  76. // @todo: (sydneyshan) Consider best way to add offset support - I assume we
  77. // would position the mask somewhere (top/left/offset px etc) and choose if
  78. // the surrounding area is white or black (opaque or transparent) using an
  79. // extra form element (radio). Assess existing positioning code first to
  80. // reduce duplication of code. Pass the results to the following function as
  81. // array($mask, $data). Perhaps add a 'scale mask to fit image'/'scale image
  82. // to fit mask'/'no scale' radio group?
  83. return image_toolkit_invoke('imagemask', $image, array($mask));
  84. }
  85. return FALSE;
  86. }
  87. /**
  88. * GD toolkit specific implementation of the image mask effect.
  89. *
  90. * @param stdClass $image
  91. * Image object containing the GD image resource to operate on.
  92. * @param stdClass $mask
  93. * An image object containing the image to use as mask.
  94. *
  95. * @return bool
  96. * true on success, false otherwise.
  97. */
  98. function image_gd_imagemask(stdClass $image, stdClass $mask) {
  99. $newPicture = imagecreatetruecolor($image->info['width'], $image->info['height']);
  100. imagesavealpha($newPicture, TRUE);
  101. imagealphablending($newPicture, TRUE);
  102. $transparent = imagecolorallocatealpha($newPicture, 0, 0, 0, 127);
  103. imagefill($newPicture, 0, 0, $transparent);
  104. // Perform pixel-based alpha map application.
  105. for ($x = 0; $x < $image->info['width']; $x++) {
  106. for ($y = 0; $y < $image->info['height']; $y++) {
  107. // Deal with images with mismatched sizes
  108. if ($x >= $mask->info['width'] || $y >= $mask->info['height']) {
  109. imagesetpixel($newPicture, $x, $y, $transparent);
  110. }
  111. else {
  112. $alpha = imagecolorsforindex($mask->resource, imagecolorat($mask->resource, $x, $y));
  113. $alpha = 127 - floor($alpha['red'] / 2);
  114. $color = imagecolorsforindex($image->resource, imagecolorat($image->resource, $x, $y));
  115. imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, $color['red'], $color['green'], $color['blue'], $alpha));
  116. }
  117. }
  118. }
  119. // Copy back to original picture.
  120. imagedestroy($image->resource);
  121. $image->resource = $newPicture;
  122. return TRUE;
  123. }
  124. /**
  125. * Imagemagick toolkit specific implementation of the image mask effect.
  126. *
  127. * @param stdClass $image
  128. * Image object containing the image resource to operate on.
  129. * @param stdClass $mask
  130. * An image object containing the image to use as mask.
  131. *
  132. * @return bool
  133. * true on success, false otherwise.
  134. */
  135. function image_imagemagick_imagemask(stdClass $image, stdClass $mask) {
  136. $image->ops[] = escapeshellarg($mask->source);
  137. $image->ops[] = '-alpha Off -compose CopyOpacity -composite';
  138. return TRUE;
  139. }
  140. /**
  141. * Image effect form callback for the define canvas effect.
  142. *
  143. * @param array $data
  144. * The current configuration for this image effect.
  145. *
  146. * @return array
  147. * The form definition for this effect.
  148. */
  149. function canvasactions_definecanvas_form(array $data) {
  150. module_load_include('inc', 'imagecache_actions', 'utility-color');
  151. $defaults = array(
  152. 'RGB' => array(
  153. 'HEX' => '#333333',
  154. ),
  155. 'under' => TRUE,
  156. 'exact' => array(
  157. 'width' => '',
  158. 'height' => '',
  159. 'xpos' => 'center',
  160. 'ypos' => 'center',
  161. ),
  162. 'relative' => array(
  163. 'leftdiff' => '',
  164. 'rightdiff' => '',
  165. 'topdiff' => '',
  166. 'bottomdiff' => '',
  167. ),
  168. );
  169. $data += $defaults;
  170. $form = array(
  171. 'RGB' => imagecache_rgb_form($data['RGB']),
  172. 'help' => array(
  173. '#markup' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'),
  174. '#prefix' => '<p>',
  175. '#suffix' => '</p>',
  176. ),
  177. 'under' => array(
  178. '#type' => 'checkbox',
  179. '#title' => t('Resize canvas <em>under</em> image (possibly cropping)'),
  180. '#default_value' => $data['under'],
  181. '#description' => t('If <em>not</em> set, this will create a solid flat layer, probably totally obscuring the source image'),
  182. ),
  183. );
  184. $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.'));
  185. $form['exact'] = array(
  186. '#type' => 'fieldset',
  187. '#collapsible' => TRUE,
  188. '#title' => 'Exact size',
  189. 'help' => array(
  190. '#markup' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'),
  191. '#prefix' => '<p>',
  192. '#suffix' => '</p>',
  193. ),
  194. 'width' => array(
  195. '#type' => 'textfield',
  196. '#title' => t('Width'),
  197. '#default_value' => $data['exact']['width'],
  198. '#description' => t('Enter a value in pixels or percent'),
  199. '#size' => 5,
  200. ),
  201. 'height' => array(
  202. '#type' => 'textfield',
  203. '#title' => t('Height'),
  204. '#default_value' => $data['exact']['height'],
  205. '#description' => t('Enter a value in pixels or percent'),
  206. '#size' => 5,
  207. ),
  208. );
  209. $form['exact'] = array_merge($form['exact'], imagecache_actions_pos_form($data['exact']));
  210. if (!$data['exact']['width'] && !$data['exact']['height']) {
  211. $form['exact']['#collapsed'] = TRUE;
  212. }
  213. $form['relative'] = array(
  214. '#type' => 'fieldset',
  215. '#collapsible' => TRUE,
  216. '#title' => t('Relative size'),
  217. 'help' => array(
  218. '#markup' => t('Set the canvas to a relative size, based on the current image dimensions. Use to add simple borders or expand by a fixed amount. Negative values may crop the image.'),
  219. '#prefix' => '<p>',
  220. '#suffix' => '</p>',
  221. ),
  222. 'leftdiff' => array(
  223. '#type' => 'textfield',
  224. '#title' => t('left difference'),
  225. '#default_value' => $data['relative']['leftdiff'],
  226. '#size' => 6,
  227. '#description' => t('Enter an offset in pixels.'),
  228. ),
  229. 'rightdiff' => array(
  230. '#type' => 'textfield',
  231. '#title' => t('right difference'),
  232. '#default_value' => $data['relative']['rightdiff'],
  233. '#size' => 6,
  234. '#description' => t('Enter an offset in pixels.'),
  235. ),
  236. 'topdiff' => array(
  237. '#type' => 'textfield',
  238. '#title' => t('top difference'),
  239. '#default_value' => $data['relative']['topdiff'],
  240. '#size' => 6,
  241. '#description' => t('Enter an offset in pixels.'),
  242. ),
  243. 'bottomdiff' => array(
  244. '#type' => 'textfield',
  245. '#title' => t('bottom difference'),
  246. '#default_value' => $data['relative']['bottomdiff'],
  247. '#size' => 6,
  248. '#description' => t('Enter an offset in pixels.'),
  249. ),
  250. );
  251. if (!$data['relative']['leftdiff'] && !$data['relative']['rightdiff'] && !$data['relative']['topdiff'] && !$data['relative']['bottomdiff']) {
  252. $form['relative']['#collapsed'] = TRUE;
  253. }
  254. $form['#submit'][] = 'canvasactions_definecanvas_form_submit';
  255. return $form;
  256. }
  257. /**
  258. * Implements theme_hook() for the define canvas effect summary.
  259. *
  260. * @param array $variables
  261. * An associative array containing:
  262. * - data: The current configuration for this image effect.
  263. *
  264. * @return string
  265. * The HTML for the summary of this image effect.
  266. * @ingroup themeable
  267. */
  268. function theme_canvasactions_definecanvas_summary(array $variables) {
  269. $data = $variables['data'];
  270. if ($data['exact']['width'] || $data['exact']['height']) {
  271. $w = !empty($data['exact']['width']) ? $data['exact']['width'] : '100%';
  272. $h = !empty($data['exact']['height']) ? $data['exact']['height'] : '100%';
  273. $x = !empty($data['exact']['xpos']) ? $data['exact']['xpos'] : '0';
  274. $y = !empty($data['exact']['ypos']) ? $data['exact']['ypos'] : '0';
  275. $output = "{$w}x{$h} ($x, $y)";
  276. }
  277. else {
  278. $output = ' left:' . $data['relative']['leftdiff'];
  279. $output .= ' right:' . $data['relative']['rightdiff'];
  280. $output .= ' top:' . $data['relative']['topdiff'];
  281. $output .= ' bottom:' . $data['relative']['bottomdiff'];
  282. }
  283. $output .= theme('imagecacheactions_rgb', array('RGB' => $data['RGB']));
  284. $output .= ($data['under']) ? t(" <b>under</b> image ") : t(" <b>over</b> image ");
  285. return $output;
  286. }
  287. /**
  288. * Image effect callback for the define canvas effect.
  289. *
  290. * @param stdClass $image
  291. * @param array $data
  292. *
  293. * @return boolean
  294. * true on success, false otherwise.
  295. */
  296. function canvasactions_definecanvas_effect(stdClass $image, array $data) {
  297. // May be given either exact or relative dimensions.
  298. if ($data['exact']['width'] || $data['exact']['height']) {
  299. // Allows only one dimension to be used if the other is unset.
  300. if (!$data['exact']['width']) {
  301. $data['exact']['width'] = $image->info['width'];
  302. }
  303. if (!$data['exact']['height']) {
  304. $data['exact']['height'] = $image->info['height'];
  305. }
  306. $targetsize['width'] = imagecache_actions_percent_filter($data['exact']['width'], $image->info['width']);
  307. $targetsize['height'] = imagecache_actions_percent_filter($data['exact']['height'], $image->info['height']);
  308. $targetsize['left'] = image_filter_keyword($data['exact']['xpos'], $targetsize['width'], $image->info['width']);
  309. $targetsize['top'] = image_filter_keyword($data['exact']['ypos'], $targetsize['height'], $image->info['height']);
  310. }
  311. else {
  312. // Calculate relative size.
  313. $targetsize['width'] = $image->info['width'] + $data['relative']['leftdiff'] + $data['relative']['rightdiff'];
  314. $targetsize['height'] = $image->info['height'] + $data['relative']['topdiff'] + $data['relative']['bottomdiff'];
  315. $targetsize['left'] = $data['relative']['leftdiff'];
  316. $targetsize['top'] = $data['relative']['topdiff'];
  317. }
  318. // Convert from hex (as it is stored in the UI).
  319. if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
  320. $data['RGB'] = array_merge($data['RGB'], $deduced);
  321. }
  322. // All the math is done, now defer to the toolkit in use.
  323. $data['targetsize'] = $targetsize;
  324. $success = image_toolkit_invoke('definecanvas', $image, array($data));
  325. if ($success) {
  326. $image->info['width'] = $targetsize['width'];
  327. $image->info['height'] = $targetsize['height'];
  328. }
  329. return $success;
  330. }
  331. /**
  332. * GD toolkit specific implementation of the define canvas effect.
  333. *
  334. * @param stdClass $image
  335. * @param array $data
  336. * The parameters for this effect. $data['targetsize'] is an array expected to
  337. * contain a width, height and a left, top.
  338. *
  339. * @return bool
  340. * true on success, false otherwise.
  341. */
  342. function image_gd_definecanvas(stdClass $image, array $data) {
  343. $targetsize = $data['targetsize'];
  344. $RGB = $data['RGB'];
  345. $newcanvas = imagecreatetruecolor($targetsize['width'], $targetsize['height']);
  346. imagesavealpha($newcanvas, TRUE);
  347. imagealphablending($newcanvas, FALSE);
  348. imagesavealpha($image->resource, TRUE);
  349. if ($RGB['HEX']) {
  350. // Set color, allow it to define transparency, or assume opaque.
  351. $background = imagecolorallocatealpha($newcanvas, $RGB['red'], $RGB['green'], $RGB['blue'], $RGB['alpha']);
  352. }
  353. else {
  354. // No color, attempt transparency, assume white.
  355. $background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127);
  356. }
  357. imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background);
  358. if ($data['under']) {
  359. $canvas_object = new stdClass();
  360. $canvas_object->resource = $newcanvas;
  361. $canvas_object->info = array(
  362. 'width' => $targetsize['width'],
  363. 'height' => $targetsize['height'],
  364. 'mime_type' => $image->info['mime_type'],
  365. 'extension' => $image->info['extension'],
  366. );
  367. $canvas_object->toolkit = $image->toolkit;
  368. image_overlay($image, $canvas_object, $targetsize['left'], $targetsize['top'], 100, TRUE);
  369. }
  370. else {
  371. $image->resource = $newcanvas;
  372. }
  373. return TRUE;
  374. }
  375. /**
  376. * Imagemagick toolkit specific implementation of the define canvas effect.
  377. *
  378. * @param stdClass $image
  379. * @param array $data
  380. * The parameters for this effect. $data['targetsize'] is an array expected to
  381. * contain a width, height and a left, top.
  382. *
  383. * @return bool
  384. * true on success, false otherwise.
  385. *
  386. * @see http://www.imagemagick.org/script/command-line-options.php#extent
  387. */
  388. function image_imagemagick_definecanvas(stdClass $image, $data) {
  389. // Reset any gravity settings from earlier effects.
  390. $image->ops[] = '-gravity None';
  391. $backgroundcolor = $data['RGB']['HEX'] != '' ? '#' . ltrim($data['RGB']['HEX'], '#') : 'None';
  392. $image->ops[] = '-background ' . escapeshellarg($backgroundcolor);
  393. $compose_operator = $data['under'] ? 'src-over' : 'dst-over';
  394. $image->ops[] = "-compose $compose_operator";
  395. $targetsize = $data['targetsize'];
  396. $geometry = sprintf('%dx%d', $targetsize['width'], $targetsize['height']);
  397. if ($targetsize['left'] || $targetsize['top']) {
  398. $geometry .= sprintf('%+d%+d', -$targetsize['left'], -$targetsize['top']);
  399. }
  400. $image->ops[] = '-extent ' . escapeshellarg($geometry);
  401. return TRUE;
  402. }
  403. /**
  404. * Image dimensions callback for the define canvas effect.
  405. *
  406. * @param array $dimensions
  407. * Dimensions to be modified - an associative array containing the items
  408. * 'width' and 'height' (in pixels).
  409. * @param array $data
  410. * An associative array containing the effect data.
  411. */
  412. function canvasactions_definecanvas_dimensions(array &$dimensions, array $data) {
  413. // May be given either exact or relative dimensions.
  414. if ($data['exact']['width'] || $data['exact']['height']) {
  415. // Allows only one dimension to be used if the other is unset.
  416. if (!$data['exact']['width']) {
  417. $data['exact']['width'] = $dimensions['width'];
  418. }
  419. if (!$data['exact']['height']) {
  420. $data['exact']['height'] = $dimensions['height'];
  421. }
  422. $dimensions['width'] = imagecache_actions_percent_filter($data['exact']['width'], $dimensions['width']);
  423. $dimensions['height'] = imagecache_actions_percent_filter($data['exact']['height'], $dimensions['height']);
  424. }
  425. else {
  426. // Calculate relative sizes (only possible if we have the current size).
  427. if ($dimensions['width'] !== NULL) {
  428. $dimensions['width'] = $dimensions['width'] + (int) $data['relative']['leftdiff'] + (int) $data['relative']['rightdiff'];
  429. }
  430. if ($dimensions['height'] !== NULL) {
  431. $dimensions['height'] = $dimensions['height'] + (int) $data['relative']['topdiff'] + (int) $data['relative']['bottomdiff'];
  432. }
  433. }
  434. }
  435. /**
  436. * Image effect form callback for the underlay (background) effect.
  437. *
  438. * @param array $data
  439. * The current configuration for this image effect.
  440. *
  441. * @return array
  442. * The form definition for this effect.
  443. */
  444. function canvasactions_canvas2file_form(array $data) {
  445. $defaults = array(
  446. 'xpos' => '0',
  447. 'ypos' => '0',
  448. 'alpha' => '100',
  449. 'path' => '',
  450. 'dimensions' => 'original',
  451. );
  452. $data = array_merge($defaults, (array) $data);
  453. $form = imagecache_actions_pos_form($data);
  454. $form['alpha'] = array(
  455. '#type' => 'textfield',
  456. '#title' => t('opacity'),
  457. '#default_value' => $data['alpha'],
  458. '#size' => 6,
  459. '#description' => t('Opacity: 0-100. Be aware that values other than 100% may be slow to process.'),
  460. );
  461. $form['path'] = array(
  462. '#type' => 'textfield',
  463. '#title' => t('file name'),
  464. '#default_value' => $data['path'],
  465. '#description' => imagecache_actions_file_field_description(),
  466. '#element_validate' => array('imagecache_actions_validate_file'),
  467. );
  468. $form['dimensions'] = array(
  469. '#type' => 'radios',
  470. '#title' => t('final dimensions'),
  471. '#default_value' => $data['dimensions'],
  472. '#options' => array(
  473. 'original' => 'original (dimensions are retained)',
  474. 'background' => 'background (image will be forced to match the size of the background)',
  475. 'minimum' => 'minimum (image may be cropped)',
  476. 'maximum' => 'maximum (image may end up with gaps)',
  477. ),
  478. '#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.'),
  479. );
  480. return $form;
  481. }
  482. /**
  483. * Implements theme_hook() for the underlay (background) effect summary.
  484. *
  485. * @param array $variables
  486. * An associative array containing:
  487. * - data: The current configuration for this image effect.
  488. *
  489. * @return string
  490. * The HTML for the summary of this image effect.
  491. * @ingroup themeable
  492. */
  493. function theme_canvasactions_canvas2file_summary($variables) {
  494. $data = $variables['data'];
  495. $file = $data['path'];
  496. return "xpos:{$data['xpos']} , ypos:{$data['ypos']} alpha:{$data['alpha']}%. file: $file, dimensions:{$data['dimensions']}";
  497. }
  498. /**
  499. * Image effect callback for the underlay (background) effect.
  500. *
  501. * @param stdClass $image
  502. * @param array $data
  503. *
  504. * @return boolean
  505. * true on success, false otherwise.
  506. */
  507. function canvasactions_canvas2file_effect(stdClass $image, array $data) {
  508. $underlay = imagecache_actions_image_load($data['path'], $image->toolkit);
  509. if ($underlay) {
  510. // To handle odd sizes, we will resize/crop the background image to the
  511. // desired dimensions before starting the merge. The built-in
  512. // imagecopymerge, and the watermark library both do not allow overlays to
  513. // be bigger than the target.
  514. // Adjust size.
  515. $crop_rules = array(
  516. 'xoffset' => 0,
  517. 'yoffset' => 0,
  518. );
  519. if (empty($data['dimensions'])) {
  520. $data['dimensions'] = 'original';
  521. }
  522. switch ($data['dimensions']) {
  523. case 'original':
  524. // If the underlay is smaller than the target size,
  525. // then when preparing the underlay by cropping it,
  526. // the offsets may need to be negative
  527. // which will produce a 'cropped' image larger than the original.
  528. // In this case, we need to calculate the position of the bg image
  529. // in relation to the space it will occupy under the top layer
  530. //$crop_rules['xoffset'] = $underlay->info['width'] - $image->info['width'] ;
  531. $crop_rules['width'] = $image->info['width'];
  532. $crop_rules['height'] = $image->info['height'];
  533. break;
  534. case 'background':
  535. $crop_rules['width'] = $underlay->info['width'];
  536. $crop_rules['height'] = $underlay->info['height'];
  537. break;
  538. case 'minimum':
  539. $crop_rules['width'] = min($underlay->info['width'], $image->info['width']);
  540. $crop_rules['height'] = min($underlay->info['height'], $image->info['height']);
  541. break;
  542. case 'maximum':
  543. $crop_rules['width'] = max($underlay->info['width'], $image->info['width']);
  544. $crop_rules['height'] = max($underlay->info['height'], $image->info['height']);
  545. break;
  546. }
  547. // imageapi crop assumes upsize is legal.
  548. // Crop both before processing to avoid unwanted processing.
  549. image_crop_effect($underlay, $crop_rules);
  550. // @todo: BUG - this doesn't position either
  551. // Actually this fails because imagecache_crop fills it with solid color when 'cropping' to a larger size.
  552. //imagecache_crop_image($image, $crop_rules);
  553. //dpm(get_defined_vars());
  554. // This func modifies the underlay image by ref, placing the current canvas on it.
  555. if (image_overlay($image, $underlay, $data['xpos'], $data['ypos'], $data['alpha'], TRUE)) {
  556. //$image->resource = $underlay->resource;
  557. $image = $underlay; //@todo: this is a no-op.
  558. return TRUE;
  559. }
  560. }
  561. return FALSE;
  562. }
  563. /**
  564. * Image dimensions callback for the underlay (background) effect.
  565. *
  566. * @param array $dimensions
  567. * Dimensions to be modified - an associative array containing the items
  568. * 'width' and 'height' (in pixels).
  569. * @param array $data
  570. * An associative array containing the effect data.
  571. */
  572. function canvasactions_canvas2file_dimensions(array &$dimensions, array $data) {
  573. if ($data['dimensions'] !== 'original') {
  574. $underlay = imagecache_actions_image_load($data['path']);
  575. if ($underlay) {
  576. // If the new dimensions are taken from the background, we don't need to
  577. // know the original dimensions, we can just set the new dimensions to the
  578. // dimensions of the background. Otherwise, we need to know the old
  579. // dimensions. If unknown we have to leave them unknown.
  580. switch ($data['dimensions']) {
  581. case 'background':
  582. $dimensions['width'] = $underlay->info['width'];
  583. $dimensions['height'] = $underlay->info['height'];
  584. break;
  585. case 'minimum':
  586. if ($dimensions['width'] !== NULL) {
  587. $dimensions['width'] = min($underlay->info['width'], $dimensions['width']);
  588. }
  589. if ($dimensions['height'] !== NULL) {
  590. $dimensions['height'] = min($underlay->info['height'], $dimensions['height']);
  591. }
  592. break;
  593. case 'maximum':
  594. if ($dimensions['width'] !== NULL) {
  595. $dimensions['width'] = max($underlay->info['width'], $dimensions['width']);
  596. }
  597. if ($dimensions['height'] !== NULL) {
  598. $dimensions['height'] = max($underlay->info['height'], $dimensions['height']);
  599. }
  600. break;
  601. }
  602. }
  603. }
  604. }
  605. /**
  606. * Image effect form callback for the overlay (watermark) effect.
  607. *
  608. * @param array $data
  609. * The current configuration for this image effect.
  610. *
  611. * @return array
  612. * The form definition for this effect.
  613. */
  614. function canvasactions_file2canvas_form(array $data) {
  615. $defaults = array(
  616. 'xpos' => '',
  617. 'ypos' => '',
  618. 'alpha' => '100',
  619. 'scale' => '',
  620. 'path' => '',
  621. );
  622. $data = array_merge($defaults, (array) $data);
  623. $form = array(
  624. 'help' => array(
  625. '#markup' => t('Note that using a non transparent overlay that is larger than the source image may result in unwanted results - a solid background.'),
  626. ),
  627. );
  628. $form += imagecache_actions_pos_form($data);
  629. $form['alpha'] = array(
  630. '#type' => 'textfield',
  631. '#title' => t('opacity'),
  632. '#default_value' => $data['alpha'],
  633. '#field_suffix' => t('%'),
  634. '#size' => 6,
  635. '#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.'),
  636. '#element_validate' => array('imagecache_actions_validate_number_non_negative'),
  637. );
  638. $form['scale'] = array(
  639. '#type' => 'textfield',
  640. '#title' => t('scale'),
  641. '#default_value' => $data['scale'],
  642. '#field_suffix' => t('%'),
  643. '#size' => 6,
  644. '#description' => t('Scales the overlay with respect to the source, thus not its own dimensions. Leave empty to use the original size of overlay image.'),
  645. '#element_validate' => array('imagecache_actions_validate_number_positive'),
  646. );
  647. $form['path'] = array(
  648. '#type' => 'textfield',
  649. '#title' => t('file name'),
  650. '#default_value' => $data['path'],
  651. '#description' => imagecache_actions_file_field_description(),
  652. '#element_validate' => array('imagecache_actions_validate_file'),
  653. );
  654. return $form;
  655. }
  656. /**
  657. * Implements theme_hook() for the overlay (watermark) effect summary.
  658. *
  659. * @param array $variables
  660. * An associative array containing:
  661. * - data: The current configuration for this image effect.
  662. *
  663. * @return string
  664. * The HTML for the summary of this image effect.
  665. * @ingroup themeable
  666. */
  667. function theme_canvasactions_file2canvas_summary(array $variables) {
  668. $data = $variables['data'];
  669. return '<strong>' . $data['path'] . '</strong>, x:' . $data['xpos'] . ', y:' . $data['ypos'] . ', alpha:' . (!empty($data['alpha']) ? $data['alpha'] : 100) . '%' . ', scale:' . (!empty($data['scale']) ? $data['scale'].'%' : '-');
  670. }
  671. /**
  672. * Image effect callback for the overlay (watermark) image effect.
  673. *
  674. * @param stdClass $image
  675. * @param array $data
  676. *
  677. * @return boolean
  678. * true on success, false otherwise.
  679. */
  680. function canvasactions_file2canvas_effect(stdClass $image, array $data) {
  681. $overlay = imagecache_actions_image_load($data['path']);
  682. if ($overlay) {
  683. if (!empty($data['scale']) && $data['scale'] > 0) {
  684. // Scale the overlay with respect to the dimensions of the source being
  685. // overlaid. To maintain the aspect ratio, only the width of the overlay
  686. // is scaled like that, the height of the overlay follows the aspect
  687. // ratio (that is why we use image_scale instead of image_resize).
  688. $overlay_w = $image->info['width'] * $data['scale'] / 100;
  689. image_scale($overlay, $overlay_w, NULL, TRUE);
  690. }
  691. if (!isset($data['alpha'])) {
  692. $data['alpha'] = 100;
  693. }
  694. return image_overlay($image, $overlay, $data['xpos'], $data['ypos'], $data['alpha']);
  695. }
  696. return FALSE;
  697. }
  698. /**
  699. * Image effect form callback for the overlay: source image to canvas effect.
  700. *
  701. * @param array $data
  702. * The current configuration for this image effect.
  703. *
  704. * @return array
  705. * The form definition for this effect.
  706. */
  707. function canvasactions_source2canvas_form($data) {
  708. $defaults = array(
  709. 'xpos' => '',
  710. 'ypos' => '',
  711. 'alpha' => '100',
  712. 'path' => '',
  713. );
  714. $data = array_merge($defaults, (array) $data);
  715. $form = imagecache_actions_pos_form($data);
  716. $form['alpha'] = array(
  717. '#type' => 'textfield',
  718. '#title' => t('opacity'),
  719. '#default_value' => $data['alpha'],
  720. '#size' => 6,
  721. '#description' => t('Opacity: 0-100.'),
  722. );
  723. return $form;
  724. }
  725. /**
  726. * Implements theme_hook() for the overlay: source img to canvas effect summary.
  727. *
  728. * @param array $variables
  729. * An associative array containing:
  730. * - data: The current configuration for this image effect.
  731. *
  732. * @return string
  733. * The HTML for the summary of this image effect.
  734. * @ingroup themeable
  735. */
  736. function theme_canvasactions_source2canvas_summary(array $variables) {
  737. $data = $variables['data'];
  738. return 'xpos:' . $data['xpos'] . ', ypos:' . $data['ypos'] . ' alpha:' . $data['alpha'] . '%';
  739. }
  740. /**
  741. * Image effect callback for the overlay: source image to canvas effect.
  742. *
  743. * @param stdClass $image
  744. * @param array $data
  745. *
  746. * @return boolean
  747. * true on success, false otherwise.
  748. */
  749. function canvasactions_source2canvas_effect(stdClass $image, array $data) {
  750. $overlay = image_load($image->source, $image->toolkit);
  751. return image_overlay($image, $overlay, $data['xpos'], $data['ypos'], $data['alpha']);
  752. }
  753. /**
  754. * Image effect form callback for the aspect switcher effect.
  755. *
  756. * @param array $data
  757. * The current configuration for this image effect.
  758. *
  759. * @return array
  760. * The form definition for this effect.
  761. */
  762. function canvasactions_aspect_form(array $data) {
  763. $defaults = array(
  764. 'ratio_adjustment' => 1,
  765. 'portrait' => '',
  766. 'landscape' => '',
  767. );
  768. $data = array_merge($defaults, (array) $data);
  769. $form = array(
  770. 'help' => array(
  771. '#markup' => t('You must create the two presets to use <em>before</em> enabling this process.'),
  772. )
  773. );
  774. // The PASS_THROUGH parameter is new as of D7.23, and is added here to prevent
  775. // image_style_options() from double-encoding the human-readable image style
  776. // name, since the form API will already sanitize options in a select list.
  777. $styles = image_style_options(TRUE, PASS_THROUGH);
  778. // @todo: remove the current style to prevent (immediate) recursion?
  779. $form['portrait'] = array(
  780. '#type' => 'select',
  781. '#title' => t('Style to use if the image is portrait (vertical)'),
  782. '#default_value' => $data['portrait'],
  783. '#options' => $styles,
  784. '#description' => t('If you choose none, no extra processing will be done.'),
  785. );
  786. $form['landscape'] = array(
  787. '#type' => 'select',
  788. '#title' => t('Style to use if the image is landscape (horizontal)'),
  789. '#default_value' => $data['landscape'],
  790. '#options' => $styles,
  791. '#description' => t('If you choose none, no extra processing will be done.'),
  792. );
  793. $form['ratio_adjustment'] = array(
  794. '#type' => 'textfield',
  795. '#title' => t('Ratio Adjustment (advanced)'),
  796. '#size' => 3,
  797. '#default_value' => $data['ratio_adjustment'],
  798. '#description' => t("
  799. This allows you to bend the rules for how different the proportions need to be to trigger the switch.
  800. <br/>If the (width/height)*n is greater than 1, use 'landscape', otherwise use 'portrait'.
  801. <br/>When n = 1 (the default) it will switch between portrait and landscape modes.
  802. <br/>If n > 1, images that are slightly wide will still be treated as portraits.
  803. If n < 1 then blunt portraits will be treated as landscape.
  804. "),
  805. );
  806. return $form;
  807. }
  808. /**
  809. * Implements theme_hook() for the aspect switcher effect summary.
  810. *
  811. * @param array $variables
  812. * An associative array containing:
  813. * - data: The current configuration for this image effect.
  814. *
  815. * @return string
  816. * The HTML for the summary of this image effect.
  817. * @ingroup themeable
  818. */
  819. function theme_canvasactions_aspect_summary(array $variables) {
  820. $data = $variables['data'];
  821. $label = imagecache_actions_get_style_label($data['portrait']);
  822. $output = t('Portrait size: %label', array('%label' => $label));
  823. $label = imagecache_actions_get_style_label($data['landscape']);
  824. $output .= ', ' . t('Landscape size: %label', array('%label' => $label));
  825. if ($data['ratio_adjustment'] != 1) {
  826. $output .= ', ' . t("(switch at 1:@ratio_adjustment)", array('@ratio_adjustment' => $data['ratio_adjustment']));
  827. }
  828. return trim($output);
  829. }
  830. /**
  831. * Image effect callback for the aspect switcher effect.
  832. *
  833. * @param stdClass $image
  834. * @param array $data
  835. *
  836. * @return boolean
  837. * true on success, false otherwise.
  838. */
  839. function canvasactions_aspect_effect(stdClass $image, array $data) {
  840. $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
  841. $aspect = $image->info['width'] / $image->info['height'];
  842. // width / height * adjustment. If > 1, it's wide.
  843. $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
  844. if (empty($style_name)) {
  845. // Do nothing. just return what we've got.
  846. return TRUE;
  847. }
  848. $style = image_style_load($style_name);
  849. if (empty($style)) {
  850. // Required preset has gone missing?
  851. watchdog('imagecache_actions', "When running 'aspect' action, I was unable to load sub-action %style_name. Either it's been deleted or the DB needs an update", array('%style_name' => $style_name), WATCHDOG_ERROR);
  852. return FALSE;
  853. }
  854. // Run the preset actions ourself.
  855. foreach ($style['effects'] as $sub_effect) {
  856. image_effect_apply($image, $sub_effect);
  857. }
  858. return TRUE;
  859. }
  860. /**
  861. * Image dimensions callback for the aspect switcher effect.
  862. *
  863. * @param array $dimensions
  864. * Dimensions to be modified - an associative array containing the items
  865. * 'width' and 'height' (in pixels).
  866. * @param array $data
  867. * An associative array containing the effect data.
  868. */
  869. function canvasactions_aspect_dimensions(array &$dimensions, array $data) {
  870. if (!isset($dimensions['width']) || !isset($dimensions['height'])) {
  871. // We cannot know which preset would be executed and thus cannot know the
  872. // resulting dimensions, unless both styles return the same dimensions:
  873. $landscape_dimensions = $portrait_dimensions = $dimensions;
  874. image_style_transform_dimensions($data['landscape'], $landscape_dimensions);
  875. image_style_transform_dimensions($data['portrait'], $portrait_dimensions);
  876. if ($landscape_dimensions == $portrait_dimensions) {
  877. $dimensions = $landscape_dimensions;
  878. }
  879. else {
  880. $dimensions['width'] = $dimensions['height'] = NULL;
  881. }
  882. }
  883. else {
  884. $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
  885. $aspect = $dimensions['width'] / $dimensions['height'];
  886. $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
  887. image_style_transform_dimensions($style_name, $dimensions);
  888. }
  889. }
  890. /**
  891. * Image effect form callback for the resize percent effect.
  892. *
  893. * @param array $data
  894. * The current configuration for this image effect.
  895. *
  896. * @return array
  897. * The form definition for this effect.
  898. */
  899. function canvasactions_resizepercent_form(array $data) {
  900. $defaults = array(
  901. 'width' => '',
  902. 'height' => '',
  903. );
  904. $data = array_merge($defaults, (array) $data);
  905. $form['#element_validate'] = array('image_effect_scale_validate');
  906. $form['width'] = array(
  907. '#type' => 'textfield',
  908. '#title' => t('Width'),
  909. '#default_value' => !empty($data['width']) ? (float) $data['width'] : '',
  910. '#field_suffix' => ' ' . t('percent'),
  911. '#required' => FALSE,
  912. '#size' => 10,
  913. '#element_validate' => array('canvasactions_resizepercent_validate'),
  914. '#allow_negative' => FALSE,
  915. );
  916. $form['height'] = array(
  917. '#type' => 'textfield',
  918. '#title' => t('Height'),
  919. '#default_value' => !empty($data['height']) ? (float) $data['height'] : '',
  920. '#field_suffix' => ' ' . t('percent'),
  921. '#required' => FALSE,
  922. '#size' => 10,
  923. '#element_validate' => array('canvasactions_resizepercent_validate'),
  924. '#allow_negative' => FALSE,
  925. );
  926. return $form;
  927. }
  928. /**
  929. * Element validate handler to ensure that a positive number is specified.
  930. */
  931. function canvasactions_resizepercent_validate($element, &$form_state) {
  932. element_validate_number($element, $form_state);
  933. if (!form_get_error($element)) {
  934. if ($element['#value'] != '' && (float) $element['#value'] <= 0) {
  935. form_error($element, t('!name must be a positive number.', array('!name' => $element['#title'])));
  936. }
  937. }
  938. }
  939. /**
  940. * Calculate percent based on input, fallback if only one value is provided.
  941. *
  942. * @param array $data
  943. *
  944. * @return float[]|FALSE
  945. */
  946. function _canvasactions_resizepercent_calculate_percent(array $data) {
  947. // Fallback if only one value is provided.
  948. if (empty($data['height'])) {
  949. if (empty($data['width'])) {
  950. return FALSE;
  951. }
  952. $data['height'] = $data['width'];
  953. }
  954. else if (empty($data['width'])) {
  955. $data['width'] = $data['height'];
  956. }
  957. // Get percentage values in decimal values.
  958. $data['width'] = (float) $data['width'] / 100;
  959. $data['height'] = (float) $data['height'] / 100;
  960. return $data;
  961. }
  962. /**
  963. * Implements theme_hook() for the resize percent effect summary.
  964. *
  965. * @param array $variables
  966. * An associative array containing:
  967. * - data: The current configuration for this image effect.
  968. *
  969. * @return string
  970. * The HTML for the summary of this image effect.
  971. * @ingroup themeable
  972. */
  973. function theme_canvasactions_resizepercent_summary(array $variables) {
  974. $data = _canvasactions_resizepercent_calculate_percent($variables['data']);
  975. if (!$data) {
  976. return t('Invalid effect data');
  977. }
  978. if ($data['width'] != $data['height']) {
  979. return t('@width%x@height%', array('@width' => 100 * $data['width'], '@height' => 100 * $data['height']));
  980. }
  981. else {
  982. return t('scale to @percent%', array('@percent' => (float) 100 * $data['height']));
  983. }
  984. }
  985. /**
  986. * Image effect callback for the resize percent effect.
  987. *
  988. * @param stdClass $image
  989. * @param array $data
  990. *
  991. * @return boolean
  992. * true on success, false otherwise.
  993. */
  994. function canvasactions_resizepercent_effect(stdClass $image, array $data) {
  995. $data = _canvasactions_resizepercent_calculate_percent($data);
  996. $data['width'] = (int) round($image->info['width'] * $data['width']);
  997. $data['height'] = (int) round($image->info['height'] * $data['height']);
  998. return image_resize_effect($image, $data);
  999. }
  1000. /**
  1001. * Image dimensions callback for the resize percent effect.
  1002. *
  1003. * @param array $dimensions
  1004. * Dimensions to be modified - an associative array containing the items
  1005. * 'width' and 'height' (in pixels).
  1006. * @param array $data
  1007. * An associative array containing the effect data.
  1008. */
  1009. function canvasactions_resizepercent_dimensions(array &$dimensions, array $data) {
  1010. $data = _canvasactions_resizepercent_calculate_percent($data);
  1011. $dimensions['width'] = (int) round($dimensions['width'] * $data['width']);
  1012. $dimensions['height'] = (int) round($dimensions['height'] * $data['height']);
  1013. }
  1014. /**
  1015. * Image effect form callback for the blur effect.
  1016. *
  1017. * @param array $data
  1018. * The current configuration for this image effect.
  1019. *
  1020. * @return array
  1021. * The form definition for this effect.
  1022. */
  1023. function canvasactions_blur_form(array $data) {
  1024. $form['intensity'] = array(
  1025. '#type' => 'textfield',
  1026. '#title' => t('Blur intensity'),
  1027. '#description' => t('A higher intensity results in more blur. The larger the image, the larger value you need to get a really blurred image, think 50 to 100 for 600x400 images.'),
  1028. '#size' => 5,
  1029. '#default_value' => isset($data['intensity']) ? (int) $data['intensity'] : 2,
  1030. '#element_validate' => array('element_validate_integer_positive'),
  1031. );
  1032. return $form;
  1033. }
  1034. /**
  1035. * Implements theme_hook() for the underlay (background) effect summary.
  1036. *
  1037. * @param array $variables
  1038. * An associative array containing:
  1039. * - data: The current configuration for this image effect.
  1040. *
  1041. * @return string
  1042. * The HTML for the summary of this image effect.
  1043. * @ingroup themeable
  1044. */
  1045. function theme_canvasactions_blur_summary($variables) {
  1046. return t('Intensity: @intensity', array('@intensity' => $variables['data']['intensity']));
  1047. }
  1048. /**
  1049. * Image effect callback for the resize percent effect.
  1050. *
  1051. * @param stdClass $image
  1052. * @param array $data
  1053. *
  1054. * @return boolean
  1055. * true on success, false otherwise.
  1056. */
  1057. function canvasactions_blur_effect(stdClass $image, array $data) {
  1058. return image_toolkit_invoke('blur', $image, $data);
  1059. }
  1060. /**
  1061. * GD toolkit specific implementation of the blur effect.
  1062. *
  1063. * @param stdClass $image
  1064. * @param int $intensity
  1065. * The number of times to apply the blur filter.
  1066. *
  1067. * @return boolean
  1068. * True on success, false otherwise.
  1069. */
  1070. function image_gd_blur(stdClass $image, $intensity) {
  1071. $intensity = (int) $intensity;
  1072. $result = TRUE;
  1073. $i = 0;
  1074. while ($result && $i++ < $intensity) {
  1075. $result = imagefilter($image->resource, IMG_FILTER_GAUSSIAN_BLUR);
  1076. }
  1077. return $result;
  1078. }
  1079. /**
  1080. * Imagemagick toolkit specific implementation of the blur effect.
  1081. *
  1082. * See http://www.imagemagick.org/Usage/blur/.
  1083. *
  1084. * @param stdClass $image
  1085. * @param int $intensity
  1086. * The "intensity" of the blur effect.
  1087. *
  1088. * @return boolean
  1089. * True on success, false otherwise.
  1090. */
  1091. function image_imagemagick_blur(stdClass $image, $intensity) {
  1092. // To get similar results asd with the GD factor, we use a formula to alter
  1093. // the intensity into the sigma value that is passed to IM.
  1094. $sigma = 4.0 + 0.8 * $intensity;
  1095. $image->ops[] = '-blur ' . escapeshellarg(sprintf('0x%f', $sigma));
  1096. return TRUE;
  1097. }
  1098. /**
  1099. * Builds the interlace form.
  1100. *
  1101. * This effect has no options, only some help text, so the form is displayed
  1102. * anyway.
  1103. */
  1104. function canvasactions_interlace_form() {
  1105. $form = array();
  1106. $form['help'] = array(
  1107. '#markup' => '<p><strong>There are no user-configurable options for this process.</strong></p>
  1108. <p>This effect will save the derivative image in an interlace / progressive way
  1109. which might improve perceived performance, especially for large images.
  1110. File size and loading speed will not change, but the user will pretty quickly
  1111. see a "degraded" copy of the entire image instead of a clear copy of the upper
  1112. part of the image.</p>
  1113. <p>Wikipedia: <a href="https://en.wikipedia.org/wiki/Interlacing_(bitmaps)">Interlacing (bitmaps)</a></p>',
  1114. );
  1115. return $form;
  1116. }
  1117. /**
  1118. * Image effect callback for the Interlace / Progressive effect.
  1119. *
  1120. * @param stdClass $image
  1121. * @param array $data
  1122. *
  1123. * @return bool
  1124. * true on success, false otherwise.
  1125. */
  1126. function canvasactions_interlace_effect(stdClass $image, array $data) {
  1127. return image_toolkit_invoke('interlace', $image, array($data));
  1128. }
  1129. /**
  1130. * GD toolkit specific implementation of the image interlace effect.
  1131. *
  1132. * @param stdClass $image
  1133. * Image object containing the GD image resource to operate on.
  1134. * param array $data
  1135. * The current configuration for this image effect.
  1136. *
  1137. * @return bool
  1138. * true on success, false otherwise.
  1139. */
  1140. function image_gd_interlace($image/*, array $data*/) {
  1141. imageinterlace($image->resource, 1);
  1142. return TRUE;
  1143. }
  1144. /**
  1145. * Imagemagick toolkit specific implementation of the image interlace effect.
  1146. *
  1147. * @param stdClass $image
  1148. * Image object containing the image resource to operate on.
  1149. * param array $data
  1150. * The current configuration for this image effect.
  1151. *
  1152. * @return bool
  1153. * true on success, false otherwise.
  1154. */
  1155. function image_imagemagick_interlace($image/*, array $data*/) {
  1156. $image->ops[] = '-interlace Plane';
  1157. return TRUE;
  1158. }