3 namespace Drupal\system\Plugin\ImageToolkit\Operation\gd;
5 use Drupal\Component\Utility\Color;
8 * Defines GD2 rotate operation.
10 * @ImageToolkitOperation(
13 * operation = "rotate",
14 * label = @Translation("Rotate"),
15 * description = @Translation("Rotates an image by the given number of degrees.")
18 class Rotate extends GDImageToolkitOperationBase {
23 protected function arguments() {
26 'description' => 'The number of (clockwise) degrees to rotate the image',
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",
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;
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];
51 // Background color is not specified: use transparent white as background.
52 $background = ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127];
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']);
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.
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);
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;
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;
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()]);
96 // Stores the original GD resource.
97 $original_res = $this->getToolkit()->getResource();
99 if ($new_res = imagerotate($this->getToolkit()->getResource(), 360 - $arguments['degrees'], $arguments['background_idx'])) {
100 $this->getToolkit()->setResource($new_res);
101 imagedestroy($original_res);
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);