From 1ac9aaffc8838d8c74a7e99bd3f524c106db3e79 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Mon, 18 Oct 2021 17:39:52 +0100 Subject: [PATCH] Revert "Issue #3239935 by mondrake, andypost, daffie: Refactor ToolkitGdTest" This reverts commit d0c712ad4d7126cc8e3b084b8e6c1d7aac6fc949. --- .../KernelTests/Core/Image/ToolkitGdTest.php | 567 +++++++++--------- 1 file changed, 278 insertions(+), 289 deletions(-) diff --git a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php index 4c238663f36c..4031189c9b17 100644 --- a/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php +++ b/core/tests/Drupal/KernelTests/Core/Image/ToolkitGdTest.php @@ -4,30 +4,18 @@ use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Image\ImageInterface; +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\Site\Settings; use Drupal\KernelTests\KernelTestBase; /** - * Tests for the GD image toolkit. + * Tests that core image manipulations work properly: scale, resize, rotate, + * crop, scale and crop, and desaturate. * - * @coversDefaultClass \Drupal\system\Plugin\ImageToolkit\GDToolkit - * @requires extension gd * @group Image */ class ToolkitGdTest extends KernelTestBase { - /** - * Colors that are used in testing. - */ - const BLACK = [0, 0, 0, 0]; - const RED = [255, 0, 0, 0]; - const GREEN = [0, 255, 0, 0]; - const BLUE = [0, 0, 255, 0]; - const YELLOW = [255, 255, 0, 0]; - const WHITE = [255, 255, 255, 0]; - const TRANSPARENT = [0, 0, 0, 127]; - const FUCHSIA = [255, 0, 255, 0]; - const ROTATE_TRANSPARENT = [255, 255, 255, 127]; - /** * The image factory service. * @@ -36,14 +24,33 @@ class ToolkitGdTest extends KernelTestBase { protected $imageFactory; /** - * A directory where test image files can be saved to. + * Colors that are used in testing. * - * @var string + * @var array */ - protected $directory; + protected $black = [0, 0, 0, 0]; + protected $red = [255, 0, 0, 0]; + protected $green = [0, 255, 0, 0]; + protected $blue = [0, 0, 255, 0]; + protected $yellow = [255, 255, 0, 0]; + protected $white = [255, 255, 255, 0]; + protected $transparent = [0, 0, 0, 127]; /** - * {@inheritdoc} + * Used as rotate background colors. + * + * @var array + */ + protected $fuchsia = [255, 0, 255, 0]; + protected $rotateTransparent = [255, 255, 255, 127]; + + protected $width = 40; + protected $height = 20; + + /** + * Modules to enable. + * + * @var array */ protected static $modules = ['system']; @@ -54,35 +61,36 @@ protected function setUp(): void { parent::setUp(); $this->installConfig(['system']); - // Set the image factory service. $this->imageFactory = $this->container->get('image.factory'); - $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); + } - // Prepare a directory for test file results. - $this->directory = 'public://imagetest'; - \Drupal::service('file_system')->prepareDirectory($this->directory, FileSystemInterface::CREATE_DIRECTORY); + protected function checkRequirements() { + // GD2 support is available. + if (!function_exists('imagegd2')) { + return [ + 'Image manipulations for the GD toolkit cannot run because the GD toolkit is not available.', + ]; + } + return parent::checkRequirements(); } /** - * Assert two colors are equal by RGBA, net of full transparency. - * - * @param int[] $expected - * The expected RGBA array. - * @param int[] $actual - * The actual RGBA array. - * @param int $tolerance - * The acceptable difference between the colors. - * @param string $message - * The assertion message. + * Function to compare two colors by RGBa. */ - protected function assertColorsAreEqual(array $expected, array $actual, int $tolerance, string $message = ''): void { - // Fully transparent colors are equal, regardless of RGB. - if ($actual[3] == 127 && $expected[3] == 127) { - return; + public function colorsAreEqual($color_a, $color_b) { + // Fully transparent pixels are equal, regardless of RGB. + if ($color_a[3] == 127 && $color_b[3] == 127) { + return TRUE; } - $distance = pow(($actual[0] - $expected[0]), 2) + pow(($actual[1] - $expected[1]), 2) + pow(($actual[2] - $expected[2]), 2) + pow(($actual[3] - $expected[3]), 2); - $this->assertLessThanOrEqual($tolerance, $distance, $message . " - Actual: {" . implode(',', $actual) . "}, Expected: {" . implode(',', $expected) . "}, Distance: " . $distance . ", Tolerance: " . $tolerance); + + foreach ($color_a as $key => $value) { + if ($color_b[$key] != $value) { + return FALSE; + } + } + + return TRUE; } /** @@ -101,87 +109,123 @@ public function getPixelColor(ImageInterface $image, $x, $y) { } /** - * Data provider for ::testManipulations(). + * Since PHP can't visually check that our images have been manipulated + * properly, build a list of expected color values for each of the corners and + * the expected height and widths for the final images. */ - public function providerTestImageFiles(): array { + public function testManipulations() { + + // Test that the image factory is set to use the GD toolkit. + $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); + + // Test the list of supported extensions. + $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp']; + $supported_extensions = $this->imageFactory->getSupportedExtensions(); + $this->assertEquals($expected_extensions, array_intersect($expected_extensions, $supported_extensions)); + + // Test that the supported extensions map to correct internal GD image + // types. + $expected_image_types = [ + 'png' => IMAGETYPE_PNG, + 'gif' => IMAGETYPE_GIF, + 'jpeg' => IMAGETYPE_JPEG, + 'jpg' => IMAGETYPE_JPEG, + 'jpe' => IMAGETYPE_JPEG, + 'webp' => IMAGETYPE_WEBP, + ]; + $image = $this->imageFactory->get(); + foreach ($expected_image_types as $extension => $expected_image_type) { + $image_type = $image->getToolkit()->extensionToImageType($extension); + $this->assertSame($expected_image_type, $image_type); + } + // Typically the corner colors will be unchanged. These colors are in the // order of top-left, top-right, bottom-right, bottom-left. - $default_corners = [static::RED, static::GREEN, static::BLUE, static::TRANSPARENT]; + $default_corners = [$this->red, $this->green, $this->blue, $this->transparent]; + + // A list of files that will be tested. + $files = [ + 'image-test.png', + 'image-test.gif', + 'image-test-no-transparency.gif', + 'image-test.jpg', + 'img-test.webp', + ]; // Setup a list of tests to perform on each type. - $test_cases = [ + $operations = [ 'resize' => [ - 'operation' => 'resize', + 'function' => 'resize', 'arguments' => ['width' => 20, 'height' => 10], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'scale_x' => [ - 'operation' => 'scale', + 'function' => 'scale', 'arguments' => ['width' => 20], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'scale_y' => [ - 'operation' => 'scale', + 'function' => 'scale', 'arguments' => ['height' => 10], 'width' => 20, 'height' => 10, 'corners' => $default_corners, ], 'upscale_x' => [ - 'operation' => 'scale', + 'function' => 'scale', 'arguments' => ['width' => 80, 'upscale' => TRUE], 'width' => 80, 'height' => 40, 'corners' => $default_corners, ], 'upscale_y' => [ - 'operation' => 'scale', + 'function' => 'scale', 'arguments' => ['height' => 40, 'upscale' => TRUE], 'width' => 80, 'height' => 40, 'corners' => $default_corners, ], 'crop' => [ - 'operation' => 'crop', + 'function' => 'crop', 'arguments' => ['x' => 12, 'y' => 4, 'width' => 16, 'height' => 12], 'width' => 16, 'height' => 12, - 'corners' => array_fill(0, 4, static::WHITE), + 'corners' => array_fill(0, 4, $this->white), ], 'scale_and_crop' => [ - 'operation' => 'scale_and_crop', + 'function' => 'scale_and_crop', 'arguments' => ['width' => 10, 'height' => 8], 'width' => 10, 'height' => 8, - 'corners' => array_fill(0, 4, static::BLACK), + 'corners' => array_fill(0, 4, $this->black), ], 'convert_jpg' => [ - 'operation' => 'convert', + 'function' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'jpeg'], 'corners' => $default_corners, ], 'convert_gif' => [ - 'operation' => 'convert', + 'function' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'gif'], 'corners' => $default_corners, ], 'convert_png' => [ - 'operation' => 'convert', + 'function' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'png'], 'corners' => $default_corners, ], 'convert_webp' => [ - 'operation' => 'convert', + 'function' => 'convert', 'width' => 40, 'height' => 20, 'arguments' => ['extension' => 'webp'], @@ -189,51 +233,49 @@ public function providerTestImageFiles(): array { ], ]; - // Systems using non-bundled GD2 may miss imagerotate(). Test if available. - if (function_exists('imagerotate')) { - $test_cases += [ + // 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)) { + $operations += [ 'rotate_5' => [ - 'operation' => 'rotate', + 'function' => 'rotate', // Fuchsia background. 'arguments' => ['degrees' => 5, 'background' => '#FF00FF'], - // @todo Re-enable dimensions' check once - // https://www.drupal.org/project/drupal/issues/2921123 is resolved. - // 'width' => 41, - // 'height' => 23, - 'corners' => array_fill(0, 4, static::FUCHSIA), - ], - 'rotate_transparent_5' => [ - 'operation' => 'rotate', - 'arguments' => ['degrees' => 5], - // @todo Re-enable dimensions' check once - // https://www.drupal.org/project/drupal/issues/2921123 is resolved. - // 'width' => 41, - // 'height' => 23, - 'corners' => array_fill(0, 4, static::ROTATE_TRANSPARENT), + 'width' => 41, + 'height' => 23, + 'corners' => array_fill(0, 4, $this->fuchsia), ], 'rotate_90' => [ - 'operation' => 'rotate', + 'function' => 'rotate', // Fuchsia background. 'arguments' => ['degrees' => 90, 'background' => '#FF00FF'], 'width' => 20, 'height' => 40, - 'corners' => [static::TRANSPARENT, static::RED, static::GREEN, static::BLUE], + 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], + ], + 'rotate_transparent_5' => [ + 'function' => 'rotate', + 'arguments' => ['degrees' => 5], + 'width' => 41, + 'height' => 23, + 'corners' => array_fill(0, 4, $this->rotateTransparent), ], 'rotate_transparent_90' => [ - 'operation' => 'rotate', + 'function' => 'rotate', 'arguments' => ['degrees' => 90], 'width' => 20, 'height' => 40, - 'corners' => [static::TRANSPARENT, static::RED, static::GREEN, static::BLUE], + 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], ], ]; } - // Systems using non-bundled GD2 may miss imagefilter(). Test if available. + // Systems using non-bundled GD2 don't have imagefilter. Test if available. if (function_exists('imagefilter')) { - $test_cases += [ + $operations += [ 'desaturate' => [ - 'operation' => 'desaturate', + 'function' => 'desaturate', 'arguments' => [], 'height' => 20, 'width' => 40, @@ -250,220 +292,148 @@ public function providerTestImageFiles(): array { ]; } - $ret = []; - foreach ([ - 'image-test.png', - 'image-test.gif', - 'image-test-no-transparency.gif', - 'image-test.jpg', - 'img-test.webp', - ] as $file_name) { - foreach ($test_cases as $test_case => $values) { - $operation = $values['operation']; - $arguments = $values['arguments']; - unset($values['operation'], $values['arguments']); - $ret[] = [$file_name, $test_case, $operation, $arguments, $values]; - } - } + // Prepare a directory for test file results. + $directory = Settings::get('file_public_path') . '/imagetest'; + \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY); + + foreach ($files as $file) { + foreach ($operations as $op => $values) { + // Load up a fresh image. + $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); + $toolkit = $image->getToolkit(); + if (!$image->isValid()) { + $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); + continue 2; + } + $image_original_type = $image->getToolkit()->getType(); - return $ret; - } + // All images should be converted to truecolor when loaded. + $image_truecolor = imageistruecolor($toolkit->getResource()); + $this->assertTrue($image_truecolor, new FormattableMarkup('Image %file after load is a truecolor image.', ['%file' => $file])); - /** - * Since PHP can't visually check that our images have been manipulated - * properly, build a list of expected color values for each of the corners and - * the expected height and widths for the final images. - * - * @dataProvider providerTestImageFiles - */ - public function testManipulations(string $file_name, string $test_case, string $operation, array $arguments, array $expected): void { - // Load up a fresh image. - $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file_name); - $toolkit = $image->getToolkit(); - $this->assertTrue($image->isValid()); - $image_original_type = $image->getToolkit()->getType(); + // Store the original GD resource. + $old_res = $toolkit->getResource(); - // All images should be converted to truecolor when loaded. - $this->assertTrue(imageistruecolor($toolkit->getResource()), "Image '$file_name' after load is a truecolor image."); + // Perform our operation. + $image->apply($values['function'], $values['arguments']); - // Store the original GD resource. - if (PHP_VERSION_ID < 80000) { - $old_res = $toolkit->getResource(); - } + // If the operation replaced the resource, check that the old one has + // been destroyed. + $new_res = $toolkit->getResource(); + if ($new_res !== $old_res) { + // @todo In https://www.drupal.org/node/3133236 convert this to + // $this->assertIsNotResource($old_res). + $this->assertFalse(is_resource($old_res), new FormattableMarkup("'%operation' destroyed the original resource.", ['%operation' => $values['function']])); + } - // Perform our operation. - $image->apply($operation, $arguments); - - // If the operation replaced the resource, check that the old one has - // been destroyed. - if (PHP_VERSION_ID < 80000) { - $new_res = $toolkit->getResource(); - if ($new_res !== $old_res) { - // @todo In https://www.drupal.org/node/3133236 convert this to - // $this->assertIsNotResource($old_res). - $this->assertFalse(is_resource($old_res), "'{$operation}' destroyed the original resource."); - } - } + // To keep from flooding the test with assert values, make a general + // value for whether each group of values fail. + $correct_dimensions_real = TRUE; + $correct_dimensions_object = TRUE; - // Flush Image object to disk storage. - $file_path = $this->directory . '/' . $test_case . image_type_to_extension($image->getToolkit()->getType()); - $image->save($file_path); - - // Check that the both the GD object and the Image object have an accurate - // record of the dimensions. - if (isset($expected['height']) && isset($expected['width'])) { - $this->assertSame($expected['height'], imagesy($toolkit->getResource()), "Image '$file_name' after '$test_case' should have a proper height."); - $this->assertSame($expected['width'], imagesx($toolkit->getResource()), "Image '$file_name' after '$test_case' should have a proper width."); - $this->assertSame($expected['height'], $image->getHeight(), "Image '$file_name' after '$test_case' should have a proper height."); - $this->assertSame($expected['width'], $image->getWidth(), "Image '$file_name' after '$test_case' should have a proper width."); - } + if (imagesy($toolkit->getResource()) != $values['height'] || imagesx($toolkit->getResource()) != $values['width']) { + $correct_dimensions_real = FALSE; + } - // Now check each of the corners to ensure color correctness. - foreach ($expected['corners'] as $key => $expected_color) { - // The test gif that does not have transparency color set is a - // special case. - if ($file_name === 'image-test-no-transparency.gif') { - if ($test_case == 'desaturate') { - // For desaturating, keep the expected color from the test - // data, but set alpha channel to fully opaque. - $expected_color[3] = 0; + // Check that the image object has an accurate record of the dimensions. + if ($image->getWidth() != $values['width'] || $image->getHeight() != $values['height']) { + $correct_dimensions_object = FALSE; } - elseif ($expected_color === static::TRANSPARENT) { - // Set expected pixel to yellow where the others have - // transparent. - $expected_color = static::YELLOW; + + $file_path = $directory . '/' . $op . image_type_to_extension($image->getToolkit()->getType()); + $image->save($file_path); + + $this->assertTrue($correct_dimensions_real, new FormattableMarkup('Image %file after %action action has proper dimensions.', ['%file' => $file, '%action' => $op])); + $this->assertTrue($correct_dimensions_object, new FormattableMarkup('Image %file object after %action action is reporting the proper height and width values.', ['%file' => $file, '%action' => $op])); + + // JPEG colors will always be messed up due to compression. So we skip + // these tests if the original or the result is in jpeg format. + if ($image->getToolkit()->getType() != IMAGETYPE_JPEG && $image_original_type != IMAGETYPE_JPEG) { + // Now check each of the corners to ensure color correctness. + foreach ($values['corners'] as $key => $corner) { + // The test gif that does not have transparency color set is a + // special case. + if ($file === 'image-test-no-transparency.gif') { + if ($op == 'desaturate') { + // For desaturating, keep the expected color from the test + // data, but set alpha channel to fully opaque. + $corner[3] = 0; + } + elseif ($corner === $this->transparent) { + // Set expected pixel to yellow where the others have + // transparent. + $corner = $this->yellow; + } + } + + // Get the location of the corner. + switch ($key) { + case 0: + $x = 0; + $y = 0; + break; + + case 1: + $x = $image->getWidth() - 1; + $y = 0; + break; + + case 2: + $x = $image->getWidth() - 1; + $y = $image->getHeight() - 1; + break; + + case 3: + $x = 0; + $y = $image->getHeight() - 1; + break; + } + $color = $this->getPixelColor($image, $x, $y); + // We also skip the color test for transparency for gif <-> png + // conversion. The convert operation cannot handle that correctly. + if ($image->getToolkit()->getType() == $image_original_type || $corner != $this->transparent) { + $correct_colors = $this->colorsAreEqual($color, $corner); + $this->assertTrue($correct_colors, new FormattableMarkup('Image %file object after %action action has the correct color placement at corner %corner.', + ['%file' => $file, '%action' => $op, '%corner' => $key])); + } + } } - } - // Get the location of the corner. - switch ($key) { - case 0: - $x = 0; - $y = 0; - break; - - case 1: - $x = $image->getWidth() - 1; - $y = 0; - break; - - case 2: - $x = $image->getWidth() - 1; - $y = $image->getHeight() - 1; - break; - - case 3: - $x = 0; - $y = $image->getHeight() - 1; - break; + // Check that saved image reloads without raising PHP errors. + $image_reloaded = $this->imageFactory->get($file_path); + $resource = $image_reloaded->getToolkit()->getResource(); } - $actual_color = $this->getPixelColor($image, $x, $y); + } - // If image cannot handle transparent colors, skip the pixel color test. - if ($actual_color[3] === 0 && $expected_color[3] === 127) { + // Test creation of image from scratch, and saving to storage. + foreach ([IMAGETYPE_PNG, IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_WEBP] as $type) { + $image = $this->imageFactory->get(); + $image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00'); + $file = 'from_null' . image_type_to_extension($type); + $file_path = $directory . '/' . $file; + $this->assertEquals(50, $image->getWidth(), new FormattableMarkup('Image file %file has the correct width.', ['%file' => $file])); + $this->assertEquals(20, $image->getHeight(), new FormattableMarkup('Image file %file has the correct height.', ['%file' => $file])); + $this->assertEquals(image_type_to_mime_type($type), $image->getMimeType(), new FormattableMarkup('Image file %file has the correct MIME type.', ['%file' => $file])); + $this->assertTrue($image->save($file_path), new FormattableMarkup('Image %file created anew from a null image was saved.', ['%file' => $file])); + + // Reload saved image. + $image_reloaded = $this->imageFactory->get($file_path); + if (!$image_reloaded->isValid()) { + $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); continue; } - - // JPEG has small differences in color after processing. - $tolerance = $image_original_type === IMAGETYPE_JPEG ? 3 : 0; - - $this->assertColorsAreEqual($expected_color, $actual_color, $tolerance, "Image '$file_name' object after '$test_case' action has the correct color placement at corner '$key'"); - } - - // Check that saved image reloads without raising PHP errors. - $image_reloaded = $this->imageFactory->get($file_path); - if (PHP_VERSION_ID >= 80000) { - $this->assertInstanceOf(\GDImage::class, $image_reloaded->getToolkit()->getResource()); - } - else { - $this->assertIsResource($image_reloaded->getToolkit()->getResource()); - } - } - - /** - * @covers ::getSupportedExtensions - * @covers ::extensionToImageType - */ - public function testSupportedExtensions(): void { - // Test the list of supported extensions. - $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe', 'webp']; - $this->assertEqualsCanonicalizing($expected_extensions, $this->imageFactory->getSupportedExtensions()); - - // Test that the supported extensions map to correct internal GD image - // types. - $expected_image_types = [ - 'png' => IMAGETYPE_PNG, - 'gif' => IMAGETYPE_GIF, - 'jpeg' => IMAGETYPE_JPEG, - 'jpg' => IMAGETYPE_JPEG, - 'jpe' => IMAGETYPE_JPEG, - 'webp' => IMAGETYPE_WEBP, - ]; - $image = $this->imageFactory->get(); - foreach ($expected_image_types as $extension => $expected_image_type) { - $this->assertSame($expected_image_type, $image->getToolkit()->extensionToImageType($extension)); - } - } - - /** - * Data provider for ::testCreateImageFromScratch(). - */ - public function providerSupportedImageTypes(): array { - return [ - [IMAGETYPE_PNG], - [IMAGETYPE_GIF], - [IMAGETYPE_JPEG], - [IMAGETYPE_WEBP], - ]; - } - - /** - * Tests that GD functions for the image type are available. - * - * @dataProvider providerSupportedImageTypes - */ - public function testGdFunctionsExist(int $type): void { - $extension = image_type_to_extension($type, FALSE); - $this->assertTrue(function_exists("imagecreatefrom$extension"), "imagecreatefrom$extension should exist."); - $this->assertTrue(function_exists("image$extension"), "image$extension should exist."); - } - - /** - * Tests creation of image from scratch, and saving to storage. - * - * @dataProvider providerSupportedImageTypes - */ - public function testCreateImageFromScratch(int $type): void { - // Build an image from scratch. - $image = $this->imageFactory->get(); - $image->createNew(50, 20, image_type_to_extension($type, FALSE), '#ffff00'); - $file = 'from_null' . image_type_to_extension($type); - $file_path = $this->directory . '/' . $file; - $this->assertSame(50, $image->getWidth()); - $this->assertSame(20, $image->getHeight()); - $this->assertSame(image_type_to_mime_type($type), $image->getMimeType()); - $this->assertTrue($image->save($file_path)); - - // Reload and check saved image. - $image_reloaded = $this->imageFactory->get($file_path); - $this->assertTrue($image_reloaded->isValid()); - $this->assertSame(50, $image_reloaded->getWidth()); - $this->assertSame(20, $image_reloaded->getHeight()); - $this->assertSame(image_type_to_mime_type($type), $image_reloaded->getMimeType()); - if ($image_reloaded->getToolkit()->getType() == IMAGETYPE_GIF) { - // Check that image has the correct transparent color channel set. - $this->assertSame('#ffff00', $image_reloaded->getToolkit()->getTransparentColor()); - } - else { - // Check that image has no color channel set. - $this->assertNull($image_reloaded->getToolkit()->getTransparentColor()); + $this->assertEquals(50, $image_reloaded->getWidth(), new FormattableMarkup('Image file %file has the correct width.', ['%file' => $file])); + $this->assertEquals(20, $image_reloaded->getHeight(), new FormattableMarkup('Image file %file has the correct height.', ['%file' => $file])); + $this->assertEquals(image_type_to_mime_type($type), $image_reloaded->getMimeType(), new FormattableMarkup('Image file %file has the correct MIME type.', ['%file' => $file])); + if ($image_reloaded->getToolkit()->getType() == IMAGETYPE_GIF) { + $this->assertEquals('#ffff00', $image_reloaded->getToolkit()->getTransparentColor(), new FormattableMarkup('Image file %file has the correct transparent color channel set.', ['%file' => $file])); + } + else { + $this->assertNull($image_reloaded->getToolkit()->getTransparentColor(), new FormattableMarkup('Image file %file has no color channel set.', ['%file' => $file])); + } } - } - /** - * Tests failures of the 'create_new' operation. - */ - public function testCreateNewFailures(): void { + // Test failures of the 'create_new' operation. $image = $this->imageFactory->get(); $image->createNew(-50, 20); $this->assertFalse($image->isValid(), 'CreateNew with negative width fails.'); @@ -512,6 +482,10 @@ public function testResourceDestruction() { * Tests for GIF images with transparency. */ public function testGifTransparentImages() { + // Prepare a directory for test file results. + $directory = Settings::get('file_public_path') . '/imagetest'; + \Drupal::service('file_system')->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY); + // Test loading an indexed GIF image with transparent color set. // Color at top-right pixel should be fully transparent. $file = 'image-test-transparent-indexed.gif'; @@ -519,20 +493,20 @@ public function testGifTransparentImages() { $resource = $image->getToolkit()->getResource(); $color_index = imagecolorat($resource, $image->getWidth() - 1, 0); $color = array_values(imagecolorsforindex($resource, $color_index)); - $this->assertEquals(static::ROTATE_TRANSPARENT, $color, "Image {$file} after load has full transparent color at corner 1."); + $this->assertEquals($this->rotateTransparent, $color, "Image {$file} after load has full transparent color at corner 1."); // Test deliberately creating a GIF image with no transparent color set. // Color at top-right pixel should be fully transparent while in memory, // fully opaque after flushing image to file. $file = 'image-test-no-transparent-color-set.gif'; - $file_path = $this->directory . '/' . $file; + $file_path = $directory . '/' . $file; // Create image. $image = $this->imageFactory->get(); $image->createNew(50, 20, 'gif', NULL); $resource = $image->getToolkit()->getResource(); $color_index = imagecolorat($resource, $image->getWidth() - 1, 0); $color = array_values(imagecolorsforindex($resource, $color_index)); - $this->assertEquals(static::ROTATE_TRANSPARENT, $color, "New GIF image with no transparent color set after creation has full transparent color at corner 1."); + $this->assertEquals($this->rotateTransparent, $color, "New GIF image with no transparent color set after creation has full transparent color at corner 1."); // Save image. $this->assertTrue($image->save($file_path), "New GIF image {$file} was saved."); // Reload image. @@ -557,19 +531,34 @@ public function testGifTransparentImages() { // can be loaded correctly. $file = 'image-test-transparent-out-of-range.gif'; $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); - $this->assertTrue($image->isValid()); + $toolkit = $image->getToolkit(); - // All images should be converted to truecolor when loaded. - $this->assertTrue(imageistruecolor($image->getToolkit()->getResource())); + if (!$image->isValid()) { + $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); + } + else { + // All images should be converted to truecolor when loaded. + $image_truecolor = imageistruecolor($toolkit->getResource()); + $this->assertTrue($image_truecolor, new FormattableMarkup('Image %file after load is a truecolor image.', ['%file' => $file])); + } } /** * Tests calling a missing image operation plugin. */ public function testMissingOperation() { + + // Test that the image factory is set to use the GD toolkit. + $this->assertEquals('gd', $this->imageFactory->getToolkitId(), 'The image factory is set to use the \'gd\' image toolkit.'); + + // An image file that will be tested. + $file = 'image-test.png'; + // Load up a fresh image. - $image = $this->imageFactory->get('core/tests/fixtures/files/image-test.png'); - $this->assertTrue($image->isValid()); + $image = $this->imageFactory->get('core/tests/fixtures/files/' . $file); + if (!$image->isValid()) { + $this->fail(new FormattableMarkup('Could not load image %file.', ['%file' => $file])); + } // Try perform a missing toolkit operation. $this->assertFalse($image->apply('missing_op', []), 'Calling a missing image toolkit operation plugin fails.'); -- GitLab