imagecache_coloractions.module 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. <?php
  2. /**
  3. * @file
  4. * Additional actions for imagecache processing.
  5. *
  6. * Exposes some of the simpler PHP 'imagefilter' actions (colorshift,
  7. * brightness, negative)
  8. * - A transparency masker for merging with backgrounds.
  9. * - A pseudo - file conversion feature.
  10. *
  11. * Compatible with the 2008 revision (imagecache 2)
  12. *
  13. * @author dan http://coders.co.nz
  14. * @author sydneyshan http://enigmadigital.net.au
  15. */
  16. if (! function_exists('imagecache_actions_calculate_relative_position') ) {
  17. module_load_include('inc', 'imagecache_actions', 'utility');
  18. }
  19. module_load_include('inc', 'imagecache_actions', 'utility-color');
  20. // There is no way to specify a file in hook_image_effect_info,
  21. // so placing this here for the time being.
  22. include_once dirname(__FILE__) . '/transparency.inc';
  23. /**
  24. * Implements hook_image_effect_info().
  25. *
  26. * Defines information about the supported effects.
  27. */
  28. function imagecache_coloractions_image_effect_info() {
  29. // @todo: standardize naming. requires a hook_update_n().
  30. $effects = array();
  31. $effects['coloractions_colorshift'] = array(
  32. 'label' => t('Color Shift'),
  33. 'help' => t('Adjust image colors.'),
  34. 'effect callback' => 'coloractions_colorshift_effect',
  35. 'dimensions passthrough' => TRUE,
  36. 'form callback' => 'coloractions_colorshift_form',
  37. 'summary theme' => 'coloractions_colorshift_summary',
  38. );
  39. $effects['imagecache_coloroverlay'] = array(
  40. 'label' => t('Color Overlay'),
  41. 'help' => t('Apply a color tint to an image (retaining blacks and whites).'),
  42. 'effect callback' => 'coloractions_coloroverlay_effect',
  43. 'dimensions passthrough' => TRUE,
  44. 'form callback' => 'coloractions_coloroverlay_form',
  45. 'summary theme' => 'coloractions_coloroverlay_summary',
  46. );
  47. $effects['imagecache_colormultiply'] = array(
  48. 'label' => t('Color Multiply'),
  49. 'help' => t('Apply a multiply blend effect to an image. The result color is always a darker color.'),
  50. 'effect callback' => 'coloractions_colormultiply_effect',
  51. 'dimensions passthrough' => TRUE,
  52. 'form callback' => 'coloractions_colormultiply_form',
  53. 'summary theme' => 'coloractions_colormultiply_summary',
  54. );
  55. $effects['coloractions_brightness'] = array(
  56. 'label' => t('Brightness'),
  57. 'help' => t('Adjust image brightness.'),
  58. 'effect callback' => 'coloractions_brightness_effect',
  59. 'dimensions passthrough' => TRUE,
  60. 'form callback' => 'coloractions_brightness_form',
  61. 'summary theme' => 'coloractions_brightness_summary',
  62. );
  63. // @todo: changing inverse to invert at this place requires a hook_update_n().
  64. $effects['coloractions_inverse'] = array(
  65. 'label' => t('Negative Image'),
  66. 'help' => t('Invert colors and brightness.'),
  67. 'effect callback' => 'coloractions_invert_effect',
  68. 'dimensions passthrough' => TRUE,
  69. 'form callback' => 'coloractions_invert_form',
  70. );
  71. // @todo Convert may need a little more work.
  72. $effects['coloractions_convert'] = array(
  73. 'label' => t('Change file format'),
  74. 'help' => t('Choose to save the image as a different filetype.'),
  75. 'effect callback' => 'coloractions_convert_effect',
  76. 'dimensions passthrough' => TRUE,
  77. 'form callback' => 'coloractions_convert_form',
  78. 'summary theme' => 'coloractions_convert_summary',
  79. );
  80. $effects['coloractions_posterize'] = array(
  81. 'label' => t('Posterize'),
  82. 'help' => t('Reduce the image to a limited number of color levels per channel.'),
  83. 'effect callback' => 'coloractions_posterize_effect',
  84. 'dimensions passthrough' => TRUE,
  85. 'form callback' => 'coloractions_posterize_form',
  86. 'summary theme' => 'coloractions_posterize_summary',
  87. );
  88. $effects['imagecache_alpha'] = array(
  89. 'label' => t('Alpha Transparency'),
  90. 'help' => t('Adjust transparency.'),
  91. 'effect callback' => 'coloractions_alpha_effect',
  92. 'dimensions passthrough' => TRUE,
  93. 'form callback' => 'coloractions_alpha_form',
  94. 'summary theme' => 'coloractions_alpha_summary',
  95. );
  96. $effects['imagecache_adjustlevels'] = array(
  97. 'label' => t('Adjust Levels'),
  98. 'help' => t('Adjust the color levels of the image.'),
  99. 'effect callback' => 'coloractions_adjustlevels_effect',
  100. 'dimensions passthrough' => TRUE,
  101. 'form callback' => 'coloractions_adjustlevels_form',
  102. 'summary theme' => 'coloractions_adjustlevels_summary',
  103. );
  104. $effects['imagecache_desaturatealpha'] = array(
  105. 'label' => t('Desaturate Alpha'),
  106. 'help' => t('Desaturate the image while retaining transparency.'),
  107. 'effect callback' => 'coloractions_desaturatealpha_effect',
  108. 'dimensions passthrough' => TRUE,
  109. 'summary theme' => 'coloractions_desaturatealpha_summary',
  110. );
  111. $effects['imagecache_removeanimation'] = array(
  112. 'label' => t('Remove animation'),
  113. 'help' => t('Freezes an animated image, keeping only the first frame.'),
  114. 'effect callback' => 'coloractions_removeanimation_effect',
  115. 'dimensions passthrough' => TRUE,
  116. 'form callback' => 'coloractions_removeanimation_form',
  117. 'summary theme' => 'coloractions_removeanimation_summary',
  118. );
  119. return $effects;
  120. }
  121. /**
  122. * Implements hook_theme().
  123. *
  124. * Registers theme functions for the effect summaries.
  125. */
  126. function imagecache_coloractions_theme() {
  127. return array(
  128. 'coloractions_colorshift_summary' => array(
  129. 'variables' => array('data' => NULL),
  130. ),
  131. 'coloractions_coloroverlay_summary' => array(
  132. 'variables' => array('data' => NULL),
  133. ),
  134. 'coloractions_colormultiply_summary' => array(
  135. 'variables' => array('data' => NULL),
  136. ),
  137. 'coloractions_brightness_summary' => array(
  138. 'variables' => array('data' => NULL),
  139. ),
  140. 'coloractions_convert_summary' => array(
  141. 'variables' => array('data' => NULL),
  142. ),
  143. 'coloractions_posterize_summary' => array(
  144. 'variables' => array('data' => NULL),
  145. ),
  146. 'coloractions_alpha_summary' => array(
  147. 'variables' => array('data' => NULL),
  148. 'file' => 'transparency.inc',
  149. ),
  150. 'coloractions_adjustlevels_summary' => array(
  151. 'variables' => array('data' => NULL),
  152. ),
  153. 'coloractions_desaturatealpha_summary' => array(
  154. 'variables' => array('data' => NULL),
  155. ),
  156. 'coloractions_removeanimation_summary' => array(
  157. 'variables' => array('data' => NULL),
  158. ),
  159. );
  160. }
  161. /**
  162. * Implements hook_image_style_flush().
  163. *
  164. * This hook checks if the style contains a change format image effect and, if
  165. * so, creates an .htaccess file in the root of the derivative folder that
  166. * forces the correct Content-Type header on images served from that folder.
  167. *
  168. * @param array $style
  169. */
  170. function imagecache_coloractions_image_style_flush($style) {
  171. if (!is_array($style)) {
  172. // See [#2190759].
  173. return;
  174. }
  175. // Error in core: the old style + set of effects is passed in. This means
  176. // that when a convert effect is added or deleted we won't notice. So we
  177. // "change" the order of execution by duplicating these lines from
  178. // image_style_flush():
  179. // Clear image style and effect caches.
  180. cache_clear_all('image_styles', 'cache');
  181. cache_clear_all('image_effects:', 'cache', TRUE);
  182. drupal_static_reset('image_styles');
  183. drupal_static_reset('image_effects');
  184. // Now load the current state of our style.
  185. $new_style = image_style_load(isset($style['name']) ? $style['name'] : NULL, isset($style['isid']) ? $style['isid'] : NULL);
  186. // If the style is flushed because it is being deleted it might be gone.
  187. if (is_array($new_style)) {
  188. // Now back to our actual work: determine if we have to crate an .htaccess
  189. // file.
  190. include_once dirname(__FILE__) . '/imagecache_coloractions.htaccess_creator.inc';
  191. imagecache_coloractions_create_htaccess_for_style($new_style);
  192. }
  193. }
  194. /**
  195. * Image effect form callback for the color shift effect.
  196. *
  197. * @param array $data
  198. * The current configuration for this image effect.
  199. *
  200. * @return array
  201. * The form definition for this effect.
  202. */
  203. function coloractions_colorshift_form(array $data) {
  204. $defaults = array(
  205. 'RGB' => array(
  206. 'HEX' => '#FF0000',
  207. ),
  208. );
  209. $data = array_merge($defaults, (array) $data);
  210. $form = array('#theme' => 'imagecache_rgb_form');
  211. $form['RGB'] = imagecache_rgb_form($data['RGB']);
  212. $form['note'] = array('#value' => t("<p>
  213. Note that colorshift is a mathematical filter that doesn't always
  214. have the expected result.
  215. To shift an image precisely TO a target color,
  216. desaturate (greyscale) it before colorizing.
  217. The hue (color wheel) is the <em>direction</em> the
  218. existing colors are shifted. The tone (inner box) is the amount.
  219. Keep the tone half-way up the left side of the color box
  220. for best results.
  221. </p>"));
  222. return $form;
  223. }
  224. /**
  225. * Implements theme_hook() for the color shift effect summary.
  226. *
  227. * @param array $variables
  228. * An associative array containing:
  229. * - data: The current configuration for this image effect.
  230. *
  231. * @return string
  232. * The HTML for the summary of this image effect.
  233. * @ingroup themeable
  234. */
  235. function theme_coloractions_colorshift_summary(array $variables) {
  236. return theme_imagecacheactions_rgb($variables['data']);
  237. }
  238. /**
  239. * Image effect callback for the color shift effect.
  240. *
  241. * @param stdClass $image
  242. * @param array $data
  243. *
  244. * @return bool
  245. * true on success, false otherwise.
  246. */
  247. function coloractions_colorshift_effect(stdClass $image, array $data) {
  248. // convert color from hex (as it is stored in the UI)
  249. if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
  250. $data['RGB'] = array_merge($data['RGB'], $deduced);
  251. }
  252. return image_toolkit_invoke('colorshift', $image, array($data));
  253. }
  254. /**
  255. * GD toolkit specific implementation of the color shift effect.
  256. *
  257. * @param stdClass $image
  258. * @param array $data
  259. * The parameters for this effect.
  260. *
  261. * @return bool
  262. * true on success, false otherwise.
  263. */
  264. function image_gd_colorshift(stdClass $image, array $data) {
  265. $RGB = $data['RGB'];
  266. if (!function_exists('imagefilter')) {
  267. module_load_include('inc', 'imagecache_actions', 'imagefilter');
  268. }
  269. return imagefilter($image->resource, 4, $RGB['red'], $RGB['green'], $RGB['blue']);
  270. }
  271. /**
  272. * Imagemagick toolkit specific implementation of the color shift effect.
  273. *
  274. * @param stdClass $image
  275. * @param array $data
  276. * The parameters for this effect.
  277. *
  278. * @return bool
  279. * true on success, false otherwise.
  280. */
  281. function image_imagemagick_colorshift(stdClass $image, array $data) {
  282. $RGB = $data['RGB'];
  283. $image->ops[] = "-fill rgb" . escapeshellcmd('(') . "{$RGB['red']},{$RGB['green']},{$RGB['blue']}" . escapeshellcmd(')') . " -colorize 50" . escapeshellcmd('%');
  284. return TRUE;
  285. }
  286. /**
  287. * Image effect form callback for the color overlay effect.
  288. *
  289. * @param array $data
  290. * The current configuration for this image effect.
  291. *
  292. * @return array
  293. * The form definition for this effect.
  294. */
  295. function coloractions_coloroverlay_form(array $data) {
  296. $defaults = array(
  297. 'RGB' => array(
  298. 'HEX' => '',
  299. ),
  300. );
  301. $data = array_merge($defaults, (array) $data);
  302. $form = array('#theme' => 'imagecache_rgb_form');
  303. $form['RGB'] = imagecache_rgb_form($data['RGB']);
  304. $form['note'] = array('#value' => t("<p>
  305. Note that color overlay is a mathematical filter that doesn't always
  306. have the expected result.
  307. To shift an image precisely TO a target color,
  308. desaturate (greyscale) it before colorizing.
  309. The hue (color wheel) is the <em>direction</em> the
  310. existing colors are shifted. The tone (inner box) is the amount.
  311. Keep the tone half-way up the left side of the color box
  312. for best results.
  313. </p>"));
  314. return $form;
  315. }
  316. /**
  317. * Implements theme_hook() for the color overlay effect summary.
  318. *
  319. * @param array $variables
  320. * An associative array containing:
  321. * - data: The current configuration for this image effect.
  322. *
  323. * @return string
  324. * The HTML for the summary of this image effect.
  325. * @ingroup themeable
  326. */
  327. function theme_coloractions_coloroverlay_summary(array $variables) {
  328. return theme_imagecacheactions_rgb($variables['data']);
  329. }
  330. /**
  331. * Image effect callback for the color overlay effect.
  332. *
  333. * @param stdClass $image
  334. * @param array $data
  335. *
  336. * @return bool
  337. * true on success, false otherwise.
  338. */
  339. function coloractions_coloroverlay_effect(stdClass $image, array $data) {
  340. // convert color from hex (as it is stored in the UI)
  341. if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
  342. $data['RGB'] = array_merge($data['RGB'], $deduced);
  343. }
  344. return image_toolkit_invoke('coloroverlay', $image, array($data));
  345. }
  346. /**
  347. * GD toolkit specific implementation of the color overlay effect.
  348. *
  349. * @param stdClass $image
  350. * @param array $data
  351. * The parameters for this effect.
  352. *
  353. * @return bool
  354. * true on success, false otherwise.
  355. */
  356. function image_gd_coloroverlay(stdClass $image, array $data) {
  357. $RGB = $data['RGB'];
  358. $w = $image->info['width'];
  359. $h = $image->info['height'];
  360. for($y=0;$y<$h;$y++) {
  361. for($x=0;$x<$w;$x++) {
  362. $rgb = imagecolorat($image->resource, $x, $y);
  363. $source = imagecolorsforindex($image->resource, $rgb);
  364. if($source['red'] <= 128){
  365. $final_r = (2 * $source['red'] * $RGB['red'])/256;
  366. }else{
  367. $final_r = 255 - (((255 - (2 * ($source['red'] - 128))) * (255 - $RGB['red']))/256);
  368. }
  369. if($source['green'] <= 128){
  370. $final_g = (2 * $source['green'] * $RGB['green'])/256;
  371. }else{
  372. $final_g = 255 - (((255 - (2 * ($source['green'] - 128))) * (255 - $RGB['green']))/256);
  373. }
  374. if($source['blue'] <= 128){
  375. $final_b = (2 * $source['blue'] * $RGB['blue'])/256;
  376. }else{
  377. $final_b = 255 - (((255 - (2 * ($source['blue'] - 128))) * (255 - $RGB['blue']))/256);
  378. }
  379. $final_colour = imagecolorallocatealpha($image->resource, $final_r, $final_g, $final_b, $source['alpha']);
  380. imagesetpixel($image->resource, $x, $y, $final_colour);
  381. }
  382. }
  383. return TRUE;
  384. }
  385. /**
  386. * Imagemagick toolkit specific implementation of the color overlay effect.
  387. *
  388. * @param stdClass $image
  389. * @param array $data
  390. * The parameters for this effect.
  391. *
  392. * @return bool
  393. * true on success, false otherwise.
  394. */
  395. function image_imagemagick_coloroverlay(stdClass $image, array $data) {
  396. $RGB = $data['RGB'];
  397. $image->ops[] = escapeshellcmd('(') . " +clone +matte -fill rgb" . escapeshellcmd('(') . "{$RGB['red']},{$RGB['green']},{$RGB['blue']}" . escapeshellcmd(')') . " -colorize 100" . escapeshellcmd('%') . " +clone +swap -compose overlay -composite " . escapeshellcmd(')') . " -compose SrcIn -composite";
  398. return TRUE;
  399. }
  400. /**
  401. * Image effect form callback for the color multiply effect.
  402. *
  403. * @param array $data
  404. * The current configuration for this image effect.
  405. *
  406. * @return array
  407. * The form definition for this effect.
  408. */
  409. function coloractions_colormultiply_form(array $data) {
  410. $defaults = array(
  411. 'RGB' => array(
  412. 'HEX' => '',
  413. ),
  414. );
  415. $data = array_merge($defaults, (array) $data);
  416. $form = array('#theme' => 'imagecache_rgb_form');
  417. $form['RGB'] = imagecache_rgb_form($data['RGB']);
  418. $form['note'] = array('#value' => t("<p>
  419. Note that color multiply is a mathematical filter that doesn't always
  420. have the expected result.
  421. To shift an image precisely TO a target color,
  422. desaturate (greyscale) it before colorizing.
  423. The hue (color wheel) is the <em>direction</em> the
  424. existing colors are shifted. The tone (inner box) is the amount.
  425. Keep the tone half-way up the left side of the color box
  426. for best results.
  427. </p>"));
  428. return $form;
  429. }
  430. /**
  431. * Implements theme_hook() for the color multiply effect summary.
  432. *
  433. * @param array $variables
  434. * An associative array containing:
  435. * - data: The current configuration for this image effect.
  436. *
  437. * @return string
  438. * The HTML for the summary of this image effect.
  439. * @ingroup themeable
  440. */
  441. function theme_coloractions_colormultiply_summary(array $variables) {
  442. return theme_imagecacheactions_rgb($variables['data']);
  443. }
  444. /**
  445. * Image effect callback for the color multiply effect.
  446. *
  447. * @param stdClass $image
  448. * @param array $data
  449. *
  450. * @return bool
  451. * true on success, false otherwise.
  452. */
  453. function coloractions_colormultiply_effect(stdClass $image, array $data) {
  454. // Convert color from hex (as it is stored in the UI).
  455. if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
  456. $data['RGB'] = array_merge($data['RGB'], $deduced);
  457. }
  458. return image_toolkit_invoke('colormultiply', $image, array($data));
  459. }
  460. /**
  461. * GD toolkit specific implementation of the color multiply effect.
  462. *
  463. * @param stdClass $image
  464. * @param array $data
  465. * The parameters for this effect.
  466. *
  467. * @return bool
  468. * true on success, false otherwise.
  469. */
  470. function image_gd_colormultiply(stdClass $image, array $data) {
  471. $factor_r = $data['RGB']['red'] / 255;
  472. $factor_g = $data['RGB']['green'] / 255;
  473. $factor_b = $data['RGB']['blue'] / 255;
  474. $w = $image->info['width'];
  475. $h = $image->info['height'];
  476. for ($y = 0; $y < $h; $y++) {
  477. for ($x = 0; $x < $w; $x++) {
  478. $rgb = imagecolorat($image->resource, $x, $y);
  479. $source = imagecolorsforindex($image->resource, $rgb);
  480. $final_r = (int) ($source['red'] * $factor_r);
  481. $final_g = (int) ($source['green'] * $factor_g);
  482. $final_b = (int) ($source['blue'] * $factor_b);
  483. $final_colour = imagecolorallocate($image->resource, $final_r, $final_g, $final_b);
  484. if ($final_colour === FALSE) {
  485. return FALSE;
  486. }
  487. if (!imagesetpixel($image->resource, $x, $y, $final_colour)) {
  488. return FALSE;
  489. }
  490. }
  491. }
  492. return TRUE;
  493. }
  494. /**
  495. * Imagemagick toolkit specific implementation of the color multiply effect.
  496. *
  497. * @param stdClass $image
  498. * @param array $data
  499. * The parameters for this effect.
  500. *
  501. * @return bool
  502. * true on success, false otherwise.
  503. */
  504. function image_imagemagick_colormultiply(stdClass $image, array $data) {
  505. $multiply_color = $data['RGB']['HEX'] != '' ? '#' . ltrim($data['RGB']['HEX'], '#') : 'None';
  506. $image->ops[] = escapeshellcmd('(') . ' +clone -fill ' . escapeshellarg($multiply_color) . ' -colorize 100 ' . escapeshellcmd(')');
  507. $image->ops[] = '-compose multiply -composite';
  508. return TRUE;
  509. }
  510. /**
  511. * Image effect form callback for the brightness effect.
  512. *
  513. * @param array $data
  514. * The current configuration for this image effect.
  515. *
  516. * @return array
  517. * The form definition for this effect.
  518. */
  519. function coloractions_brightness_form(array $data) {
  520. $default = array('filter_arg1' => '100');
  521. $data = array_merge($default, (array) $data);
  522. $form = array();
  523. $form['help'] = array('#value' => t("The brightness effect seldom looks good on its own, but can be useful to wash out an image before making it transparent - eg for a watermark."));
  524. $form['filter_arg1'] = array(
  525. '#type' => 'textfield',
  526. '#title' => t('Brightness'),
  527. '#description' => t('-255 - +255'),
  528. '#default_value' => $data['filter_arg1'],
  529. '#size' => 3,
  530. );
  531. return $form;
  532. }
  533. /**
  534. * Implements theme_hook() for the brightness effect summary.
  535. *
  536. * @param array $variables
  537. * An associative array containing:
  538. * - data: The current configuration for this image effect.
  539. *
  540. * @return string
  541. * The HTML for the summary of this image effect.
  542. * @ingroup themeable
  543. */
  544. function theme_coloractions_brightness_summary(array $variables) {
  545. return t("Adjust") . " : " . $variables['data']['filter_arg1'];
  546. }
  547. /**
  548. * Image effect callback for the brightness effect.
  549. *
  550. * @param stdClass $image
  551. * @param array $data
  552. *
  553. * @return bool
  554. * true on success, false otherwise.
  555. */
  556. function coloractions_brightness_effect(stdClass $image, array $data) {
  557. return image_toolkit_invoke('brightness', $image, array($data));
  558. }
  559. /**
  560. * GD toolkit specific implementation of the brightness effect.
  561. *
  562. * @param stdClass $image
  563. * @param array $data
  564. * The parameters for this effect.
  565. *
  566. * @return bool
  567. * true on success, false otherwise.
  568. */
  569. function image_gd_brightness(stdClass $image, array $data) {
  570. if (!function_exists('imagefilter')) {
  571. module_load_include('inc', 'imagecache_actions', 'imagefilter'); }
  572. return imagefilter($image->resource, 2, $data['filter_arg1']);
  573. }
  574. /**
  575. * Imagemagick toolkit specific implementation of the brightness effect.
  576. *
  577. * @param stdClass $image
  578. * @param array $data
  579. * The parameters for this effect.
  580. *
  581. * @return bool
  582. * true on success, false otherwise.
  583. */
  584. function image_imagemagick_brightness(stdClass $image, array $data) {
  585. $image->ops[] = "-modulate " . (int)(100 + ( $data['filter_arg1'] / 128 * 100 ));
  586. return TRUE;
  587. }
  588. /**
  589. * Image effect form callback for the image invert effect.
  590. *
  591. * This effect has no parameters.
  592. *
  593. * param array $data
  594. * The current configuration for this image effect.
  595. *
  596. * @return array
  597. * The form definition for this effect.
  598. */
  599. function coloractions_invert_form(/*array $data*/) {
  600. $form = array();
  601. return $form;
  602. }
  603. /**
  604. * Image effect callback for the image invert effect.
  605. *
  606. * @param stdClass $image
  607. * @param array $data
  608. *
  609. * @return bool
  610. * true on success, false otherwise.
  611. */
  612. function coloractions_invert_effect(stdClass $image, array $data) {
  613. return image_toolkit_invoke('invert', $image, array($data));
  614. }
  615. /**
  616. * GD toolkit specific implementation of the image invert effect.
  617. *
  618. * @param stdClass $image
  619. * param array $data
  620. * The parameters for this effect.
  621. *
  622. * @return bool
  623. * true on success, false otherwise.
  624. */
  625. function image_gd_invert(stdClass $image/*, array $data*/) {
  626. if (!function_exists('imagefilter')) {
  627. module_load_include('inc', 'imagecache_actions', 'imagefilter');
  628. }
  629. return imagefilter($image->resource, 0);
  630. }
  631. /**
  632. * Imagemagick toolkit specific implementation of the image invert effect.
  633. *
  634. * @param stdClass $image
  635. * param array $data
  636. * The parameters for this effect.
  637. *
  638. * @return bool
  639. * true on success, false otherwise.
  640. */
  641. function image_imagemagick_invert(stdClass $image/*, array $data*/) {
  642. // http://www.imagemagick.org/script/command-line-options.php?#negate
  643. $image->ops[] = "-negate";
  644. return TRUE;
  645. }
  646. /**
  647. * Image effect form callback for the convert image format effect.
  648. *
  649. * @param array $data
  650. * The current configuration for this image effect.
  651. *
  652. * @return array
  653. * The form definition for this effect.
  654. */
  655. function coloractions_convert_form(array $data) {
  656. $defaults = array(
  657. 'format' => 'image/png',
  658. 'quality' => '75',
  659. );
  660. $data = array_merge($defaults, $data);
  661. $form = array(
  662. 'help' => array(
  663. '#markup' => t("If you've been using transparencies in the process, the result may get saved as a PNG (as the image was treated as a one in in-between processes). If this is not desired (file sizes may get too big) you should use this process to force a flatten action before saving. "),
  664. ),
  665. 'help2' => array(
  666. '#markup' => t("For technical reasons, changing the file format within imagecache does <em>not</em> change the filename suffix. A png may be saved as a *.jpg or vice versa. This may confuse some browsers and image software, but most of them have no trouble. "),
  667. ),
  668. 'format' => array(
  669. '#title' => t("File format"),
  670. '#type' => 'select',
  671. '#default_value' => isset($data['format']) ? $data['format'] : 'image/png',
  672. '#options' => coloractions_file_formats(),
  673. ),
  674. 'quality' => array(
  675. '#type' => 'textfield',
  676. '#title' => t('Quality'),
  677. '#description' => t('Override the default image quality. Works for Imagemagick only. Ranges from 0 to 100. For jpg, higher values mean better image quality but bigger files. For png it is a combination of compression and filter'),
  678. '#size' => 10,
  679. '#maxlength' => 3,
  680. '#default_value' => $data['quality'],
  681. '#field_suffix' => '%',
  682. ),
  683. );
  684. return $form;
  685. }
  686. /**
  687. * Implements theme_hook() for the convert image format effect summary.
  688. *
  689. * @param array $variables
  690. * An associative array containing:
  691. * - data: The current configuration for this image effect.
  692. *
  693. * @return string
  694. * The HTML for the summary of this image effect.
  695. * @ingroup themeable
  696. */
  697. function theme_coloractions_convert_summary($variables) {
  698. $data = $variables['data'];
  699. $formats = coloractions_file_formats();
  700. if ($formats[$data['format']] == 'jpg') {
  701. return t('Convert to: @format, quality: @quality%', array(
  702. '@format' => $formats[$data['format']],
  703. '@quality' => $data['quality']
  704. ));
  705. }
  706. else {
  707. return t("Convert to") .": ". $formats[$data['format']];
  708. }
  709. }
  710. /**
  711. * Image effect callback for the convert image format effect.
  712. *
  713. * @param stdClass $image
  714. * @param array $data
  715. *
  716. * @return bool
  717. * true on success, false otherwise.
  718. */
  719. function coloractions_convert_effect(stdClass $image, array $data) {
  720. $formats = coloractions_file_formats();
  721. $image->info['mime_type'] = $data['format'];
  722. $image->info['extension'] = $formats[$data['format']];
  723. image_toolkit_invoke('convert', $image, array($data));
  724. return TRUE;
  725. }
  726. /**
  727. * GD toolkit specific implementation of the convert image format effect.
  728. *
  729. * param stdClass $image
  730. * param array $data
  731. * The parameters for this effect.
  732. *
  733. * @return bool
  734. * true on success, false otherwise.
  735. */
  736. function image_gd_convert(/*stdClass $image, array $data*/) {
  737. return TRUE;
  738. }
  739. /**
  740. * Imagemagick toolkit specific implementation of the color shift effect.
  741. *
  742. * Converting the image format with imagemagick is done by prepending the output
  743. * format to the target file separated by a colon (:). This is done with
  744. * hook_imagemagick_arguments_alter(), see below.
  745. *
  746. * @param stdClass $image
  747. * @param array $data
  748. * The parameters for this effect.
  749. *
  750. * @return bool
  751. * true on success, false otherwise.
  752. */
  753. function image_imagemagick_convert(stdClass $image, array $data) {
  754. $image->ops['output_format'] = $image->info['extension'];
  755. $image->ops['custom_quality_value'] = (int) $data['quality'];
  756. return TRUE;
  757. }
  758. /**
  759. * Implements hook_imagemagick_arguments_alter().
  760. *
  761. * This hook moves a change in output format from the args (action list) to the
  762. * destination format setting within the context.
  763. */
  764. function imagecache_coloractions_imagemagick_arguments_alter(&$args, &$context) {
  765. if (isset($args['output_format'])) {
  766. $context['destination_format'] = $args['output_format'];
  767. unset($args['output_format']);
  768. }
  769. if (isset($args['custom_quality_value'])) {
  770. $args['quality'] = sprintf('-quality %d', $args['custom_quality_value']);
  771. unset($args['custom_quality_value']);
  772. }
  773. }
  774. /**
  775. * Mini mime-type list
  776. *
  777. * image_type_to_extension and image_type_to_mime_type?
  778. */
  779. function coloractions_file_formats() {
  780. return array('image/jpeg' => 'jpg', 'image/gif' => 'gif', 'image/png' => 'png');
  781. }
  782. /**
  783. * Image effect form callback for the posterize effect.
  784. *
  785. * @param array $data
  786. * The current configuration for this image effect.
  787. *
  788. * @return array
  789. * The form definition for this effect.
  790. */
  791. function coloractions_posterize_form(array $data) {
  792. $form = array();
  793. $form['colors'] = array(
  794. '#type' => 'textfield',
  795. '#title' => t('Color levels per channel'),
  796. '#default_value' => isset($data['colors']) ? $data['colors'] : '',
  797. '#required' => TRUE,
  798. '#size' => 10,
  799. '#element_validate' => array('image_effect_integer_validate'),
  800. '#allow_negative' => FALSE,
  801. '#description' => t('Number of unique values per color channel to reduce this image to. The transparency channel is left unchanged. This effect can be used to reduce file size on png images.'),
  802. );
  803. return $form;
  804. }
  805. /**
  806. * Implements theme_hook() for the posterize effect summary.
  807. *
  808. * @param array $variables
  809. * An associative array containing:
  810. * - data: The current configuration for this image effect.
  811. *
  812. * @return string
  813. * The HTML for the summary of this image effect.
  814. * @ingroup themeable
  815. */
  816. function theme_coloractions_posterize_summary(array $variables) {
  817. return t(': Reduce to @colors color levels per channel', array('@colors' => $variables['data']['colors']));
  818. }
  819. /**
  820. * Image effect callback for the posterize effect.
  821. *
  822. * @param stdClass $image
  823. * @param array $data
  824. *
  825. * @return bool
  826. * true on success, false otherwise.
  827. */
  828. function coloractions_posterize_effect(stdClass $image, array $data) {
  829. if (!image_toolkit_invoke('posterize', $image, array($data['colors']))) {
  830. watchdog('imagecache_actions', 'Image posterize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array(
  831. '%toolkit' => $image->toolkit,
  832. '%path' => $image->source,
  833. '%mimetype' => $image->info['mime_type'],
  834. '%dimensions' => $image->info['height'] . 'x' . $image->info['height'],
  835. ), WATCHDOG_ERROR);
  836. return FALSE;
  837. }
  838. return TRUE;
  839. }
  840. /**
  841. * GD toolkit specific implementation of the posterize effect.
  842. *
  843. * Based on:
  844. * http://www.qtcentre.org/threads/36385-Posterizes-an-image-with-results-identical-to-Gimp-s-Posterize-command?p=167712#post167712
  845. *
  846. * @param stdClass $image
  847. * @param int $colors
  848. * The parameter for this effect.
  849. *
  850. * @return bool
  851. * true on success, false otherwise.
  852. */
  853. function image_gd_posterize(stdClass $image, $colors) {
  854. // Value step for colors per channel.
  855. $round_to = 255 / ($colors - 1);
  856. $alpha_bit_mask = 255 << 24;
  857. for ($x = imagesx($image->resource); $x--; ) {
  858. for ($y = imagesy($image->resource); $y--; ) {
  859. $rgb = imagecolorat($image->resource, $x, $y);
  860. // Use bitmasks to extract numbers we want, faster equivalent to imagecolorsforindex().
  861. $a = $rgb & $alpha_bit_mask; // Alpha
  862. $r = $rgb >> 16 & 255; // Red
  863. $g = $rgb >> 8 & 255; // Green
  864. $b = $rgb & 255; // Blue
  865. // (int) (value + 0.5) faster equivalent to round() and already an int.
  866. $new_r = (int) (((int) ($r / $round_to + 0.5)) * $round_to + 0.5);
  867. $new_g = (int) (((int) ($g / $round_to + 0.5)) * $round_to + 0.5);
  868. $new_b = (int) (((int) ($b / $round_to + 0.5)) * $round_to + 0.5);
  869. // Faster equivalent to imagecolorallocatealpha().
  870. $color_combined = $a | ($new_r << 16) | ($new_g << 8) | $new_b;
  871. imagesetpixel($image->resource, $x, $y, $color_combined);
  872. }
  873. }
  874. return TRUE;
  875. }
  876. /**
  877. * Imagemagick toolkit specific implementation of the color shift effect.
  878. *
  879. * @param stdClass $image
  880. * @param int $colors
  881. * The parameter for this effect.
  882. *
  883. * @return bool
  884. * true on success, false otherwise.
  885. */
  886. function image_imagemagick_posterize(stdClass $image, $colors) {
  887. // In newer versions of ImageMagick dithering has no effect on posterize.
  888. // Turn dithering off on older versions of ImageMagick for consistency.
  889. $image->ops[] = ' +dither -posterize ' . (int) $colors;
  890. return TRUE;
  891. }
  892. /**
  893. * Image effect form callback for the brightness effect.
  894. *
  895. * Settings for color level adjustment actions.
  896. *
  897. * @param array $data
  898. * The current configuration for this image effect.
  899. *
  900. * @return array
  901. * The form definition for this effect.
  902. */
  903. function coloractions_adjustlevels_form(array $data) {
  904. $defaults = array(
  905. 'independent_colors' => FALSE,
  906. 'all_colors' => array(
  907. 'low' => 0,
  908. 'high' => 1,
  909. ),
  910. 'per_color' => array(
  911. 'low_red' => 0,
  912. 'high_red' => 1,
  913. 'low_green' => 0,
  914. 'high_green' => 1,
  915. 'low_blue' => 0,
  916. 'high_blue' => 1,
  917. ),
  918. );
  919. $data = array_merge($defaults, $data);
  920. $form = array(
  921. '#type' => 'container',
  922. 'help' => array(
  923. '#type' => 'markup',
  924. '#markup' => t("<p>Adjusting color levels scales the given channels to a range specified by the 'low' and 'high' values.
  925. These 'low' and 'high' values can be any value between 0 and 1.
  926. E.g. assume that 'low' is 0.2 and 'high' is 0.9.
  927. Pixels that had a value of 0, will get a value of 0.2 * 255 = 51 and pixels that had a value of 255, will get a value of 0.9 * 255 = 229.</p>
  928. <p>Note that color level adjustment is a mathematical filter and a such doesn't do automatic balancing.</p>"),
  929. ),
  930. '#element_validate' => array('coloractions_validate_form'),
  931. ) ;
  932. $form['independent_colors'] = array(
  933. '#type' => 'checkbox',
  934. '#title' => t('Set each color independently'),
  935. '#default_value' => $data['independent_colors'],
  936. );
  937. $form['all_colors'] = array(
  938. '#type' => 'container',
  939. '#tree' => TRUE,
  940. '#title' => t('All colors range'),
  941. '#required' => !$data['independent_colors'],
  942. '#states' => array(
  943. 'visible' => array(':input[name="data[independent_colors]"]' => array('checked' => FALSE)),
  944. 'required' => array(':input[name="data[independent_colors]"]' => array('checked' => FALSE)),
  945. ),
  946. );
  947. $form['all_colors'] += coloractions_adjustlevels_form_helper(array(
  948. 'low' => array('title' => t('Low'), 'default' => $data['all_colors']['low']),
  949. 'high' => array('title' => t('High'), 'default' => $data['all_colors']['high']),
  950. ));
  951. $form['per_color'] = array(
  952. '#type' => 'container',
  953. '#tree' => TRUE,
  954. '#title' => t('Individual Color Ranges'),
  955. '#required' => $data['independent_colors'],
  956. '#states' => array(
  957. 'visible' => array(':input[name="data[independent_colors]"]' => array('checked' => TRUE)),
  958. 'required' => array(':input[name="data[independent_colors]"]' => array('checked' => TRUE)),
  959. ),
  960. );
  961. $form['per_color'] += coloractions_adjustlevels_form_helper(array(
  962. 'low_red' => array('title' => t('Red Low'), 'default' => $data['per_color']['low_red']),
  963. 'high_red' => array('title' => t('Red High'), 'default' => $data['per_color']['high_red']),
  964. 'low_green' => array('title' => t('Green Low'), 'default' => $data['per_color']['low_green']),
  965. 'high_green' => array('title' => t('Green High'), 'default' => $data['per_color']['high_green']),
  966. 'low_blue' => array('title' => t('Blue Low'), 'default' => $data['per_color']['low_blue']),
  967. 'high_blue' => array('title' => t('Blue High'), 'default' => $data['per_color']['high_blue']),
  968. ));
  969. return $form;
  970. }
  971. /**
  972. * Helper function to create the form for the color level adjustment effect.
  973. *
  974. * @param array $data
  975. * Array containing the form elements
  976. * names as keys for array elements containing title and default value.
  977. *
  978. * @return array
  979. */
  980. function coloractions_adjustlevels_form_helper(array $data) {
  981. $form = array();
  982. foreach ($data as $name => $value) {
  983. $form[$name] = array(
  984. '#type' => 'textfield',
  985. '#title' => $value['title'],
  986. '#default_value' => $value['default'],
  987. '#size' => 5,
  988. '#element_validate' => array('coloractions_validate_scale_0_1'),
  989. );
  990. }
  991. return $form;
  992. }
  993. /**
  994. * Form element validation handler for elements that should contain a number
  995. * between 0 and 1.
  996. */
  997. function coloractions_validate_scale_0_1($element/*, &$form_state*/) {
  998. $value = $element['#value'];
  999. if ($value != '' && (!is_numeric($value) || (float) $value > 1.0 || (float) $value < 0.0)) {
  1000. form_error($element, t('%name must be a value between 0 and 1.', array('%name' => $element['#title'])));
  1001. }
  1002. }
  1003. /**
  1004. * Form element validation handler that compares low and high values.
  1005. */
  1006. function coloractions_validate_form($element/*, &$form_state*/) {
  1007. $independent_colors = !empty($element['independent_colors']['#value']);
  1008. if (!$independent_colors) {
  1009. // Compare low and high.
  1010. coloractions_validate_low_and_high($element, 'all_colors', '');
  1011. }
  1012. else {
  1013. // Compare low and high per color
  1014. coloractions_validate_low_and_high($element, 'per_color', '_red');
  1015. coloractions_validate_low_and_high($element, 'per_color', '_green');
  1016. coloractions_validate_low_and_high($element, 'per_color', '_blue');
  1017. }
  1018. }
  1019. function coloractions_validate_low_and_high($element, $fieldset, $suffix) {
  1020. if ((float) $element[$fieldset]["low$suffix"]['#value'] > (float) $element[$fieldset]["high$suffix"]['#value']) {
  1021. form_error($element[$fieldset]["high$suffix"], t('%name-high must be higher then %name-low.',
  1022. array('%name-high' => $element[$fieldset]["high$suffix"]['#title'], '%name-low' => $element[$fieldset]["low$suffix"]['#title'])));
  1023. }
  1024. }
  1025. /**
  1026. * Implements theme_hook() for the adjust color levels effect summary.
  1027. *
  1028. * @param array $variables
  1029. * An associative array containing:
  1030. * - data: The current configuration for this image effect.
  1031. *
  1032. * @return string
  1033. * The HTML for the summary of this image effect.
  1034. * @ingroup themeable
  1035. */
  1036. function theme_coloractions_adjustlevels_summary(array $variables) {
  1037. $data = $variables['data'];
  1038. if (empty($data['independent_colors'])) {
  1039. return t('@range',
  1040. array('@range' => "[{$data['all_colors']['low']} - {$data['all_colors']['high']}]"));
  1041. }
  1042. else {
  1043. return t('red: @red-range, green: @green-range, blue: @blue-range',
  1044. array('@red-range' => "[{$data['per_color']['low_red']} - {$data['per_color']['high_red']}]",
  1045. '@green-range' => "[{$data['per_color']['low_green']} - {$data['per_color']['high_green']}]",
  1046. '@blue-range' => "[{$data['per_color']['low_blue']} - {$data['per_color']['high_blue']}]"));
  1047. }
  1048. }
  1049. /**
  1050. * Image effect callback for the adjust levels effect.
  1051. *
  1052. * @param stdClass $image
  1053. * @param array $data
  1054. *
  1055. * @return bool
  1056. * true on success, false otherwise.
  1057. */
  1058. function coloractions_adjustlevels_effect(stdClass $image, array $data) {
  1059. return image_toolkit_invoke('adjustlevels', $image, array($data));
  1060. }
  1061. /**
  1062. * GD toolkit specific implementation of the adjust levels effect.
  1063. *
  1064. * @param stdClass $image
  1065. * @param array $data
  1066. * The parameters for this effect.
  1067. *
  1068. * @return bool
  1069. * true on success, false otherwise.
  1070. */
  1071. function image_gd_adjustlevels(stdClass $image, array $data) {
  1072. $width = $image->info['width'];
  1073. $height = $image->info['height'];
  1074. if ($data['independent_colors']) {
  1075. $lower_r = $data['per_color']['low_red'] * 255;
  1076. $factor_r = ($data['per_color']['high_red'] * 255 - $lower_r) / 255;
  1077. $lower_g = $data['per_color']['low_green'] * 255;
  1078. $factor_g = ($data['per_color']['high_green'] * 255 - $lower_g) / 255;
  1079. $lower_b = $data['per_color']['low_blue'] * 255;
  1080. $factor_b = ($data['per_color']['high_blue'] * 255 - $lower_b) / 255;
  1081. }
  1082. else {
  1083. $lower_r = $lower_g = $lower_b = $data['all_colors']['low'] * 255;
  1084. $factor_r = $factor_g = $factor_b = ($data['all_colors']['high'] * 255 - $lower_r) / 255;
  1085. }
  1086. for ($y = 0; $y < $height; $y++) {
  1087. for ($x = 0; $x < $width; $x++) {
  1088. $rgb = imagecolorat($image->resource, $x, $y);
  1089. $source = imagecolorsforindex($image->resource, $rgb);
  1090. $final_r = $lower_r + $factor_r * $source['red'];
  1091. $final_g = $lower_g + $factor_g * $source['green'];
  1092. $final_b = $lower_b + $factor_b * $source['blue'];
  1093. $final_colour = imagecolorallocatealpha($image->resource, $final_r, $final_g, $final_b, $source['alpha']);
  1094. imagesetpixel($image->resource, $x, $y, $final_colour);
  1095. }
  1096. }
  1097. return TRUE;
  1098. }
  1099. /**
  1100. * Implements theme_hook() for the desaturate alpha effect summary.
  1101. *
  1102. * param array $variables
  1103. * An associative array containing:
  1104. * - data: The current configuration for this image effect.
  1105. *
  1106. * @return string
  1107. * The HTML for the summary of this image effect.
  1108. * @ingroup themeable
  1109. */
  1110. function theme_coloractions_desaturatealpha_summary(/*array $variables*/) {
  1111. return t(': Desaturates the image while retaining transparency.');
  1112. }
  1113. /**
  1114. * Image effect callback for the desaturate alpha effect.
  1115. *
  1116. * @param stdClass $image
  1117. * @param array $data
  1118. *
  1119. * @return bool
  1120. * true on success, false otherwise.
  1121. */
  1122. function coloractions_desaturatealpha_effect(stdClass $image, array $data) {
  1123. return image_toolkit_invoke('desaturatealpha', $image, array($data));
  1124. }
  1125. /**
  1126. * GD toolkit specific implementation of the adjust levels effect.
  1127. *
  1128. * @param stdClass $image
  1129. * param array $data
  1130. * The parameters for this effect.
  1131. *
  1132. * @return bool
  1133. * true on success, false otherwise.
  1134. */
  1135. function image_gd_desaturatealpha(stdClass $image/*, array $data*/) {
  1136. imagealphablending($image->resource, FALSE);
  1137. $result = imagefilter($image->resource, IMG_FILTER_GRAYSCALE);
  1138. imagealphablending($image->resource, TRUE);
  1139. return $result;
  1140. }
  1141. /**
  1142. * Image effect form callback for the remove animation effect.
  1143. *
  1144. * This effect has no parameters.
  1145. *
  1146. * param array $data
  1147. * The current configuration for this image effect.
  1148. *
  1149. * @return array
  1150. * The form definition for this effect.
  1151. */
  1152. function coloractions_removeanimation_form(/*array $data*/) {
  1153. $form = array();
  1154. $form['help'] = array(
  1155. '#markup' => "<p><strong>There are no user-configurable options for this effect.</strong></p>
  1156. <p>This image effect will remove all animation from a gif image, keeping only the first frame. Some notes:</p>
  1157. <ul>
  1158. <li>GD cannot handle animation at all and will always silently remove animation, whether this effect has been added to an image style or not.</li>
  1159. <li>Thus, this effect will only do something with ImageMagick as image toolkit.</li>
  1160. <li>Non gif images and non-animated gif images are silently ignored.</li>
  1161. <li>You can place this effect anywhere in the list of effects for an image style. There may be some performance gains when you add it as first though.</li>
  1162. </ul>
  1163. ",
  1164. );
  1165. return $form;
  1166. }
  1167. /**
  1168. * Implements theme_hook() for the remove animation effect summary.
  1169. *
  1170. * param array $variables
  1171. * An associative array containing:
  1172. * - data: The current configuration for this image effect.
  1173. *
  1174. * @return string
  1175. * The HTML for the summary of this image effect.
  1176. * @ingroup themeable
  1177. */
  1178. function theme_coloractions_removeanimation_summary(/*array $variables*/) {
  1179. return t('Remove animation, keeping only the first frame.');
  1180. }
  1181. /**
  1182. * Image effect callback for the remove animation effect.
  1183. *
  1184. * @param stdClass $image
  1185. * @param array $data
  1186. *
  1187. * @return bool
  1188. * True on success, false otherwise.
  1189. */
  1190. function coloractions_removeanimation_effect(stdClass $image, array $data) {
  1191. return image_toolkit_invoke('removeanimation', $image, array($data));
  1192. }
  1193. /**
  1194. * GD toolkit specific implementation of the remove animation effect.
  1195. *
  1196. * param stdClass $image
  1197. * param array $data
  1198. * The parameters for this effect.
  1199. *
  1200. * @return bool
  1201. * Always true, GD removes animations anyway.
  1202. */
  1203. function image_gd_removeanimation(/*stdClass $image, array $data*/) {
  1204. return TRUE;
  1205. }
  1206. /**
  1207. * Imagemagick toolkit specific implementation of the remove animation effect.
  1208. *
  1209. * @param stdClass $image
  1210. * param array $data
  1211. * The parameters for this effect.
  1212. *
  1213. * @return bool
  1214. * True on success, false otherwise.
  1215. */
  1216. function image_imagemagick_removeanimation(stdClass $image/*, array $data*/) {
  1217. if ($image->info['mime_type'] === 'image/gif') {
  1218. $image->ops[] = '-delete 1--1';
  1219. }
  1220. return TRUE;
  1221. }