Version 1
[yaffs-website] / web / core / modules / system / src / Plugin / ImageToolkit / Operation / gd / Rotate.php
1 <?php
2
3 namespace Drupal\system\Plugin\ImageToolkit\Operation\gd;
4
5 use Drupal\Component\Utility\Color;
6
7 /**
8  * Defines GD2 rotate operation.
9  *
10  * @ImageToolkitOperation(
11  *   id = "gd_rotate",
12  *   toolkit = "gd",
13  *   operation = "rotate",
14  *   label = @Translation("Rotate"),
15  *   description = @Translation("Rotates an image by the given number of degrees.")
16  * )
17  */
18 class Rotate extends GDImageToolkitOperationBase {
19
20   /**
21    * {@inheritdoc}
22    */
23   protected function arguments() {
24     return [
25       'degrees' => [
26         'description' => 'The number of (clockwise) degrees to rotate the image',
27       ],
28       'background' => [
29         'description' => "A string specifying the hexadecimal color code to use as background for the uncovered area of the image after the rotation. E.g. '#000000' for black, '#ff00ff' for magenta, and '#ffffff' for white. For images that support transparency, this will default to transparent white",
30         'required' => FALSE,
31         'default' => NULL,
32       ],
33     ];
34   }
35
36   /**
37    * {@inheritdoc}
38    */
39   protected function validateArguments(array $arguments) {
40     // PHP 5.5 GD bug: https://bugs.php.net/bug.php?id=65148: To prevent buggy
41     // behavior on negative multiples of 90 degrees we convert any negative
42     // angle to a positive one between 0 and 360 degrees.
43     $arguments['degrees'] -= floor($arguments['degrees'] / 360) * 360;
44
45     // Validate or set background color argument.
46     if (!empty($arguments['background'])) {
47       // Validate the background color: Color::hexToRgb does so for us.
48       $background = Color::hexToRgb($arguments['background']) + [ 'alpha' => 0 ];
49     }
50     else {
51       // Background color is not specified: use transparent white as background.
52       $background = ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127];
53     }
54     // Store the color index for the background as that is what GD uses.
55     $arguments['background_idx'] = imagecolorallocatealpha($this->getToolkit()->getResource(), $background['red'], $background['green'], $background['blue'], $background['alpha']);
56
57     if ($this->getToolkit()->getType() === IMAGETYPE_GIF) {
58       // GIF does not work with a transparency channel, but can define 1 color
59       // in its palette to act as transparent.
60
61       // Get the current transparent color, if any.
62       $gif_transparent_id = imagecolortransparent($this->getToolkit()->getResource());
63       if ($gif_transparent_id !== -1) {
64         // The gif already has a transparent color set: remember it to set it on
65         // the rotated image as well.
66         $arguments['gif_transparent_color'] = imagecolorsforindex($this->getToolkit()->getResource(), $gif_transparent_id);
67
68         if ($background['alpha'] >= 127) {
69           // We want a transparent background: use the color already set to act
70           // as transparent, as background.
71           $arguments['background_idx'] = $gif_transparent_id;
72         }
73       }
74       else {
75         // The gif does not currently have a transparent color set.
76         if ($background['alpha'] >= 127) {
77           // But as the background is transparent, it should get one.
78           $arguments['gif_transparent_color'] = $background;
79         }
80       }
81     }
82
83     return $arguments;
84   }
85
86   /**
87    * {@inheritdoc}
88    */
89   protected function execute(array $arguments) {
90     // PHP installations using non-bundled GD do not have imagerotate.
91     if (!function_exists('imagerotate')) {
92       $this->logger->notice('The image %file could not be rotated because the imagerotate() function is not available in this PHP installation.', ['%file' => $this->getToolkit()->getSource()]);
93       return FALSE;
94     }
95
96     // Stores the original GD resource.
97     $original_res = $this->getToolkit()->getResource();
98
99     if ($new_res = imagerotate($this->getToolkit()->getResource(), 360 - $arguments['degrees'], $arguments['background_idx'])) {
100       $this->getToolkit()->setResource($new_res);
101       imagedestroy($original_res);
102
103       // GIFs need to reassign the transparent color after performing the
104       // rotate, but only do so, if the image already had transparency of its
105       // own, or the rotate added a transparent background.
106       if (!empty($arguments['gif_transparent_color'])) {
107         $transparent_idx = imagecolorexactalpha($this->getToolkit()->getResource(), $arguments['gif_transparent_color']['red'], $arguments['gif_transparent_color']['green'], $arguments['gif_transparent_color']['blue'], $arguments['gif_transparent_color']['alpha']);
108         imagecolortransparent($this->getToolkit()->getResource(), $transparent_idx);
109       }
110
111       return TRUE;
112     }
113
114     return FALSE;
115   }
116
117 }