diff --git a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php index 82092e6..56f0596 100644 --- a/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php +++ b/core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php @@ -7,8 +7,8 @@ namespace Drupal\image\Plugin\Field\FieldWidget; -use Drupal\Core\Field\FieldItemListInterface; use Drupal\Component\Utility\NestedArray; +use Drupal\Core\Field\FieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\file\Entity\File; use Drupal\file\Plugin\Field\FieldWidget\FileWidget; @@ -27,6 +27,13 @@ class ImageWidget extends FileWidget { /** + * The image factory service. + * + * @var \Drupal\Core\Image\ImageFactory + */ + protected $imageFactory; + + /** * {@inheritdoc} */ public static function defaultSettings() { @@ -121,11 +128,17 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen $element['#upload_validators']['file_validate_image_resolution'] = array($field_settings['max_resolution'], $field_settings['min_resolution']); } - // If not using custom extension validation, ensure this is an image. - $supported_extensions = array('png', 'gif', 'jpg', 'jpeg'); - $extensions = isset($element['#upload_validators']['file_validate_extensions'][0]) ? $element['#upload_validators']['file_validate_extensions'][0] : implode(' ', $supported_extensions); - $extensions = array_intersect(explode(' ', $extensions), $supported_extensions); - $element['#upload_validators']['file_validate_extensions'][0] = implode(' ', $extensions); + // If using custom extension validation, ensure that the extensions are + // supported by the current image toolkit. + $supported_extensions = $this->getImageFactory()->getSupportedExtensions(); + if (isset($element['#upload_validators']['file_validate_extensions'][0])) { + $extensions = $element['#upload_validators']['file_validate_extensions'][0]; + $extensions = array_intersect(explode(' ', $extensions), $supported_extensions); + $element['#upload_validators']['file_validate_extensions'][0] = implode(' ', $extensions); + } + else { + $element['#upload_validators']['file_validate_extensions'][0] = implode(' ', $supported_extensions); + } // Add properties needed by process() method. $element['#preview_image_style'] = $this->getSetting('preview_image_style'); @@ -273,4 +286,17 @@ public static function validateRequiredFields($element, FormStateInterface $form } } + /** + * Returns the image factory service. + * + * @return \Drupal\Core\Image\ImageFactory + * The image factory service. + */ + protected function getImageFactory() { + if (!$this->imageFactory) { + $this->imageFactory = \Drupal::service('image.factory'); + } + return $this->imageFactory; + } + } diff --git a/core/modules/image/src/Tests/ImageFieldWidgetTest.php b/core/modules/image/src/Tests/ImageFieldWidgetTest.php index 8bc70bc..0f027ab 100644 --- a/core/modules/image/src/Tests/ImageFieldWidgetTest.php +++ b/core/modules/image/src/Tests/ImageFieldWidgetTest.php @@ -7,6 +7,8 @@ namespace Drupal\image\Tests; +use Drupal\field\Entity\FieldConfig; + /** * Tests the image field widget. * @@ -30,6 +32,22 @@ public function testWidgetElement() { $this->createImageField($field_name, 'article', array(), $field_settings); $this->drupalGet('node/add/article'); $this->assertNotEqual(0, count($this->xpath('//div[contains(@class, "field--widget-image-image")]')), 'Image field widget found on add/node page', 'Browser'); + + // Check for allowed image file extensions - default. + $this->assertText('Allowed types: png gif jpg jpeg.'); + + // Try adding to the field config an unsupported extension, should not + // appear in the allowed types. + $field_config = FieldConfig::loadByName('node', 'article', $field_name); + $field_config->setSetting('file_extensions', 'png gif jpg jpeg tiff')->save(); + $this->drupalGet('node/add/article'); + $this->assertText('Allowed types: png gif jpg jpeg.'); + + // Add a supported extension and remove some supported ones, we should see + // the intersect of those entered in field config with those supported. + $field_config->setSetting('file_extensions', 'png jpe tiff')->save(); + $this->drupalGet('node/add/article'); + $this->assertText('Allowed types: png jpe.'); } } diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php index f9cfb53..d9f4a09 100644 --- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php +++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php @@ -398,7 +398,15 @@ public static function isAvailable() { public static function getSupportedExtensions() { $extensions = array(); foreach (static::supportedTypes() as $image_type) { - $extensions[] = Unicode::strtolower(image_type_to_extension($image_type, FALSE)); + // @todo Automatically fetch possible extensions for each mime type. + // @see https://www.drupal.org/node/2311679 + $extension = Unicode::strtolower(image_type_to_extension($image_type, FALSE)); + $extensions[] = $extension; + // Add some known similar extensions. + if ($extension === 'jpeg') { + $extensions[] = 'jpg'; + $extensions[] = 'jpe'; + } } return $extensions; } @@ -418,6 +426,9 @@ public static function getSupportedExtensions() { * @see image_type_to_extension() */ public function extensionToImageType($extension) { + if (in_array($extension, ['jpe', 'jpg'])) { + $extension = 'jpeg'; + } foreach ($this->supportedTypes() as $type) { if (image_type_to_extension($type, FALSE) === $extension) { return $type; diff --git a/core/modules/system/src/Tests/Image/ToolkitGdTest.php b/core/modules/system/src/Tests/Image/ToolkitGdTest.php index a731f5b..9390cfc 100644 --- a/core/modules/system/src/Tests/Image/ToolkitGdTest.php +++ b/core/modules/system/src/Tests/Image/ToolkitGdTest.php @@ -111,6 +111,26 @@ function testManipulations() { // Test that the image factory is set to use the GD toolkit. $this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.'); + // Test the list of supported extensions. + $expected_extensions = ['png', 'gif', 'jpeg', 'jpg', 'jpe']; + $supported_extensions = $this->imageFactory->getSupportedExtensions(); + $this->assertEqual($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 + ]; + $image = $this->imageFactory->get(); + foreach ($expected_image_types as $extension => $expected_image_type) { + $image_type = $image->getToolkit()->extensionToImageType($extension); + $this->assertEqual($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 = array($this->red, $this->green, $this->blue, $this->transparent);