X-Git-Url: http://aleph1.co.uk/gitweb/?a=blobdiff_plain;f=web%2Fmodules%2Fcontrib%2Fimagemagick%2Ftests%2Fsrc%2FFunctional%2FToolkitImagemagickTest.php;fp=web%2Fmodules%2Fcontrib%2Fimagemagick%2Ftests%2Fsrc%2FFunctional%2FToolkitImagemagickTest.php;h=df6af8dab9e8c5fc299a49702ff801aa9ece2a31;hb=f8fc16ae6b862bef59baaad5d051dd37b7ff11b2;hp=2322581ffa91ff34b90bc1b2104278c94c70d54f;hpb=dd08b95e4e519a02d45a50fb504bf5d685eaa9e3;p=yaffs-website diff --git a/web/modules/contrib/imagemagick/tests/src/Functional/ToolkitImagemagickTest.php b/web/modules/contrib/imagemagick/tests/src/Functional/ToolkitImagemagickTest.php index 2322581ff..df6af8dab 100644 --- a/web/modules/contrib/imagemagick/tests/src/Functional/ToolkitImagemagickTest.php +++ b/web/modules/contrib/imagemagick/tests/src/Functional/ToolkitImagemagickTest.php @@ -2,9 +2,12 @@ namespace Drupal\Tests\imagemagick\Functional; +use Drupal\Core\Cache\Cache; use Drupal\Core\Image\ImageInterface; use Drupal\Tests\TestFileCreationTrait; use Drupal\Tests\BrowserTestBase; +use Drupal\file_mdm\FileMetadataInterface; +use Drupal\imagemagick\ImagemagickExecArguments; /** * Tests that core image manipulations work properly through Imagemagick. @@ -57,6 +60,8 @@ class ToolkitImagemagickTest extends BrowserTestBase { 'simpletest', 'file_test', 'imagemagick', + 'file_mdm', + 'file_mdm_exif', ]; /** @@ -79,51 +84,36 @@ class ToolkitImagemagickTest extends BrowserTestBase { } /** - * Provides data for testManipulations. - * - * @return array[] - * A simple array of simple arrays, each having the following elements: - * - binaries to use for testing. - */ - public function providerManipulationTest() { - return [ - ['imagemagick'], - ['graphicsmagick'], - ]; - } - - /** - * Test image toolkit operations. - * - * 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. + * Helper to setup the image toolkit. * * @param string $binaries * The graphics package binaries to use for testing. - * - * @dataProvider providerManipulationTest + * @param bool $check_path + * Whether the path to binaries should be tested. */ - public function testManipulations($binaries) { + protected function setUpToolkit($binaries, $check_path = TRUE) { // Change the toolkit. \Drupal::configFactory()->getEditable('system.image') ->set('toolkit', 'imagemagick') ->save(); // Execute tests with selected binaries. - // The test can only be executed if binaries are available on the shell - // path. \Drupal::configFactory()->getEditable('imagemagick.settings') ->set('debug', TRUE) ->set('binaries', $binaries) ->set('quality', 100) ->save(); - $status = \Drupal::service('image.toolkit.manager')->createInstance('imagemagick')->checkPath(''); - if (!empty($status['errors'])) { - // Bots running automated test on d.o. do not have binaries installed, - // so the test will be skipped; it can be run locally where binaries are - // installed. - $this->markTestSkipped("Tests for '{$binaries}' cannot run because the binaries are not available on the shell path."); + + if ($check_path) { + // The test can only be executed if binaries are available on the shell + // path. + $status = \Drupal::service('image.toolkit.manager')->createInstance('imagemagick')->getExecManager()->checkPath(''); + if (!empty($status['errors'])) { + // Bots running automated test on d.o. do not have binaries installed, + // so the test will be skipped; it can be run locally where binaries + // are installed. + $this->markTestSkipped("Tests for '{$binaries}' cannot run because the binaries are not available on the shell path."); + } } // Set the toolkit on the image factory. @@ -135,6 +125,36 @@ class ToolkitImagemagickTest extends BrowserTestBase { // Prepare directory. file_unmanaged_delete_recursive($this->testDirectory); file_prepare_directory($this->testDirectory, FILE_CREATE_DIRECTORY); + } + + /** + * Provides data for testManipulations. + * + * @return array[] + * A simple array of simple arrays, each having the following elements: + * - binaries to use for testing. + */ + public function providerManipulationTest() { + return [ + ['imagemagick'], + ['graphicsmagick'], + ]; + } + + /** + * Test image toolkit operations. + * + * 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. + * + * @param string $binaries + * The graphics package binaries to use for testing. + * + * @dataProvider providerManipulationTest + */ + public function testManipulations($binaries) { + $this->setUpToolkit($binaries); // Typically the corner colors will be unchanged. These colors are in the // order of top-left, top-right, bottom-right, bottom-left. @@ -309,31 +329,36 @@ class ToolkitImagemagickTest extends BrowserTestBase { $this->getTestFiles('image'); foreach ($files as $file) { + $image_uri = 'public://' . $file; foreach ($operations as $op => $values) { // Load up a fresh image. - $image = $this->imageFactory->get('public://' . $file); + $image = $this->imageFactory->get($image_uri); if (!$image->isValid()) { $this->fail("Could not load image $file."); continue 2; } // Check that no multi-frame information is set. - $this->assertNull($image->getToolkit()->getFrames()); + $this->assertIdentical(1, $image->getToolkit()->getFrames()); // Perform our operation. $image->apply($values['function'], $values['arguments']); // Save and reload image. $file_path = $this->testDirectory . '/' . $op . substr($file, -4); - $image->save($file_path); + $this->assertTrue($image->save($file_path)); $image = $this->imageFactory->get($file_path); $this->assertTrue($image->isValid()); - // @todo GraphicsMagick specifics, temporarily adjust tests. - $package = $image->getToolkit()->getPackage(); + // @todo Suite specifics, temporarily adjust tests. + $package = $image->getToolkit()->getExecManager()->getPackage(); if ($package === 'graphicsmagick') { - // @todo Issues with crop on GIF files, investigate. - if (in_array($file, ['image-test.gif', 'image-test-no-transparency.gif']) && in_array($op, ['crop', 'scale_and_crop'])) { + // @todo Issues with crop and convert on GIF files, investigate. + if (in_array($file, [ + 'image-test.gif', 'image-test-no-transparency.gif', + ]) && in_array($op, [ + 'crop', 'scale_and_crop', 'convert_png', + ])) { continue; } } @@ -409,7 +434,7 @@ class ToolkitImagemagickTest extends BrowserTestBase { } $color = $this->getPixelColor($image, $x, $y); - $correct_colors = $this->colorsAreClose($color, $corner, $values['tolerance']); + $this->colorsAreClose($color, $corner, $values['tolerance'], $file, $op); } } } @@ -470,10 +495,14 @@ class ToolkitImagemagickTest extends BrowserTestBase { 'viet "with double quotes" hình ảnh thử nghiệm.png', ]; foreach ($file_names as $file) { + // On Windows, skip filenames with non-allowed characters. + if (substr(PHP_OS, 0, 3) === 'WIN' && preg_match('/[:*?"<>|]/', $file)) { + continue; + } $image = $this->imageFactory->get(); - $image->createNew(50, 20, 'png'); + $this->assertTrue($image->createNew(50, 20, 'png')); $file_path = $this->testDirectory . '/' . $file; - $image->save($file_path); + $this->assertTrue($image->save($file_path), $file); $image_reloaded = $this->imageFactory->get($file_path, 'gd'); $this->assertTrue($image_reloaded->isValid(), "Image file '$file' loaded successfully."); } @@ -481,21 +510,31 @@ class ToolkitImagemagickTest extends BrowserTestBase { // Test handling a file stored through a remote stream wrapper. $image = $this->imageFactory->get('dummy-remote://image-test.png'); // Source file should be equal to the copied local temp source file. - $this->assertEqual(filesize('dummy-remote://image-test.png'), filesize($image->getToolkit()->getSourceLocalPath())); + $this->assertEqual(filesize('dummy-remote://image-test.png'), filesize($image->getToolkit()->arguments()->getSourceLocalPath())); $image->desaturate(); - $image->save('dummy-remote://remote-image-test.png'); + $this->assertTrue($image->save('dummy-remote://remote-image-test.png')); // Destination file should exists, and destination local temp file should // have been reset. - $this->assertTrue(file_exists($image->getToolkit()->getDestination())); - $this->assertEqual('dummy-remote://remote-image-test.png', $image->getToolkit()->getDestination()); - $this->assertIdentical('', $image->getToolkit()->getDestinationLocalPath()); + $this->assertTrue(file_exists($image->getToolkit()->arguments()->getDestination())); + $this->assertEqual('dummy-remote://remote-image-test.png', $image->getToolkit()->arguments()->getDestination()); + $this->assertIdentical('', $image->getToolkit()->arguments()->getDestinationLocalPath()); // Test retrieval of EXIF information. + file_unmanaged_copy(drupal_get_path('module', 'imagemagick') . '/misc/test-exif.jpeg', 'public://', FILE_EXISTS_REPLACE); + // The image files that will be tested. $image_files = [ [ 'path' => drupal_get_path('module', 'imagemagick') . '/misc/test-exif.jpeg', 'orientation' => 8, ], + [ + 'path' => 'public://test-exif.jpeg', + 'orientation' => 8, + ], + [ + 'path' => 'dummy-remote://test-exif.jpeg', + 'orientation' => 8, + ], [ 'path' => 'public://image-test.jpg', 'orientation' => NULL, @@ -513,7 +552,6 @@ class ToolkitImagemagickTest extends BrowserTestBase { 'orientation' => NULL, ], ]; - foreach ($image_files as $image_file) { // Get image using 'identify'. \Drupal::configFactory()->getEditable('imagemagick.settings') @@ -521,13 +559,6 @@ class ToolkitImagemagickTest extends BrowserTestBase { ->save(); $image = $this->imageFactory->get($image_file['path']); $this->assertIdentical($image_file['orientation'], $image->getToolkit()->getExifOrientation()); - - // Get image using 'getimagesize'. - \Drupal::configFactory()->getEditable('imagemagick.settings') - ->set('use_identify', FALSE) - ->save(); - $image = $this->imageFactory->get($image_file['path']); - $this->assertIdentical($image_file['orientation'], $image->getToolkit()->getExifOrientation()); } // Test multi-frame GIF image. @@ -544,7 +575,6 @@ class ToolkitImagemagickTest extends BrowserTestBase { 'rotated_height' => 26, ], ]; - // Get images using 'identify'. \Drupal::configFactory()->getEditable('imagemagick.settings') ->set('use_identify', TRUE) @@ -557,7 +587,7 @@ class ToolkitImagemagickTest extends BrowserTestBase { // Scaling should preserve frames. $image->scale(30); - $image->save($image_file['destination']); + $this->assertTrue($image->save($image_file['destination'])); $image = $this->imageFactory->get($image_file['destination']); $this->assertIdentical($image_file['scaled_width'], $image->getWidth()); $this->assertIdentical($image_file['scaled_height'], $image->getHeight()); @@ -565,7 +595,7 @@ class ToolkitImagemagickTest extends BrowserTestBase { // Rotating should preserve frames. $image->rotate(24); - $image->save($image_file['destination']); + $this->assertTrue($image->save($image_file['destination'])); $image = $this->imageFactory->get($image_file['destination']); $this->assertIdentical($image_file['rotated_width'], $image->getWidth()); $this->assertIdentical($image_file['rotated_height'], $image->getHeight()); @@ -573,12 +603,301 @@ class ToolkitImagemagickTest extends BrowserTestBase { // Converting to PNG should drop frames. $image->convert('png'); - $this->assertNull($image->getToolkit()->getFrames()); - $image->save($image_file['destination']); + $this->assertTrue($image->save($image_file['destination'])); $image = $this->imageFactory->get($image_file['destination']); + $this->assertIdentical(1, $image->getToolkit()->getFrames()); $this->assertIdentical($image_file['rotated_width'], $image->getWidth()); $this->assertIdentical($image_file['rotated_height'], $image->getHeight()); - $this->assertNull($image->getToolkit()->getFrames()); + $this->assertIdentical(1, $image->getToolkit()->getFrames()); + } + } + + /** + * Legacy methods tests. + * + * @param string $binaries + * The graphics package binaries to use for testing. + * + * @dataProvider providerManipulationTest + * + * @todo remove in 8.x-3.0. + * + * @group legacy + */ + public function testManipulationsLegacy($binaries) { + $this->setUpToolkit($binaries); + + // Check package. + $toolkit = \Drupal::service('image.toolkit.manager')->createInstance('imagemagick'); + $this->assertSame($binaries, $toolkit->getPackage()); + $this->assertNotNull($toolkit->getPackageLabel()); + $this->assertSame([], $toolkit->checkPath('')['errors']); + + // Typically the corner colors will be unchanged. These colors are in the + // order of top-left, top-right, bottom-right, bottom-left. + $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', + ]; + + // Setup a list of tests to perform on each type. + $operations = [ + 'resize' => [ + 'function' => 'resize', + 'arguments' => ['width' => 20, 'height' => 10], + 'width' => 20, + 'height' => 10, + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'scale_x' => [ + 'function' => 'scale', + 'arguments' => ['width' => 20], + 'width' => 20, + 'height' => 10, + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'scale_y' => [ + 'function' => 'scale', + 'arguments' => ['height' => 10], + 'width' => 20, + 'height' => 10, + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'upscale_x' => [ + 'function' => 'scale', + 'arguments' => ['width' => 80, 'upscale' => TRUE], + 'width' => 80, + 'height' => 40, + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'upscale_y' => [ + 'function' => 'scale', + 'arguments' => ['height' => 40, 'upscale' => TRUE], + 'width' => 80, + 'height' => 40, + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'crop' => [ + 'function' => 'crop', + 'arguments' => ['x' => 12, 'y' => 4, 'width' => 16, 'height' => 12], + 'width' => 16, + 'height' => 12, + 'corners' => array_fill(0, 4, $this->white), + 'tolerance' => 0, + ], + 'scale_and_crop' => [ + 'function' => 'scale_and_crop', + 'arguments' => ['width' => 10, 'height' => 8], + 'width' => 10, + 'height' => 8, + 'corners' => array_fill(0, 4, $this->black), + 'tolerance' => 100, + ], + 'convert_jpg' => [ + 'function' => 'convert', + 'width' => 40, + 'height' => 20, + 'arguments' => ['extension' => 'jpeg'], + 'mimetype' => 'image/jpeg', + 'corners' => $default_corners, + 'tolerance' => 0, + ], + 'convert_gif' => [ + 'function' => 'convert', + 'width' => 40, + 'height' => 20, + 'arguments' => ['extension' => 'gif'], + 'mimetype' => 'image/gif', + 'corners' => $default_corners, + 'tolerance' => 15, + ], + 'convert_png' => [ + 'function' => 'convert', + 'width' => 40, + 'height' => 20, + 'arguments' => ['extension' => 'png'], + 'mimetype' => 'image/png', + 'corners' => $default_corners, + 'tolerance' => 5, + ], + 'rotate_5' => [ + 'function' => 'rotate', + 'arguments' => [ + 'degrees' => 5, + 'background' => '#FF00FF', + 'resize_filter' => 'Box', + ], + 'width' => 41, + 'height' => 23, + 'corners' => array_fill(0, 4, $this->fuchsia), + 'tolerance' => 5, + ], + 'rotate_minus_10' => [ + 'function' => 'rotate', + 'arguments' => [ + 'degrees' => -10, + 'background' => '#FF00FF', + 'resize_filter' => 'Box', + ], + 'width' => 41, + 'height' => 26, + 'corners' => array_fill(0, 4, $this->fuchsia), + 'tolerance' => 15, + ], + 'rotate_90' => [ + 'function' => 'rotate', + 'arguments' => ['degrees' => 90, 'background' => '#FF00FF'], + 'width' => 20, + 'height' => 40, + 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], + 'tolerance' => 0, + ], + 'rotate_transparent_5' => [ + 'function' => 'rotate', + 'arguments' => ['degrees' => 5, 'resize_filter' => 'Box'], + 'width' => 41, + 'height' => 23, + 'corners' => array_fill(0, 4, $this->transparent), + 'tolerance' => 0, + ], + 'rotate_transparent_90' => [ + 'function' => 'rotate', + 'arguments' => ['degrees' => 90], + 'width' => 20, + 'height' => 40, + 'corners' => [$this->transparent, $this->red, $this->green, $this->blue], + 'tolerance' => 0, + ], + 'desaturate' => [ + 'function' => 'desaturate', + 'arguments' => [], + 'height' => 20, + 'width' => 40, + // Grayscale corners are a bit funky. Each of the corners are a shade of + // gray. The values of these were determined simply by looking at the + // final image to see what desaturated colors end up being. + 'corners' => [ + array_fill(0, 3, 76) + [3 => 0], + array_fill(0, 3, 149) + [3 => 0], + array_fill(0, 3, 29) + [3 => 0], + array_fill(0, 3, 225) + [3 => 127], + ], + // @todo tolerance here is too high. Check reasons. + 'tolerance' => 17000, + ], + ]; + + // Prepare a copy of test files. + $this->getTestFiles('image'); + + foreach ($files as $file) { + $image_uri = 'public://' . $file; + foreach ($operations as $op => $values) { + // Load up a fresh image. + $image = $this->imageFactory->get($image_uri); + if (!$image->isValid()) { + $this->fail("Could not load image $file."); + continue 2; + } + + // Check that no multi-frame information is set. + $this->assertIdentical(1, $image->getToolkit()->getFrames()); + + // Legacy source tests. + $this->assertSame($image_uri, $image->getToolkit()->getSource()); + $this->assertSame($image->getToolkit()->arguments()->getSourceLocalPath(), $image->getToolkit()->getSourceLocalPath()); + $this->assertSame($image->getToolkit()->arguments()->getSourceFormat(), $image->getToolkit()->getSourceFormat()); + + // Perform our operation. + $image->apply($values['function'], $values['arguments']); + + // Save image. + $file_path = $this->testDirectory . '/' . $op . substr($file, -4); + $this->assertTrue($image->save($file_path)); + + // Legacy destination tests. + $this->assertSame($file_path, $image->getToolkit()->getDestination()); + $this->assertSame('', $image->getToolkit()->getDestinationLocalPath()); + $this->assertNotNull($image->getToolkit()->arguments()->getSourceFormat(), $image->getToolkit()->getDestinationFormat()); + + // Reload image. + $image = $this->imageFactory->get($file_path); + $this->assertTrue($image->isValid()); + + // Legacy set methods. + $image->getToolkit()->setSourceLocalPath('bar'); + $image->getToolkit()->setSourceFormat('PNG'); + $image->getToolkit()->setDestination('foo'); + $image->getToolkit()->setDestinationLocalPath('baz'); + $image->getToolkit()->setDestinationFormat('GIF'); + $this->assertSame('bar', $image->getToolkit()->arguments()->getSourceLocalPath()); + $this->assertSame('PNG', $image->getToolkit()->arguments()->getSourceFormat()); + $this->assertSame('foo', $image->getToolkit()->arguments()->getDestination()); + $this->assertSame('baz', $image->getToolkit()->arguments()->getDestinationLocalPath()); + $this->assertSame('GIF', $image->getToolkit()->arguments()->getDestinationFormat()); + $image->getToolkit()->setSourceFormatFromExtension('jpg'); + $image->getToolkit()->setDestinationFormatFromExtension('jpg'); + $this->assertSame('JPEG', $image->getToolkit()->arguments()->getSourceFormat()); + $this->assertSame('JPEG', $image->getToolkit()->arguments()->getDestinationFormat()); + } + } + + // Test retrieval of EXIF information. + file_unmanaged_copy(drupal_get_path('module', 'imagemagick') . '/misc/test-exif.jpeg', 'public://', FILE_EXISTS_REPLACE); + // The image files that will be tested. + $image_files = [ + [ + 'path' => drupal_get_path('module', 'imagemagick') . '/misc/test-exif.jpeg', + 'orientation' => 8, + ], + [ + 'path' => 'public://test-exif.jpeg', + 'orientation' => 8, + ], + [ + 'path' => 'dummy-remote://test-exif.jpeg', + 'orientation' => 8, + ], + [ + 'path' => 'public://image-test.jpg', + 'orientation' => NULL, + ], + [ + 'path' => 'public://image-test.png', + 'orientation' => NULL, + ], + [ + 'path' => 'public://image-test.gif', + 'orientation' => NULL, + ], + [ + 'path' => NULL, + 'orientation' => NULL, + ], + ]; + + foreach ($image_files as $image_file) { + // Get image using 'getimagesize'. + \Drupal::configFactory()->getEditable('imagemagick.settings') + ->set('use_identify', FALSE) + ->save(); + $image = $this->imageFactory->get($image_file['path']); + $this->assertIdentical($image_file['orientation'], $image->getToolkit()->getExifOrientation()); } } @@ -596,7 +915,7 @@ class ToolkitImagemagickTest extends BrowserTestBase { $this->assertFieldByName('image_toolkit', 'imagemagick'); $edit = [ 'image_toolkit' => 'gd', - 'imagemagick[suite][path_to_binaries]' => '/foo/bar', + 'imagemagick[suite][path_to_binaries]' => '/foo/bar/', ]; $this->drupalPostForm(NULL, $edit, 'Save configuration'); $this->assertFieldByName('image_toolkit', 'gd'); @@ -642,7 +961,7 @@ class ToolkitImagemagickTest extends BrowserTestBase { $transparent_index = imagecolortransparent($toolkit->getResource()); if ($color_index == $transparent_index) { - return array(0, 0, 0, 127); + return [0, 0, 0, 127]; } return array_values(imagecolorsforindex($toolkit->getResource(), $color_index)); @@ -660,18 +979,294 @@ class ToolkitImagemagickTest extends BrowserTestBase { * The expected RGBA array. * @param int $tolerance * The acceptable difference between the colors. + * @param string $file + * The image file being tested. + * @param string $op + * The image operation being tested. * * @return bool * TRUE if the colors differences are within tolerance, FALSE otherwise. */ - protected function colorsAreClose(array $actual, array $expected, $tolerance) { + protected function colorsAreClose(array $actual, array $expected, $tolerance, $file, $op) { // Fully transparent colors are equal, regardless of RGB. if ($actual[3] == 127 && $expected[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, "Actual: {" . implode(',', $actual) . "}, Expected: {" . implode(',', $expected) . "}, Distance: " . $distance . ", Tolerance: " . $tolerance); + $this->assertLessThanOrEqual($tolerance, $distance, "Actual: {" . implode(',', $actual) . "}, Expected: {" . implode(',', $expected) . "}, Distance: " . $distance . ", Tolerance: " . $tolerance . ", File: " . $file . ", Operation: " . $op); return TRUE; } + /** + * Test legacy arguments handling. + * + * @todo remove in 8.x-3.0. + * + * @group legacy + */ + public function testArgumentsLegacy() { + $this->setUpToolkit('imagemagick'); + + // Prepare a copy of test files. + $this->getTestFiles('image'); + + $image_uri = "public://image-test.png"; + $image = $this->imageFactory->get($image_uri); + if (!$image->isValid()) { + $this->fail("Could not load image $image_uri."); + } + + // Setup a list of arguments. + $image->getToolkit()->addArgument("-resize 100x75!"); + // Internal argument. + $image->getToolkit()->addArgument(">!>INTERNAL"); + $image->getToolkit()->addArgument("-quality 75"); + $image->getToolkit()->prependArgument("-hoxi 76"); + + // Use methods introduced in 8.x-2.3. + $image->getToolkit()->arguments() + // Pre source argument. + ->add("-density 25", ImagemagickExecArguments::PRE_SOURCE) + // Another internal argument. + ->add("GATEAU", ImagemagickExecArguments::INTERNAL) + // Another pre source argument. + ->add("-auchocolat 90", ImagemagickExecArguments::PRE_SOURCE) + // Add two arguments with additional info. + ->add( + "-addz 150", + ImagemagickExecArguments::POST_SOURCE, + ImagemagickExecArguments::APPEND, + [ + 'foo' => 'bar', + 'qux' => 'der', + ] + ) + ->add( + "-addz 200", + ImagemagickExecArguments::POST_SOURCE, + ImagemagickExecArguments::APPEND, + [ + 'wey' => 'lod', + 'foo' => 'bar', + ] + ); + + // Test find arguments skipping identifiers. + $this->assertSame([ + 0 => '-hoxi 76', + 1 => '-resize 100x75!', + 2 => '>!>INTERNAL', + 3 => '-quality 75', + 5 => '>!>GATEAU', + 7 => '-addz 150', + 8 => '-addz 200', + ], $image->getToolkit()->getArguments()); + $this->assertSame([2], array_keys($image->getToolkit()->arguments()->find('/^INTERNAL/'))); + $this->assertSame([5], array_keys($image->getToolkit()->arguments()->find('/^GATEAU/'))); + $this->assertSame([6], array_keys($image->getToolkit()->arguments()->find('/^\-auchocolat/'))); + $this->assertSame([7, 8], array_keys($image->getToolkit()->arguments()->find('/^\-addz/'))); + $this->assertSame([7, 8], array_keys($image->getToolkit()->arguments()->find('/.*/', NULL, ['foo' => 'bar']))); + $this->assertSame([], $image->getToolkit()->arguments()->find('/.*/', NULL, ['arw' => 'moo'])); + $this->assertSame(2, $image->getToolkit()->findArgument('>!>INTERNAL')); + $this->assertSame(5, $image->getToolkit()->findArgument('>!>GATEAU')); + $this->assertFalse($image->getToolkit()->findArgument('-auchocolat')); + + // Check resulting command line strings. + $this->assertSame('-density 25 -auchocolat 90', $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::PRE_SOURCE)); + $this->assertSame("-hoxi 76 -resize 100x75! -quality 75 -addz 150 -addz 200", $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + $this->assertSame("-hoxi 76 -resize 100x75! -quality 75 -addz 150 -addz 200", $image->getToolkit()->getStringForBinary()); + } + + /** + * Test arguments handling. + */ + public function testArguments() { + $this->setUpToolkit('imagemagick'); + + // Prepare a copy of test files. + $this->getTestFiles('image'); + + $image_uri = "public://image-test.png"; + $image = $this->imageFactory->get($image_uri); + if (!$image->isValid()) { + $this->fail("Could not load image $image_uri."); + } + + // Setup a list of arguments. + $image->getToolkit()->arguments() + ->add("-resize 100x75!") + // Internal argument. + ->add("INTERNAL", ImagemagickExecArguments::INTERNAL) + ->add("-quality 75") + // Prepend argument. + ->add("-hoxi 76", ImagemagickExecArguments::POST_SOURCE, 0) + // Pre source argument. + ->add("-density 25", ImagemagickExecArguments::PRE_SOURCE) + // Another internal argument. + ->add("GATEAU", ImagemagickExecArguments::INTERNAL) + // Another pre source argument. + ->add("-auchocolat 90", ImagemagickExecArguments::PRE_SOURCE) + // Add two arguments with additional info. + ->add( + "-addz 150", + ImagemagickExecArguments::POST_SOURCE, + ImagemagickExecArguments::APPEND, + [ + 'foo' => 'bar', + 'qux' => 'der', + ] + ) + ->add( + "-addz 200", + ImagemagickExecArguments::POST_SOURCE, + ImagemagickExecArguments::APPEND, + [ + 'wey' => 'lod', + 'foo' => 'bar', + ] + ); + + // Test find arguments skipping identifiers. + $this->assertSame([2], array_keys($image->getToolkit()->arguments()->find('/^INTERNAL/'))); + $this->assertSame([5], array_keys($image->getToolkit()->arguments()->find('/^GATEAU/'))); + $this->assertSame([6], array_keys($image->getToolkit()->arguments()->find('/^\-auchocolat/'))); + $this->assertSame([7, 8], array_keys($image->getToolkit()->arguments()->find('/^\-addz/'))); + $this->assertSame([7, 8], array_keys($image->getToolkit()->arguments()->find('/.*/', NULL, ['foo' => 'bar']))); + $this->assertSame([], $image->getToolkit()->arguments()->find('/.*/', NULL, ['arw' => 'moo'])); + + // Check resulting command line strings. + $this->assertSame('-density 25 -auchocolat 90', $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::PRE_SOURCE)); + $this->assertSame("-hoxi 76 -resize 100x75! -quality 75 -addz 150 -addz 200", $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + + // Add arguments with a specific index. + $image->getToolkit()->arguments() + ->add("-ix aa", ImagemagickExecArguments::POST_SOURCE, 4) + ->add("-ix bb", ImagemagickExecArguments::POST_SOURCE, 4); + $this->assertSame([4, 5], array_keys($image->getToolkit()->arguments()->find('/^\-ix/'))); + $this->assertSame("-hoxi 76 -resize 100x75! -quality 75 -ix bb -ix aa -addz 150 -addz 200", $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + + // Create a new image and inspect the arguments. + $image->createNew(100, 200); + $this->assertSame([0], array_keys($image->getToolkit()->arguments()->find('/^./', NULL, ['image_toolkit_operation' => 'create_new']))); + $this->assertSame([0], array_keys($image->getToolkit()->arguments()->find('/^./', NULL, ['image_toolkit_operation_plugin_id' => 'imagemagick_create_new']))); + $this->assertSame("-size 100x200 xc:transparent", $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + } + + /** + * Test module arguments alter hook. + */ + public function testArgumentsAlterHook() { + $this->setUpToolkit('imagemagick'); + + $fmdm = $this->container->get('file_metadata_manager'); + + // Change the Advanced Colorspace setting, must be included in the command + // line. + \Drupal::configFactory()->getEditable('imagemagick.settings') + ->set('advanced.colorspace', 'GRAY') + ->save(); + + // Prepare a copy of test files. + $this->getTestFiles('image'); + $image_uri = "public://image-test.png"; + $image = $this->imageFactory->get($image_uri); + if (!$image->isValid()) { + $this->fail("Could not load image $image_uri."); + } + + // Check the source colorspace. + $this->assertSame('SRGB', $image->getToolkit()->getColorspace()); + + // Setup a list of arguments. + $image->getToolkit()->arguments() + ->add("-resize 100x75!") + ->add("-quality 75"); + + // Save the derived image. + $image->save($image_uri . '.derived'); + + // Check expected command line. + if (substr(PHP_OS, 0, 3) === 'WIN') { + $expected = "-resize 100x75! -quality 75 -colorspace \"GRAY\""; + } + else { + $expected = "-resize 100x75! -quality 75 -colorspace 'GRAY'"; + } + $this->assertSame($expected, $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + + // Check that the colorspace has been actually changed in the file. + Cache::InvalidateTags([ + 'config:imagemagick.file_metadata_plugin.imagemagick_identify', + ]); + $fmdm->release($image_uri . '.derived'); + $image_md = $fmdm->uri($image_uri . '.derived'); + $image = $this->imageFactory->get($image_uri . '.derived'); + $this->assertIdentical(FileMetadataInterface::LOADED_FROM_FILE, $image_md->isMetadataLoaded('imagemagick_identify')); + $this->assertSame('GRAY', $image->getToolkit()->getColorspace()); + + // Change the Prepend settings, must be included in the command line. + // Once before the source image. + \Drupal::configFactory()->getEditable('imagemagick.settings') + ->set('prepend', '-debug All') + ->set('prepend_pre_source', TRUE) + ->save(); + $image = $this->imageFactory->get($image_uri); + $image->getToolkit()->arguments() + ->add("-resize 100x75!") + ->add("-quality 75"); + $image->save($image_uri . '.derived'); + if (substr(PHP_OS, 0, 3) === 'WIN') { + $expected = "-resize 100x75! -quality 75 -colorspace \"GRAY\""; + } + else { + $expected = "-resize 100x75! -quality 75 -colorspace 'GRAY'"; + } + $this->assertSame('-debug All', $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::PRE_SOURCE)); + $this->assertSame($expected, $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + // Then after the source image. + \Drupal::configFactory()->getEditable('imagemagick.settings') + ->set('prepend_pre_source', FALSE) + ->save(); + $image = $this->imageFactory->get($image_uri); + $image->getToolkit()->arguments() + ->add("-resize 100x75!") + ->add("-quality 75"); + $image->save($image_uri . '.derived'); + if (substr(PHP_OS, 0, 3) === 'WIN') { + $expected = "-debug All -resize 100x75! -quality 75 -colorspace \"GRAY\""; + } + else { + $expected = "-debug All -resize 100x75! -quality 75 -colorspace 'GRAY'"; + } + $this->assertSame('', $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::PRE_SOURCE)); + $this->assertSame($expected, $image->getToolkit()->arguments()->toString(ImagemagickExecArguments::POST_SOURCE)); + } + + /** + * Test missing command on ExecManager. + */ + public function testExecManagerCommandNotFound() { + $exec_manager = \Drupal::service('imagemagick.exec_manager'); + $output = ''; + $error = ''; + $expected = substr(PHP_OS, 0, 3) !== 'WIN' ? 127 : 1; + $ret = $exec_manager->runOsShell('pinkpanther', '-inspector Clouseau', 'blake', $output, $error); + $this->assertEquals($expected, $ret, $error); + } + + /** + * Test timeout on ExecManager. + */ + public function testExecManagerTimeout() { + $exec_manager = \Drupal::service('imagemagick.exec_manager'); + $output = ''; + $error = ''; + $expected = substr(PHP_OS, 0, 3) !== 'WIN' ? 143 : 1; + // Set a short timeout (1 sec.) and run a process that is expected to last + // longer (10 secs.). Should return a 'terminate' exit code. + $exec_manager->setTimeout(1); + $ret = $exec_manager->runOsShell('sleep', '10', 'sleep', $output, $error); + $this->assertEquals($expected, $ret, $error); + } + }