diff --git a/core/modules/image/src/Tests/ImageDimensionsTest.php b/core/modules/image/src/Tests/ImageDimensionsTest.php
index 136b0f1..d81c04d 100644
--- a/core/modules/image/src/Tests/ImageDimensionsTest.php
+++ b/core/modules/image/src/Tests/ImageDimensionsTest.php
@@ -207,18 +207,14 @@ public function testImageDimensions() {
$effect_id = $style->addImageEffect($effect);
$style->save();
- // @todo Uncomment this once
- // https://www.drupal.org/project/drupal/issues/2670966 is resolved.
- // $this->assertEqual($this->getImageTag($variables), '');
+ $this->assertEqual($this->getImageTag($variables), '');
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
$this->drupalGet($this->getAbsoluteUrl($url));
$this->assertResponse(200, 'Image was generated at the URL.');
$this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.');
$image_file = $image_factory->get($generated_uri);
- // @todo Uncomment this once
- // https://www.drupal.org/project/drupal/issues/2670966 is resolved.
- // $this->assertEqual($image_file->getWidth(), 41);
- // $this->assertEqual($image_file->getHeight(), 41);
+ $this->assertEqual($image_file->getWidth(), 41);
+ $this->assertEqual($image_file->getHeight(), 41);
$effect_plugin = $style->getEffect($effect_id);
$style->deleteImageEffect($effect_plugin);
diff --git a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/Rotate.php b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/Rotate.php
index e567ea4..af6bb6d 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/Rotate.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/Operation/gd/Rotate.php
@@ -3,6 +3,7 @@
namespace Drupal\system\Plugin\ImageToolkit\Operation\gd;
use Drupal\Component\Utility\Color;
+use Drupal\Component\Utility\Rectangle;
/**
* Defines GD2 rotate operation.
@@ -96,6 +97,13 @@ protected function execute(array $arguments) {
// Stores the original GD resource.
$original_res = $this->getToolkit()->getResource();
+ // Get expected width and height resulting from the rotation.
+ $rect = new Rectangle($this->getToolkit()->getWidth(), $this->getToolkit()->getHeight());
+ $rect = $rect->rotate($arguments['degrees']);
+ $expected_width = $rect->getBoundingWidth();
+ $expected_height = $rect->getBoundingHeight();
+
+ // Rotate the image.
if ($new_res = imagerotate($this->getToolkit()->getResource(), 360 - $arguments['degrees'], $arguments['background_idx'])) {
$this->getToolkit()->setResource($new_res);
imagedestroy($original_res);
@@ -108,6 +116,67 @@ protected function execute(array $arguments) {
imagecolortransparent($this->getToolkit()->getResource(), $transparent_idx);
}
+ // Resizes the image if width and height are not as expected.
+ // PHP 7.0.26+ and 7.1.12+ GD rotates differently then it did in PHP 5.5
+ // and above, resulting in different dimensions. Here we are harmonizing
+ // final size across PHP versions by resizing the image to the dimensions
+ // we expect.
+ // @see https://bugs.php.net/bug.php?id=65148
+ if ($this->getToolkit()->getWidth() != $expected_width || $this->getToolkit()->getHeight() != $expected_height) {
+ // If either dimension of the current image is bigger than expected,
+ // crop the image.
+ if ($this->getToolkit()->getWidth() > $expected_width || $this->getToolkit()->getHeight() > $expected_height) {
+ $crop_width = min($expected_width, $this->getToolkit()->getWidth());
+ $crop_height = min($expected_height, $this->getToolkit()->getHeight());
+ if (!$this->getToolkit()->apply('crop', [
+ 'x' => $this->getToolkit()->getWidth() / 2 - $crop_width / 2,
+ 'y' => $this->getToolkit()->getHeight() / 2 - $crop_height /2,
+ 'width' => $crop_width,
+ 'height' => $crop_height,
+ ])) {
+ return FALSE;
+ }
+ }
+ // If the image at this point is smaller than expected, place it above
+ // a canvas of the expected dimensions.
+ if ($this->getToolkit()->getWidth() < $expected_width || $this->getToolkit()->getHeight() < $expected_height) {
+ // Store the current GD resource.
+ $temp_res = $this->getToolkit()->getResource();
+
+ // Prepare the canvas.
+ $data = [
+ 'width' => $expected_width,
+ 'height' => $expected_height,
+ 'extension' => image_type_to_extension($this->getToolkit()->getType(), FALSE),
+ 'transparent_color' => $this->getToolkit()->getTransparentColor(),
+ 'is_temp' => TRUE,
+ ];
+ if (!$this->getToolkit()->apply('create_new', $data)) {
+ return FALSE;
+ }
+
+ // Fill the canvas with the required background color.
+ imagefill($this->getToolkit()->getResource(), 0, 0, $arguments['background_idx']);
+
+ // Overlay the current image on the canvas.
+ imagealphablending($temp_res, TRUE);
+ imagesavealpha($temp_res, TRUE);
+ imagealphablending($this->getToolkit()->getResource(), TRUE);
+ imagesavealpha($this->getToolkit()->getResource(), TRUE);
+ $x_pos = (int) ($expected_width / 2 - imagesx($temp_res) / 2);
+ $y_pos = (int) ($expected_height / 2 - imagesy($temp_res) / 2);
+ if (imagecopy($this->getToolkit()->getResource(), $temp_res, $x_pos, $y_pos, 0, 0, imagesx($temp_res), imagesy($temp_res))) {
+ imagedestroy($temp_res);
+ }
+ else {
+ // In case of failure, destroy the temporary resource and restore
+ // the original one.
+ imagedestroy($this->getToolkit()->getResource());
+ $this->getToolkit()->setResource($temp_res);
+ return FALSE;
+ }
+ }
+ }
return TRUE;
}
diff --git a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
index 96ce7e0..8148a89 100644
--- a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php
@@ -214,9 +214,7 @@ public function testManipulations() {
];
// Systems using non-bundled GD2 don't have imagerotate. Test if available.
- // @todo Remove the version check once
- // https://www.drupal.org/project/drupal/issues/2670966 is resolved.
- if (function_exists('imagerotate') && (version_compare(phpversion(), '7.0.26') < 0)) {
+ if (function_exists('imagerotate')) {
$operations += [
'rotate_5' => [
'function' => 'rotate',