/** * Processing the focus point crop (fallback to LocalCropScaleMaskHelper) * * @param TaskInterface $task * * @return array|NULL */ public function process(TaskInterface $task) { $configuration = $task->getConfiguration(); $crop = $configuration['crop'] ? json_decode($configuration['crop']) : null; if ($crop instanceof \stdClass && isset($crop->x)) { // if crop is enable release the process return parent::process($task); } $sourceFile = $task->getSourceFile(); try { if (self::$deepCheck === false) { self::$deepCheck = true; $ratio = $this->getCurrentRatioConfiguration(); $this->dimensionService->getRatio($ratio); $newFile = $this->focusCropService->getCroppedImageSrcByFile($sourceFile, $ratio); $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($newFile); $targetFile = $task->getTargetFile(); ObjectAccess::setProperty($targetFile, 'originalFile', $file, true); ObjectAccess::setProperty($targetFile, 'originalFileSha1', $file->getSha1(), true); ObjectAccess::setProperty($targetFile, 'storage', $file->getStorage(), true); ObjectAccess::setProperty($task, 'sourceFile', $file, true); ObjectAccess::setProperty($task, 'targetFile', $targetFile, true); } } catch (\Exception $ex) { } self::$deepCheck = false; return parent::process($task); }
/** * 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(); // Merge custom configuration with default configuration $configuration = array_merge(array('width' => 64, 'height' => 64), $task->getConfiguration()); $configuration['width'] = Utility\MathUtility::forceIntegerInRange($configuration['width'], 1, 1000); $configuration['height'] = Utility\MathUtility::forceIntegerInRange($configuration['height'], 1, 1000); $originalFileName = $targetFile->getOriginalFile()->getForLocalProcessing(FALSE); // Create a temporary file in typo3temp/ if ($targetFile->getOriginalFile()->getExtension() === 'jpg') { $targetFileExtension = '.jpg'; } else { $targetFileExtension = '.png'; } // Create the thumb filename in typo3temp/preview_....jpg $temporaryFileName = Utility\GeneralUtility::tempnam('preview_') . $targetFileExtension; // Check file extension if ($targetFile->getOriginalFile()->getType() != Resource\File::FILETYPE_IMAGE && !Utility\GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $targetFile->getOriginalFile()->getExtension())) { // Create a default image $this->processor->getTemporaryImageWithText($temporaryFileName, 'Not imagefile!', 'No ext!', $targetFile->getOriginalFile()->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!', $targetFile->getOriginalFile()->getName()); } } } return array('filePath' => $temporaryFileName); }
/** * @param TaskInterface $task * @return array|null */ protected function process(TaskInterface $task) { $result = NULL; $sourceFile = $task->getOriginalProcessedFile() ?: $task->getSourceFile(); $sourceFilePath = realpath($sourceFile->getForLocalProcessing(FALSE)); $targetFilePath = realpath(GeneralUtility::tempnam('_processed_/nlx-tempfile-', '.' . $sourceFile->getExtension())); switch ($sourceFile->getExtension()) { case 'jpg': case 'jpeg': if ($this->settings['jpg.']['enabled'] === FALSE) { return $result; } $library = 'jpegtran'; $arguments = sprintf('-copy none -optimize %s -outfile %s %s', $this->settings['jpg.']['progressive'] === TRUE ? '-progressive' : '', escapeshellarg($targetFilePath), escapeshellarg($sourceFilePath)); break; case 'png': if ($this->settings['png.']['enabled'] === FALSE) { return $result; } $library = 'optipng'; $arguments = sprintf('-o%u -strip all -fix -clobber -force -out %s %s', $this->settings['png.']['optimizationLevel'], escapeshellarg($targetFilePath), escapeshellarg($sourceFilePath)); break; case 'gif': if ($this->settings['gif.']['enabled'] === FALSE) { return $result; } $library = 'gifsicle'; $arguments = sprintf('--batch -O%u -o %s %s', $this->settings['gif.']['optimizationLevel'], escapeshellarg($targetFilePath), escapeshellarg($sourceFilePath)); break; case 'svg': if ($this->settings['svg.']['enabled'] === FALSE) { return $result; } $library = 'svgo'; $arguments = sprintf('%s %s', escapeshellarg($sourceFilePath), escapeshellarg($targetFilePath)); break; default: return $result; } $cmd = escapeshellcmd($library) . ' ' . $arguments; $output = []; exec($cmd, $output, $return); if ($return === 0) { $result = array('filePath' => $targetFilePath); } return $result; }
/** * Processing the focus point crop (fallback to LocalCropScaleMaskHelper) * * @param TaskInterface $task * * @return array|NULL */ public function process(TaskInterface $task) { $sourceFile = $task->getSourceFile(); try { $ratio = $this->getCurrentRatioConfiguration(); $this->dimensionService->getRatio($ratio); $newFile = $this->focusCropService->getCroppedImageSrcByFile($sourceFile, $ratio); $file = ResourceFactory::getInstance()->retrieveFileOrFolderObject($newFile); $targetFile = $task->getTargetFile(); ObjectAccess::setProperty($targetFile, 'originalFile', $file, TRUE); ObjectAccess::setProperty($targetFile, 'originalFileSha1', $file->getSha1(), TRUE); ObjectAccess::setProperty($targetFile, 'storage', $file->getStorage(), TRUE); ObjectAccess::setProperty($task, 'sourceFile', $file, TRUE); ObjectAccess::setProperty($task, 'targetFile', $targetFile, TRUE); } catch (\Exception $ex) { } return parent::process($task); }
/** * Returns TRUE if this processor can process the given task. * * @param TaskInterface $task * @return boolean */ public function canProcessTask(TaskInterface $task) { $canProcessTask = $task->getType() === 'Image'; $canProcessTask = $canProcessTask & in_array($task->getName(), array('Preview', 'CropScaleMask')); return $canProcessTask; }
/** * Returns the filename for a cropped/scaled/masked file. * * @param TaskInterface $task * @return string */ protected function getFilenameForImageCropScaleMask(TaskInterface $task) { $configuration = $task->getTargetFile()->getProcessingConfiguration(); $targetFileExtension = $task->getSourceFile()->getExtension(); $processedFileExtension = $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif'; if (is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && $task->getSourceFile()->getExtension() != $processedFileExtension) { $targetFileExtension = 'jpg'; } elseif ($configuration['fileExtension']) { $targetFileExtension = $configuration['fileExtension']; } return $task->getTargetFile()->generateProcessedFileNameWithoutExtension() . '.' . ltrim(trim($targetFileExtension), '.'); }
/** * Check if the to be processed target file already exists * if exist take info from that file and mark task as done * * @param TaskInterface $task * @return bool */ protected function checkForExistingTargetFile(TaskInterface $task) { $processingFolder = $task->getTargetFile()->getStorage()->getProcessingFolder(); $storage = $task->getTargetFile()->getStorage(); // @todo: make proper use of the FAL API, see https://forge.typo3.org/issues/67126 if ($processingFolder->hasFile($task->getTargetFileName()) && $storage->getDriverType() === 'Local') { $processedFileIdentifier = rtrim($processingFolder->getIdentifier(), '/') . '/' . $task->getTargetFileName(); $configuration = $storage->getConfiguration(); if ($configuration['pathType'] === 'relative') { $absoluteBasePath = PATH_site . $configuration['basePath']; } else { $absoluteBasePath = $configuration['basePath']; } $targetFile = $absoluteBasePath . ltrim($processedFileIdentifier, '/'); $task->setExecuted(true); $imageDimensions = $this->getGraphicalFunctionsObject()->getImageDimensions($targetFile); $task->getTargetFile()->setName($task->getTargetFileName()); $properties = array('width' => $imageDimensions[0], 'height' => $imageDimensions[1], 'size' => filesize($targetFile), 'checksum' => $task->getConfigurationChecksum()); $task->getTargetFile()->updateProperties($properties); return true; } else { return false; } }
/** * 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()); }
/** * Check if the to be processed target file already exists * if exist take info from that file and mark task as done * * @param TaskInterface $task * @return bool */ protected function checkForExistingTargetFile(TaskInterface $task) { // the storage of the processed file, not of the original file! $storage = $task->getTargetFile()->getStorage(); $processingFolder = $storage->getProcessingFolder(); // explicitly check for the raw filename here, as we check for files that existed before we even started // processing, i.e. that were processed earlier if ($processingFolder->hasFile($task->getTargetFileName())) { // When the processed file already exists set it as processed file $task->getTargetFile()->setName($task->getTargetFileName()); // If the processed file is stored on a remote server, we must fetch a local copy of the file, as we // have no API for fetching file metadata from a remote file. $localProcessedFile = $storage->getFileForLocalProcessing($task->getTargetFile(), false); $task->setExecuted(true); $imageDimensions = $this->getGraphicalFunctionsObject()->getImageDimensions($localProcessedFile); $properties = array('width' => $imageDimensions[0], 'height' => $imageDimensions[1], 'size' => filesize($localProcessedFile), 'checksum' => $task->getConfigurationChecksum()); $task->getTargetFile()->updateProperties($properties); return true; } else { return false; } }
/** * 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. * * @param TaskInterface $task * @return array */ public function process(TaskInterface $task) { $result = NULL; $targetFile = $task->getTargetFile(); $originalFileName = $targetFile->getOriginalFile()->getForLocalProcessing(FALSE); /** @var $gifBuilder \TYPO3\CMS\Frontend\Imaging\GifBuilder */ $gifBuilder = Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Imaging\\GifBuilder'); $gifBuilder->init(); $configuration = $targetFile->getProcessingConfiguration(); $configuration['additionalParameters'] = $this->modifyImageMagickStripProfileParameters($configuration['additionalParameters'], $configuration); $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($targetFile); $temporaryFileName = $gifBuilder->tempPath . $targetFileName; $maskImage = $configuration['maskImages']['maskImage']; $maskBackgroundImage = $configuration['maskImages']['backgroundImage']; if ($maskImage instanceof Resource\FileInterface && $maskBackgroundImage instanceof Resource\FileInterface) { $negate = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_negate_mask'] ? ' -negate' : ''; $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 $maskBottomImage) { $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 . $negate); // m_bgImg $tempScale['m_bgImg'] = $tmpStr . '_bgImg.' . trim($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_noloss']); $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 . $negate); // 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); // 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; }