diff --git a/src/Plugin/ImageEffect/AutoOrientImageEffect.php b/src/Plugin/ImageEffect/AutoOrientImageEffect.php index 6e89113..0b48ec7 100644 --- a/src/Plugin/ImageEffect/AutoOrientImageEffect.php +++ b/src/Plugin/ImageEffect/AutoOrientImageEffect.php @@ -28,10 +28,4 @@ class AutoOrientImageEffect extends ImageEffectBase { return $image->apply('auto_orient'); } - /** - * {@inheritdoc} - */ - public function transformDimensions(array &$dimensions) { - } - } diff --git a/src/Plugin/ImageToolkit/ImagemagickToolkit.php b/src/Plugin/ImageToolkit/ImagemagickToolkit.php index 36bad2c..8552a17 100644 --- a/src/Plugin/ImageToolkit/ImagemagickToolkit.php +++ b/src/Plugin/ImageToolkit/ImagemagickToolkit.php @@ -71,11 +71,18 @@ class ImagemagickToolkit extends ImageToolkitBase { protected $source = NULL; /** - * The current image format. + * The source image format. * * @var string */ - protected $currentFormat = ''; + protected $sourceFormat = ''; + + /** + * The source image EXIF orientation. + * + * @var string + */ + protected $exifOrientation = NULL; /** * The image destination path on saving. @@ -352,6 +359,52 @@ class ImagemagickToolkit extends ImageToolkitBase { } /** + * Gets the source image format. + * + * @return string + * The source image format. + */ + public function getSourceFormat() { + return $this->sourceFormat; + } + + /** + * Sets the source image format. + * + * @param string $format + * The image format. + * + * @return $this + */ + public function setSourceFormat($format) { + $this->sourceFormat = $format; + return $this; + } + + /** + * Gets the source EXIF orientation. + * + * @return integer + * The source EXIF orientation. + */ + public function getExifOrientation() { + return $this->exifOrientation; + } + + /** + * Sets the source EXIF orientation. + * + * @param integer|null $exif_orientation + * The EXIF orientation. + * + * @return $this + */ + public function setExifOrientation($exif_orientation) { + $this->exifOrientation = (int) $exif_orientation; + return $this; + } + + /** * Gets the image destination path on saving. * * @return string @@ -450,24 +503,12 @@ class ImagemagickToolkit extends ImageToolkitBase { */ public function getMimeType() { // @todo change if extension mapping service gets in, see #2311679 - return empty($this->currentFormat) ? NULL : $this->mimeTypeGuesser->guess('dummy.' . $this->currentFormat); + $format = $this->getSourceFormat(); + return empty($format) ? NULL : $this->mimeTypeGuesser->guess('dummy.' . $format); } /** - * Sets the current image format. - * - * @param string $format - * The image format. - * - * @return $this - */ - public function setCurrentFormat($format) { - $this->currentFormat = $format; - return $this; - } - - /** - * Gets the 'convert' command line arguments. + * Gets the command line arguments for the Imagemagick binary. * * @return string[] * The array of command line arguments. @@ -477,7 +518,7 @@ class ImagemagickToolkit extends ImageToolkitBase { } /** - * Add a command line argument for 'convert'. + * Adds a command line argument. * * @param string $arg * The command line argument to be added. @@ -490,7 +531,7 @@ class ImagemagickToolkit extends ImageToolkitBase { } /** - * Prepends a command line argument for 'convert'. + * Prepends a command line argument. * * @param string $arg * The command line argument to be prepended. @@ -503,7 +544,7 @@ class ImagemagickToolkit extends ImageToolkitBase { } /** - * Find if a command line argument exists. + * Finds if a command line argument exists. * * @param string $arg * The command line argument to be found. @@ -522,7 +563,7 @@ class ImagemagickToolkit extends ImageToolkitBase { } /** - * Resets the 'convert' command line arguments. + * Resets the command line arguments. * * @return $this */ @@ -536,11 +577,20 @@ class ImagemagickToolkit extends ImageToolkitBase { * * PHP escapeshellarg() drops non-ascii characters, this is a replacement. * + * Stop-gap replacement while core issue #1561214 is solved. + * * @return string * An escaped string for use in the ::imagemagickExec method. */ public function escapeShellArg($arg) { - return "'" . $arg . "'"; + // return '\'' . str_replace('\'', '\'\\\'\'', $arg) . '\''; + + // Solution proposed in #1502924-8. + $old_locale = setlocale(LC_CTYPE, 0); + setlocale(LC_CTYPE, 'en_US.UTF-8'); + $arg_escaped = escapeshellarg($arg); + setlocale(LC_CTYPE, $old_locale); + return $arg_escaped; } /** @@ -582,11 +632,13 @@ class ImagemagickToolkit extends ImageToolkitBase { list($key, $value) = explode(':', $item); $data[$key] = $value; } - if ($data['format'] && in_array(Unicode::strtolower($data['format']), static::getSupportedExtensions())) { + $format = isset($data['format']) ? Unicode::strtolower($data['format']) : NULL; + if ($format && in_array($format, static::getSupportedExtensions())) { $this - ->setCurrentFormat($data['format']) + ->setSourceFormat($format) ->setWidth($data['width']) - ->setHeight($data['height']); + ->setHeight($data['height']) + ->setExifOrientation($data['exif_orientation']); $this->moduleHandler->alter('imagemagick_parse_file', $this); return TRUE; } @@ -604,7 +656,7 @@ class ImagemagickToolkit extends ImageToolkitBase { $data = @getimagesize(drupal_realpath($this->getSource())); if ($data && in_array(image_type_to_extension($data[2], FALSE), static::getSupportedExtensions())) { $this - ->setCurrentFormat(image_type_to_extension($data[2], FALSE)) + ->setSourceFormat(image_type_to_extension($data[2], FALSE)) ->setWidth($data[0]) ->setHeight($data[1]); $this->moduleHandler->alter('imagemagick_parse_file', $this); @@ -669,32 +721,36 @@ class ImagemagickToolkit extends ImageToolkitBase { $destination_formatted = $destination; } + // Combine the command line arguments. + $command_args = implode(' ', $this->getArguments()); + // GraphicsMagick arguments: // gm convert [options] input output // @see http://www.graphicsmagick.org/GraphicsMagick.html + $command_line = NULL; if ($this->configFactory->get('imagemagick.settings')->get('gm')) { - array_unshift($this->arguments, 'convert'); + $command_line .= ('convert ' . $command_args); if ($source) { - $this->addArgument($this->escapeShellArg($source)); + $command_line .= (' ' . $this->escapeShellArg($source)); + } + $command_line .= (' ' . $this->escapeShellArg($destination_formatted)); + if ($this->imagemagickExec('gm', $command_line) !== TRUE) { + return FALSE; } - $this->addArgument($this->escapeShellArg($destination_formatted)); } // ImageMagick arguments: // convert input [options] output // @see http://www.imagemagick.org/Usage/basics/#cmdline else { if ($source) { - array_unshift($this->arguments, $this->escapeShellArg($source)); + $command_line .= ($this->escapeShellArg($source) . ' '); + } + $command_line .= ($command_args . ' ' . $this->escapeShellArg($destination_formatted)); + if ($this->imagemagickExec('convert', $command_line) !== TRUE) { + return FALSE; } - $this->addArgument($this->escapeShellArg($destination_formatted)); } - $command_args = implode(' ', $this->getArguments()); - // Execute the 'convert' command. - if ($this->imagemagickExec('convert', $command_args) !== TRUE) { - return FALSE; - } - $this->resetArguments(); return file_exists($destination); } @@ -723,7 +779,7 @@ class ImagemagickToolkit extends ImageToolkitBase { protected function imagemagickExec($command, $command_args, &$output = NULL, &$error = NULL, $path = NULL) { // $path is only passed from the system-wide image toolkit form, on // which the path to convert is configured. - // @see _imagemagick_check_path() + // @see ::checkPath() if (!isset($path)) { // By using a default of NULL, we force users to setup the toolkit through // the image toolkit administration UI. Sites enforcing a path via diff --git a/src/Plugin/ImageToolkit/Operation/imagemagick/AutoOrient.php b/src/Plugin/ImageToolkit/Operation/imagemagick/AutoOrient.php index 67f8a88..1cb6dff 100644 --- a/src/Plugin/ImageToolkit/Operation/imagemagick/AutoOrient.php +++ b/src/Plugin/ImageToolkit/Operation/imagemagick/AutoOrient.php @@ -33,6 +33,13 @@ class AutoOrient extends ImagemagickImageToolkitOperationBase { */ protected function execute(array $arguments) { $this->getToolkit()->addArgument('-auto-orient'); + // Swap toolkit's height and width when picture orientation is vertical. + if (in_array($this->getToolkit()->getExifOrientation(), [5, 6, 7, 8])) { + $tmp = $this->getToolkit()->getWidth(); + $this->getToolkit()->setWidth($this->getToolkit()->getHeight()); + $this->getToolkit()->setHeight($tmp); + $this->getToolkit()->setExifOrientation(NULL); + } return TRUE; } diff --git a/src/Plugin/ImageToolkit/Operation/imagemagick/CreateNew.php b/src/Plugin/ImageToolkit/Operation/imagemagick/CreateNew.php index 5e10a29..9cf0e4d 100644 --- a/src/Plugin/ImageToolkit/Operation/imagemagick/CreateNew.php +++ b/src/Plugin/ImageToolkit/Operation/imagemagick/CreateNew.php @@ -83,9 +83,10 @@ class CreateNew extends ImagemagickImageToolkitOperationBase { $this->getToolkit() ->resetArguments() ->setSource(NULL) - ->setCurrentFormat($arguments['extension']) + ->setSourceFormat($arguments['extension']) ->setWidth($arguments['width']) ->setHeight($arguments['height']) + ->setExifOrientation(NULL) ->addArgument('-size ' . $arguments['width'] . 'x' . $arguments['height'] . ' xc:transparent'); if ($arguments['extension'] == 'gif') { $this->getToolkit()->addArgument('-transparent-color ' . $this->getToolkit()->escapeShellArg($arguments['transparent_color'])); diff --git a/src/Tests/ToolkitImagemagickTest.php b/src/Tests/ToolkitImagemagickTest.php index 43aaf60..ac1395b 100644 --- a/src/Tests/ToolkitImagemagickTest.php +++ b/src/Tests/ToolkitImagemagickTest.php @@ -395,5 +395,27 @@ class ToolkitImagemagickTest extends WebTestBase { $this->assertFalse($image->isValid(), 'CreateNew with invalid color hex string fails.'); $image->createNew(50, 20, 'gif', '#ff0000'); $this->assertTrue($image->isValid(), 'CreateNew with valid arguments validates the Image.'); + + // Test saving image files with filenames having non-ascii characters. + $file_names = [ + 'greek εικόνα δοκιμής.png', + 'russian Тестовое изображение.png', + 'simplified chinese 测试图片.png', + 'japanese 試験画像.png', + 'arabic صورة الاختبار.png', + 'armenian փորձարկման պատկերը.png', + 'bengali পরীক্ষা ইমেজ.png', + 'hebraic תמונת בדיקה.png', + 'hindi परीक्षण छवि.png', + 'viet hình ảnh thử nghiệm.png', + 'viet \'with quotes\' hình ảnh thử nghiệm.png', + 'viet "with double quotes" hình ảnh thử nghiệm.png', + ]; + foreach ($file_names as $file) { + $file_path = $directory . '/' . $file; + $image->save($file_path); + $image_reloaded = $this->imageFactory->get($file_path); + $this->assertTrue($image_reloaded->isValid(), String::format('Image file %file loaded successfully.', array('%file' => $file))); + } } }