/**
  * This method actually does the processing of files locally
  *
  * takes the original file (on remote storages this will be fetched from the remote server)
  * does the IM magic on the local server by creating a temporary typo3temp/ file
  * copies the typo3temp/ file to the processing folder of the target storage
  * removes the typo3temp/ file
  *
  * @param TaskInterface $task
  * @return array
  */
 public function process(TaskInterface $task)
 {
     $targetFile = $task->getTargetFile();
     $sourceFile = $task->getSourceFile();
     // Merge custom configuration with default configuration
     $configuration = array_merge(array('width' => 64, 'height' => 64), $task->getConfiguration());
     $configuration['width'] = Utility\MathUtility::forceIntegerInRange($configuration['width'], 1);
     $configuration['height'] = Utility\MathUtility::forceIntegerInRange($configuration['height'], 1);
     $originalFileName = $sourceFile->getForLocalProcessing(FALSE);
     // Create a temporaryFile
     $temporaryFileName = Utility\GeneralUtility::tempnam('preview_', '.' . $task->getTargetFileExtension());
     // Check file extension
     if ($sourceFile->getType() != Resource\File::FILETYPE_IMAGE && !Utility\GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $sourceFile->getExtension())) {
         // Create a default image
         $this->processor->getTemporaryImageWithText($temporaryFileName, 'Not imagefile!', 'No ext!', $sourceFile->getName());
     } else {
         // Create the temporary file
         if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
             $parameters = '-sample ' . $configuration['width'] . 'x' . $configuration['height'] . ' ' . $this->processor->wrapFileName($originalFileName) . '[0] ' . $this->processor->wrapFileName($temporaryFileName);
             $cmd = Utility\GeneralUtility::imageMagickCommand('convert', $parameters) . ' 2>&1';
             Utility\CommandUtility::exec($cmd);
             if (!file_exists($temporaryFileName)) {
                 // Create a error gif
                 $this->processor->getTemporaryImageWithText($temporaryFileName, 'No thumb', 'generated!', $sourceFile->getName());
             }
         }
     }
     return array('filePath' => $temporaryFileName);
 }
 /**
  * This method actually does the processing of files locally
  *
  * Takes the original file (for remote storages this will be fetched from the remote server),
  * does the IM magic on the local server by creating a temporary typo3temp/ file,
  * copies the typo3temp/ file to the processing folder of the target storage and
  * removes the typo3temp/ file.
  *
  * The returned array has the following structure:
  *   width => 100
  *   height => 200
  *   filePath => /some/path
  *
  * If filePath isn't set but width and height are the original file is used as ProcessedFile
  * with the returned width and height. This is for example useful for SVG images.
  *
  * @param TaskInterface $task
  * @return array|NULL
  */
 public function process(TaskInterface $task)
 {
     $result = null;
     $targetFile = $task->getTargetFile();
     $sourceFile = $task->getSourceFile();
     $originalFileName = $sourceFile->getForLocalProcessing(false);
     /** @var $gifBuilder GifBuilder */
     $gifBuilder = GeneralUtility::makeInstance(GifBuilder::class);
     $gifBuilder->init();
     $gifBuilder->absPrefix = PATH_site;
     $configuration = $targetFile->getProcessingConfiguration();
     $configuration['additionalParameters'] = $this->modifyImageMagickStripProfileParameters($configuration['additionalParameters'], $configuration);
     if (empty($configuration['fileExtension'])) {
         $configuration['fileExtension'] = $task->getTargetFileExtension();
     }
     $options = $this->getConfigurationForImageCropScaleMask($targetFile, $gifBuilder);
     $croppedImage = null;
     if (!empty($configuration['crop'])) {
         // check if it is a json object
         $cropData = json_decode($configuration['crop']);
         if ($cropData) {
             $crop = implode(',', array((int) $cropData->x, (int) $cropData->y, (int) $cropData->width, (int) $cropData->height));
         } else {
             $crop = $configuration['crop'];
         }
         list($offsetLeft, $offsetTop, $newWidth, $newHeight) = explode(',', $crop, 4);
         $backupPrefix = $gifBuilder->filenamePrefix;
         $gifBuilder->filenamePrefix = 'crop_';
         // the result info is an array with 0=width,1=height,2=extension,3=filename
         $result = $gifBuilder->imageMagickConvert($originalFileName, '', '', '', sprintf('-crop %dx%d+%d+%d', $newWidth, $newHeight, $offsetLeft, $offsetTop), '', ['noScale' => true], true);
         $gifBuilder->filenamePrefix = $backupPrefix;
         if ($result !== null) {
             $originalFileName = $croppedImage = $result[3];
         }
     }
     // Normal situation (no masking)
     if (!(is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'])) {
         // SVG
         if ($croppedImage === null && $sourceFile->getExtension() === 'svg') {
             $newDimensions = $this->getNewSvgDimensions($sourceFile, $configuration, $options, $gifBuilder);
             $result = array(0 => $newDimensions['width'], 1 => $newDimensions['height'], 3 => '');
             // all other images
         } else {
             // the result info is an array with 0=width,1=height,2=extension,3=filename
             $result = $gifBuilder->imageMagickConvert($originalFileName, $configuration['fileExtension'], $configuration['width'], $configuration['height'], $configuration['additionalParameters'], $configuration['frame'], $options);
         }
     } else {
         $targetFileName = $this->getFilenameForImageCropScaleMask($task);
         $temporaryFileName = $gifBuilder->tempPath . $targetFileName;
         $maskImage = $configuration['maskImages']['maskImage'];
         $maskBackgroundImage = $configuration['maskImages']['backgroundImage'];
         if ($maskImage instanceof Resource\FileInterface && $maskBackgroundImage instanceof Resource\FileInterface) {
             $temporaryExtension = 'png';
             if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_gif']) {
                 // If ImageMagick version 5+
                 $temporaryExtension = $gifBuilder->gifExtension;
             }
             $tempFileInfo = $gifBuilder->imageMagickConvert($originalFileName, $temporaryExtension, $configuration['width'], $configuration['height'], $configuration['additionalParameters'], $configuration['frame'], $options);
             if (is_array($tempFileInfo)) {
                 $maskBottomImage = $configuration['maskImages']['maskBottomImage'];
                 if ($maskBottomImage instanceof Resource\FileInterface) {
                     $maskBottomImageMask = $configuration['maskImages']['maskBottomImageMask'];
                 } else {
                     $maskBottomImageMask = null;
                 }
                 //	Scaling:	****
                 $tempScale = array();
                 $command = '-geometry ' . $tempFileInfo[0] . 'x' . $tempFileInfo[1] . '!';
                 $command = $this->modifyImageMagickStripProfileParameters($command, $configuration);
                 $tmpStr = $gifBuilder->randomName();
                 //	m_mask
                 $tempScale['m_mask'] = $tmpStr . '_mask.' . $temporaryExtension;
                 $gifBuilder->imageMagickExec($maskImage->getForLocalProcessing(true), $tempScale['m_mask'], $command);
                 //	m_bgImg
                 $tempScale['m_bgImg'] = $tmpStr . '_bgImg.miff';
                 $gifBuilder->imageMagickExec($maskBackgroundImage->getForLocalProcessing(), $tempScale['m_bgImg'], $command);
                 //	m_bottomImg / m_bottomImg_mask
                 if ($maskBottomImage instanceof Resource\FileInterface && $maskBottomImageMask instanceof Resource\FileInterface) {
                     $tempScale['m_bottomImg'] = $tmpStr . '_bottomImg.' . $temporaryExtension;
                     $gifBuilder->imageMagickExec($maskBottomImage->getForLocalProcessing(), $tempScale['m_bottomImg'], $command);
                     $tempScale['m_bottomImg_mask'] = $tmpStr . '_bottomImg_mask.' . $temporaryExtension;
                     $gifBuilder->imageMagickExec($maskBottomImageMask->getForLocalProcessing(), $tempScale['m_bottomImg_mask'], $command);
                     // BEGIN combining:
                     // The image onto the background
                     $gifBuilder->combineExec($tempScale['m_bgImg'], $tempScale['m_bottomImg'], $tempScale['m_bottomImg_mask'], $tempScale['m_bgImg']);
                 }
                 // The image onto the background
                 $gifBuilder->combineExec($tempScale['m_bgImg'], $tempFileInfo[3], $tempScale['m_mask'], $temporaryFileName);
                 $tempFileInfo[3] = $temporaryFileName;
                 // Unlink the temp-images...
                 foreach ($tempScale as $tempFile) {
                     if (@is_file($tempFile)) {
                         unlink($tempFile);
                     }
                 }
             }
             $result = $tempFileInfo;
         }
     }
     // check if the processing really generated a new file (scaled and/or cropped)
     if ($result !== null) {
         if ($result[3] !== $originalFileName || $originalFileName === $croppedImage) {
             $result = array('width' => $result[0], 'height' => $result[1], 'filePath' => $result[3]);
         } else {
             // No file was generated
             $result = null;
         }
     }
     // Cleanup temp file if it isn't used as result
     if ($croppedImage && ($result === null || $croppedImage !== $result['filePath'])) {
         GeneralUtility::unlink_tempfile($croppedImage);
     }
     return $result;
 }
 /**
  * This method actually does the processing of files locally
  *
  * Takes the original file (for remote storages this will be fetched from the remote server),
  * does the IM magic on the local server by creating a temporary typo3temp/ file,
  * copies the typo3temp/ file to the processing folder of the target storage and
  * removes the typo3temp/ file.
  *
  * The returned array has the following structure:
  *   width => 100
  *   height => 200
  *   filePath => /some/path
  *
  * @param TaskInterface $task
  * @return array|NULL
  */
 public function process(TaskInterface $task)
 {
     $result = NULL;
     $targetFile = $task->getTargetFile();
     $sourceFile = $task->getSourceFile();
     $originalFileName = $sourceFile->getForLocalProcessing(FALSE);
     /** @var $gifBuilder \TYPO3\CMS\Frontend\Imaging\GifBuilder */
     $gifBuilder = Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Imaging\\GifBuilder');
     $gifBuilder->init();
     $gifBuilder->absPrefix = PATH_site;
     $configuration = $targetFile->getProcessingConfiguration();
     $configuration['additionalParameters'] = $this->modifyImageMagickStripProfileParameters($configuration['additionalParameters'], $configuration);
     if (empty($configuration['fileExtension'])) {
         $configuration['fileExtension'] = $task->getTargetFileExtension();
     }
     $options = $this->getConfigurationForImageCropScaleMask($targetFile, $gifBuilder);
     // Normal situation (no masking)
     if (!(is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'])) {
         // the result info is an array with 0=width,1=height,2=extension,3=filename
         $result = $gifBuilder->imageMagickConvert($originalFileName, $configuration['fileExtension'], $configuration['width'], $configuration['height'], $configuration['additionalParameters'], $configuration['frame'], $options);
     } else {
         $targetFileName = $this->getFilenameForImageCropScaleMask($task);
         $temporaryFileName = $gifBuilder->tempPath . $targetFileName;
         $maskImage = $configuration['maskImages']['maskImage'];
         $maskBackgroundImage = $configuration['maskImages']['backgroundImage'];
         if ($maskImage instanceof Resource\FileInterface && $maskBackgroundImage instanceof Resource\FileInterface) {
             $temporaryExtension = 'png';
             if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_gif']) {
                 // If ImageMagick version 5+
                 $temporaryExtension = $gifBuilder->gifExtension;
             }
             $tempFileInfo = $gifBuilder->imageMagickConvert($originalFileName, $temporaryExtension, $configuration['width'], $configuration['height'], $configuration['additionalParameters'], $configuration['frame'], $options);
             if (is_array($tempFileInfo)) {
                 $maskBottomImage = $configuration['maskImages']['maskBottomImage'];
                 if ($maskBottomImage instanceof Resource\FileInterface) {
                     $maskBottomImageMask = $configuration['maskImages']['maskBottomImageMask'];
                 } else {
                     $maskBottomImageMask = NULL;
                 }
                 //	Scaling:	****
                 $tempScale = array();
                 $command = '-geometry ' . $tempFileInfo[0] . 'x' . $tempFileInfo[1] . '!';
                 $command = $this->modifyImageMagickStripProfileParameters($command, $configuration);
                 $tmpStr = $gifBuilder->randomName();
                 //	m_mask
                 $tempScale['m_mask'] = $tmpStr . '_mask.' . $temporaryExtension;
                 $gifBuilder->imageMagickExec($maskImage->getForLocalProcessing(TRUE), $tempScale['m_mask'], $command);
                 //	m_bgImg
                 $tempScale['m_bgImg'] = $tmpStr . '_bgImg.miff';
                 $gifBuilder->imageMagickExec($maskBackgroundImage->getForLocalProcessing(), $tempScale['m_bgImg'], $command);
                 //	m_bottomImg / m_bottomImg_mask
                 if ($maskBottomImage instanceof Resource\FileInterface && $maskBottomImageMask instanceof Resource\FileInterface) {
                     $tempScale['m_bottomImg'] = $tmpStr . '_bottomImg.' . $temporaryExtension;
                     $gifBuilder->imageMagickExec($maskBottomImage->getForLocalProcessing(), $tempScale['m_bottomImg'], $command);
                     $tempScale['m_bottomImg_mask'] = $tmpStr . '_bottomImg_mask.' . $temporaryExtension;
                     $gifBuilder->imageMagickExec($maskBottomImageMask->getForLocalProcessing(), $tempScale['m_bottomImg_mask'], $command);
                     // BEGIN combining:
                     // The image onto the background
                     $gifBuilder->combineExec($tempScale['m_bgImg'], $tempScale['m_bottomImg'], $tempScale['m_bottomImg_mask'], $tempScale['m_bgImg']);
                 }
                 // The image onto the background
                 $gifBuilder->combineExec($tempScale['m_bgImg'], $tempFileInfo[3], $tempScale['m_mask'], $temporaryFileName);
                 $tempFileInfo[3] = $temporaryFileName;
                 // Unlink the temp-images...
                 foreach ($tempScale as $tempFile) {
                     if (@is_file($tempFile)) {
                         unlink($tempFile);
                     }
                 }
             }
             $result = $tempFileInfo;
         }
     }
     // check if the processing really generated a new file
     if ($result !== NULL) {
         if ($result[3] !== $originalFileName) {
             $result = array('width' => $result[0], 'height' => $result[1], 'filePath' => $result[3]);
         } else {
             // No file was generated
             $result = NULL;
         }
     }
     return $result;
 }
 /**
  * Returns the path to a temporary file for processing
  *
  * @param TaskInterface $task
  * @return string
  */
 protected function getTemporaryFilePath(TaskInterface $task)
 {
     return GeneralUtility::tempnam('preview_', '.' . $task->getTargetFileExtension());
 }