Commit 156bdc43 authored by alexpott's avatar alexpott

Issue #2066219 by claudiu.cristea, fietserwin: Decouple image type from image extension.

parent af6cd3da
......@@ -63,7 +63,14 @@ class Image implements ImageInterface {
protected $extension = '';
/**
* MIME type ('image/jpeg', 'image/gif', 'image/png').
* Image type represented by a PHP IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG).
*
* @var int
*/
protected $type;
/**
* MIME type (e.g. 'image/jpeg', 'image/gif', 'image/png').
*
* @var string
*/
......@@ -96,6 +103,13 @@ public function __construct($source, ImageToolkitInterface $toolkit) {
$this->toolkit = $toolkit;
}
/**
* {@inheritdoc}
*/
public function isSupported() {
return in_array($this->getType(), $this->toolkit->supportedTypes());
}
/**
* {@inheritdoc}
*/
......@@ -144,6 +158,14 @@ public function getFileSize() {
return $this->fileSize;
}
/**
* {@inheritdoc}
*/
public function getType() {
$this->processInfo();
return $this->type;
}
/**
* {@inheritdoc}
*/
......@@ -245,9 +267,17 @@ protected function processInfo() {
if ($details = $this->toolkit->getInfo($this)) {
$this->height = $details['height'];
$this->width = $details['width'];
$this->extension = $details['extension'];
$this->type = $details['type'];
$this->mimeType = $details['mime_type'];
$this->fileSize = filesize($destination);
$this->extension = pathinfo($destination, PATHINFO_EXTENSION);
// It may be a temporary file, without extension, or an image created from
// an image resource. Fallback to default extension for this image type.
if (empty($this->extension)) {
$this->extension = image_type_to_extension($this->type, FALSE);
}
$this->processed = TRUE;
}
return TRUE;
......
......@@ -12,6 +12,14 @@
*/
interface ImageInterface {
/**
* Checks if the image format is supported.
*
* @return bool
* Returns TRUE if the image format is supported by the toolkit.
*/
public function isSupported();
/**
* Returns the extension of the image file.
*
......@@ -64,6 +72,15 @@ public function setWidth($width);
*/
public function getFileSize();
/**
* Returns the type of the image.
*
* @return int
* The image type represented by a PHP IMAGETYPE_* constant (e.g.
* IMAGETYPE_JPEG).
*/
public function getType();
/**
* Returns the MIME type of the image file.
*
......
......@@ -7,6 +7,7 @@
use Drupal\file\Entity\File;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\EntityStorageControllerInterface;
use Drupal\Core\Template\Attribute;
use Drupal\file\FileUsage\FileUsageInterface;
......@@ -411,8 +412,13 @@ function file_validate_is_image(File $file) {
$errors = array();
$image = \Drupal::service('image.factory')->get($file->getFileUri());
if (!$image->getExtension()) {
$errors[] = t('Only JPEG, PNG and GIF images are allowed.');
if (!$image->isSupported()) {
$toolkit = \Drupal::service('image.toolkit');
$extensions = array();
foreach ($toolkit->supportedTypes() as $image_type) {
$extensions[] = Unicode::strtoupper(image_type_to_extension($image_type));
}
$errors[] = t('Image type not supported. Allowed types: @types.', array('@types' => implode(', ', $extensions)));
}
return $errors;
......@@ -447,7 +453,7 @@ function file_validate_image_resolution(File $file, $maximum_dimensions = 0, $mi
// Check first that the file is an image.
$image_factory = \Drupal::service('image.factory');
$image = $image_factory->get($file->getFileUri());
if ($image->getExtension()) {
if ($image->isSupported()) {
if ($maximum_dimensions) {
// Check that it is smaller than the given dimensions.
list($width, $height) = explode('x', $maximum_dimensions);
......
......@@ -41,7 +41,7 @@ function image_field_widget_process($element, &$form_state, $form) {
}
else {
$image = \Drupal::service('image.factory')->get($file->getFileUri());
if ($image->getExtension()) {
if ($image->isSupported()) {
$variables['width'] = $image->getWidth();
$variables['height'] = $image->getHeight();
}
......
......@@ -233,7 +233,7 @@ function image_file_download($uri) {
// Check that the file exists and is an image.
$image = \Drupal::service('image.factory')->get($uri);
if ($image->getExtension()) {
if ($image->isSupported()) {
// Check the permissions of the original to grant access to this image.
$headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri));
// Confirm there's at least one module granting access and none denying access.
......
......@@ -293,7 +293,7 @@ public function preSave() {
// Determine the dimensions if necessary.
if (empty($width) || empty($height)) {
$image = \Drupal::service('image.factory')->get($this->entity->getFileUri());
if ($image->getExtension()) {
if ($image->isSupported()) {
$this->width = $image->getWidth();
$this->height =$image->getHeight();
}
......
......@@ -98,7 +98,7 @@ public function rotate(ImageInterface $image, $degrees, $background = NULL) {
// Images are assigned a new color palette when rotating, removing any
// transparency flags. For GIF images, keep a record of the transparent color.
if ($image->getExtension() == 'gif') {
if ($image->getType() == IMAGETYPE_GIF) {
$transparent_index = imagecolortransparent($image->getResource());
if ($transparent_index != 0) {
$transparent_gif_color = imagecolorsforindex($image->getResource(), $transparent_index);
......@@ -155,8 +155,7 @@ public function desaturate(ImageInterface $image) {
* {@inheritdoc}
*/
public function load(ImageInterface $image) {
$extension = str_replace('jpg', 'jpeg', $image->getExtension());
$function = 'imagecreatefrom' . $extension;
$function = 'imagecreatefrom' . image_type_to_extension($image->getType(), FALSE);
if (function_exists($function) && $resource = $function($image->getSource())) {
$image->setResource($resource);
if (!imageistruecolor($resource)) {
......@@ -190,17 +189,16 @@ public function save(ImageInterface $image, $destination) {
$destination = drupal_realpath($destination);
}
$extension = str_replace('jpg', 'jpeg', $image->getExtension());
$function = 'image' . $extension;
$function = 'image' . image_type_to_extension($image->getType(), FALSE);
if (!function_exists($function)) {
return FALSE;
}
if ($extension == 'jpeg') {
if ($image->getType() == IMAGETYPE_JPEG) {
$success = $function($image->getResource(), $destination, \Drupal::config('system.image.gd')->get('jpeg_quality'));
}
else {
// Always save PNG images with full transparency.
if ($extension == 'png') {
if ($image->getType() == IMAGETYPE_PNG) {
imagealphablending($image->getResource(), FALSE);
imagesavealpha($image->getResource(), TRUE);
}
......@@ -221,12 +219,10 @@ public function getInfo(ImageInterface $image) {
$data = getimagesize($image->getSource());
if (isset($data) && is_array($data)) {
$extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
$extension = isset($extensions[$data[2]]) ? $extensions[$data[2]] : '';
$details = array(
'width' => $data[0],
'height' => $data[1],
'extension' => $extension,
'type' => $data[2],
'mime_type' => $data['mime'],
);
}
......@@ -250,7 +246,7 @@ public function getInfo(ImageInterface $image) {
public function createTmp(ImageInterface $image, $width, $height) {
$res = imagecreatetruecolor($width, $height);
if ($image->getExtension() == 'gif') {
if ($image->getType() == IMAGETYPE_GIF) {
// Grab transparent color index from image resource.
$transparent = imagecolortransparent($image->getResource());
......@@ -264,7 +260,7 @@ public function createTmp(ImageInterface $image, $width, $height) {
imagecolortransparent($res, $transparent);
}
}
elseif ($image->getExtension() == 'png') {
elseif ($image->getType() == IMAGETYPE_PNG) {
imagealphablending($res, FALSE);
$transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
imagefill($res, 0, 0, $transparency);
......@@ -290,4 +286,11 @@ public static function isAvailable() {
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public static function supportedTypes() {
return array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
}
}
......@@ -50,14 +50,14 @@ interface ImageToolkitInterface extends PluginInspectionInterface {
*
* @see system_image_toolkit_settings()
*/
function settingsForm();
public function settingsForm();
/**
* Handles submissions for toolkit's settings form.
*
* @see system_image_toolkit_settings_submit()
*/
function settingsFormSubmit($form, &$form_state);
public function settingsFormSubmit($form, &$form_state);
/**
* Scales an image to the specified size.
......@@ -73,7 +73,7 @@ function settingsFormSubmit($form, &$form_state);
* @return bool
* TRUE or FALSE, based on success.
*/
function resize(ImageInterface $image, $width, $height);
public function resize(ImageInterface $image, $width, $height);
/**
* Rotates an image the given number of degrees.
......@@ -93,7 +93,7 @@ function resize(ImageInterface $image, $width, $height);
* @return bool
* TRUE or FALSE, based on success.
*/
function rotate(ImageInterface $image, $degrees, $background = NULL);
public function rotate(ImageInterface $image, $degrees, $background = NULL);
/**
* Crops an image.
......@@ -115,7 +115,7 @@ function rotate(ImageInterface $image, $degrees, $background = NULL);
*
* @see image_crop()
*/
function crop(ImageInterface $image, $x, $y, $width, $height);
public function crop(ImageInterface $image, $x, $y, $width, $height);
/**
* Converts an image resource to grayscale.
......@@ -129,7 +129,7 @@ function crop(ImageInterface $image, $x, $y, $width, $height);
* @return bool
* TRUE or FALSE, based on success.
*/
function desaturate(ImageInterface $image);
public function desaturate(ImageInterface $image);
/**
* Creates an image resource from a file.
......@@ -140,7 +140,7 @@ function desaturate(ImageInterface $image);
* @return bool
* TRUE or FALSE, based on success.
*/
function load(ImageInterface $image);
public function load(ImageInterface $image);
/**
* Writes an image resource to a destination file.
......@@ -153,7 +153,7 @@ function load(ImageInterface $image);
* @return bool
* TRUE or FALSE, based on success.
*/
function save(ImageInterface $image, $destination);
public function save(ImageInterface $image, $destination);
/**
* Gets details about an image.
......@@ -166,12 +166,12 @@ function save(ImageInterface $image, $destination);
* keyed array containing information about the image:
* - "width": Width, in pixels.
* - "height": Height, in pixels.
* - "extension": Commonly used file extension for the image.
* - "mime_type": MIME type ('image/jpeg', 'image/gif', 'image/png').
* - "type": Image type represented as an IMAGETYPE_* constant.
* - "mime_type": MIME type (e.g. 'image/jpeg', 'image/gif', 'image/png').
*
* @see \Drupal\Core\Image\ImageInterface::processInfo()
*/
function getInfo(ImageInterface $image);
public function getInfo(ImageInterface $image);
/**
* Verifies Image Toolkit is set up correctly.
......@@ -179,5 +179,14 @@ function getInfo(ImageInterface $image);
* @return bool
* True if the GD toolkit is available on this machine.
*/
static function isAvailable();
public static function isAvailable();
/**
* Returns a list of image types supported by the toolkit.
*
* @return array
* An array of available image types. An image type is represented by a PHP
* IMAGETYPE_* constant (e.g. IMAGETYPE_JPEG, IMAGETYPE_PNG, etc.).
*/
public static function supportedTypes();
}
......@@ -230,7 +230,7 @@ function testManipulations() {
$image_truecolor = imageistruecolor($image->getResource());
$this->assertTrue($image_truecolor, format_string('Image %file after load is a truecolor image.', array('%file' => $file)));
if ($image->getExtension() == 'gif') {
if ($image->getType() == IMAGETYPE_GIF) {
if ($op == 'desaturate') {
// Transparent GIFs and the imagefilter function don't work together.
$values['corners'][3][3] = 0;
......@@ -264,7 +264,7 @@ function testManipulations() {
$this->assertTrue($correct_dimensions_object, format_string('Image %file object after %action action is reporting the proper height and width values.', array('%file' => $file, '%action' => $op)));
// JPEG colors will always be messed up due to compression.
if ($image->getExtension() != 'jpg') {
if ($image->getType() != IMAGETYPE_JPEG) {
// Now check each of the corners to ensure color correctness.
foreach ($values['corners'] as $key => $corner) {
// Get the location of the corner.
......@@ -293,6 +293,6 @@ function testManipulations() {
}
}
}
}
}
......@@ -46,12 +46,10 @@ public function getInfo(ImageInterface $image) {
$data = getimagesize($image->getSource());
if (isset($data) && is_array($data)) {
$extensions = array('1' => 'gif', '2' => 'jpg', '3' => 'png');
$extension = isset($extensions[$data[2]]) ? $extensions[$data[2]] : '';
$details = array(
'width' => $data[0],
'height' => $data[1],
'extension' => $extension,
'type' => $data[2],
'mime_type' => $data['mime'],
);
}
......@@ -133,4 +131,12 @@ protected function logCall($op, $args) {
public static function isAvailable() {
return TRUE;
}
/**
* {@inheritdoc}
*/
public static function supportedTypes() {
return array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
}
}
......@@ -54,6 +54,7 @@ protected function setUp() {
'width' => 88,
'height' => 100,
'extension' => 'png',
'type' => IMAGETYPE_PNG,
'mime_type' => 'image/png',
)));
......@@ -106,6 +107,13 @@ public function testGetFileSize() {
$this->assertEquals($this->image->getFileSize(), 3905);
}
/**
* Tests \Drupal\Core\Image\Image::getType().
*/
public function testGetType() {
$this->assertEquals($this->image->getType(), IMAGETYPE_PNG);
}
/**
* Tests \Drupal\Core\Image\Image::getMimeType().
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment