‪TYPO3CMS  11.5
LocalCropScaleMaskHelper.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
26 
31 {
51  public function ‪process(‪TaskInterface $task)
52  {
53  return $this->‪processWithLocalFile($task, $task->‪getSourceFile()->‪getForLocalProcessing(false));
54  }
55 
64  public function ‪processWithLocalFile(‪TaskInterface $task, string $originalFileName): ?array
65  {
66  $result = null;
67  $targetFile = $task->‪getTargetFile();
68 
69  $gifBuilder = GeneralUtility::makeInstance(GifBuilder::class);
70 
71  $configuration = $targetFile->getProcessingConfiguration();
72  $configuration['additionalParameters'] = $this->‪modifyImageMagickStripProfileParameters((string)($configuration['additionalParameters'] ?? ''), $configuration);
73 
74  if (empty($configuration['fileExtension'])) {
75  $configuration['fileExtension'] = $task->‪getTargetFileExtension();
76  }
77 
78  $options = $this->‪getConfigurationForImageCropScaleMask($targetFile, $gifBuilder);
79 
80  $croppedImage = null;
81  if (!empty($configuration['crop'])) {
82  // check if it is a json object
83  $cropData = json_decode($configuration['crop']);
84  if ($cropData) {
85  $offsetLeft = (int)($cropData->x ?? 0);
86  $offsetTop = (int)($cropData->y ?? 0);
87  $newWidth = (int)($cropData->width ?? 0);
88  $newHeight = (int)($cropData->height ?? 0);
89  } else {
90  [$offsetLeft, $offsetTop, $newWidth, $newHeight] = explode(',', $configuration['crop'], 4);
91  }
92 
93  $backupPrefix = $gifBuilder->filenamePrefix;
94  $gifBuilder->filenamePrefix = 'crop_';
95 
96  $jpegQuality = ‪MathUtility::forceIntegerInRange(‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['jpg_quality'], 10, 100, 85);
97 
98  // the result info is an array with 0=width,1=height,2=extension,3=filename
99  $result = $gifBuilder->imageMagickConvert(
100  $originalFileName,
101  $configuration['fileExtension'],
102  '',
103  '',
104  sprintf('-crop %dx%d+%d+%d +repage -quality %d', $newWidth, $newHeight, $offsetLeft, $offsetTop, $jpegQuality),
105  '',
106  ['noScale' => true],
107  true
108  );
109  $gifBuilder->filenamePrefix = $backupPrefix;
110 
111  if ($result !== null) {
112  $originalFileName = $croppedImage = $result[3];
113  }
114  }
115 
116  // Normal situation (no masking)
117  if (!(is_array($configuration['maskImages'] ?? null) && ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'])) {
118  // the result info is an array with 0=width,1=height,2=extension,3=filename
119  $result = $gifBuilder->imageMagickConvert(
120  $originalFileName,
121  $configuration['fileExtension'],
122  $configuration['width'] ?? '',
123  $configuration['height'] ?? '',
124  $configuration['additionalParameters'],
125  $configuration['frame'] ?? '',
126  $options,
127  // in case file is in `/typo3temp/`, it must create a result
128  $this->‪isTemporaryFile($originalFileName)
129  );
130  } else {
131  $targetFileName = $this->‪getFilenameForImageCropScaleMask($task);
132  $temporaryFileName = ‪Environment::getPublicPath() . '/typo3temp/' . $targetFileName;
133  $maskImage = $configuration['maskImages']['maskImage'] ?? null;
134  $maskBackgroundImage = $configuration['maskImages']['backgroundImage'];
135  if ($maskImage instanceof ‪FileInterface && $maskBackgroundImage instanceof ‪FileInterface) {
136  $temporaryExtension = 'png';
137  if (!‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_allowTemporaryMasksAsPng']) {
138  // If ImageMagick version 5+
139  $temporaryExtension = $gifBuilder->gifExtension;
140  }
141  $tempFileInfo = $gifBuilder->imageMagickConvert(
142  $originalFileName,
143  $temporaryExtension,
144  $configuration['width'] ?? '',
145  $configuration['height'] ?? '',
146  $configuration['additionalParameters'],
147  $configuration['frame'] ?? '',
148  $options
149  );
150  if (is_array($tempFileInfo)) {
151  $maskBottomImage = $configuration['maskImages']['maskBottomImage'];
152  if ($maskBottomImage instanceof ‪FileInterface) {
153  $maskBottomImageMask = $configuration['maskImages']['maskBottomImageMask'];
154  } else {
155  $maskBottomImageMask = null;
156  }
157 
158  // Scaling: ****
159  $tempScale = [];
160  $command = '-geometry ' . $tempFileInfo[0] . 'x' . $tempFileInfo[1] . '!';
161  $command = $this->‪modifyImageMagickStripProfileParameters($command, $configuration);
162  $tmpStr = $gifBuilder->randomName();
163  // m_mask
164  $tempScale['m_mask'] = $tmpStr . '_mask.' . $temporaryExtension;
165  $gifBuilder->imageMagickExec($maskImage->getForLocalProcessing(true), $tempScale['m_mask'], $command);
166  // m_bgImg
167  $tempScale['m_bgImg'] = $tmpStr . '_bgImg.miff';
168  $gifBuilder->imageMagickExec($maskBackgroundImage->getForLocalProcessing(), $tempScale['m_bgImg'], $command);
169  // m_bottomImg / m_bottomImg_mask
170  if ($maskBottomImage instanceof ‪FileInterface && $maskBottomImageMask instanceof ‪FileInterface) {
171  $tempScale['m_bottomImg'] = $tmpStr . '_bottomImg.' . $temporaryExtension;
172  $gifBuilder->imageMagickExec($maskBottomImage->getForLocalProcessing(), $tempScale['m_bottomImg'], $command);
173  $tempScale['m_bottomImg_mask'] = ($tmpStr . '_bottomImg_mask.') . $temporaryExtension;
174  $gifBuilder->imageMagickExec($maskBottomImageMask->getForLocalProcessing(), $tempScale['m_bottomImg_mask'], $command);
175  // BEGIN combining:
176  // The image onto the background
177  $gifBuilder->combineExec($tempScale['m_bgImg'], $tempScale['m_bottomImg'], $tempScale['m_bottomImg_mask'], $tempScale['m_bgImg']);
178  }
179  // The image onto the background
180  $gifBuilder->combineExec($tempScale['m_bgImg'], $tempFileInfo[3], $tempScale['m_mask'], $temporaryFileName);
181  $tempFileInfo[3] = $temporaryFileName;
182  // Unlink the temp-images...
183  foreach ($tempScale as $tempFile) {
184  if (@is_file($tempFile)) {
185  unlink($tempFile);
186  }
187  }
188  }
189  $result = $tempFileInfo;
190  }
191  }
192 
193  // check if the processing really generated a new file (scaled and/or cropped)
194  if ($result !== null) {
195  if ($result[3] !== $originalFileName || $originalFileName === $croppedImage) {
196  $result = [
197  'width' => $result[0],
198  'height' => $result[1],
199  'filePath' => $result[3],
200  ];
201  } else {
202  // No file was generated
203  $result = null;
204  }
205  }
206 
207  // Cleanup temp file if it isn't used as result
208  if ($croppedImage && ($result === null || $croppedImage !== $result['filePath'])) {
209  GeneralUtility::unlink_tempfile($croppedImage);
210  }
211 
212  return $result;
213  }
214 
221  protected function ‪getConfigurationForImageCropScaleMask(‪ProcessedFile $processedFile, ‪GifBuilder $gifBuilder)
222  {
223  $configuration = $processedFile->‪getProcessingConfiguration();
224 
225  if ($configuration['useSample'] ?? false) {
226  $gifBuilder->scalecmd = '-sample';
227  }
228  $options = [];
229  if ($configuration['maxWidth'] ?? false) {
230  $options['maxW'] = $configuration['maxWidth'];
231  }
232  if ($configuration['maxHeight'] ?? false) {
233  $options['maxH'] = $configuration['maxHeight'];
234  }
235  if ($configuration['minWidth'] ?? false) {
236  $options['minW'] = $configuration['minWidth'];
237  }
238  if ($configuration['minHeight'] ?? false) {
239  $options['minH'] = $configuration['minHeight'];
240  }
241 
242  $options['noScale'] = $configuration['noScale'] ?? null;
243 
244  return $options;
245  }
246 
254  {
255  $configuration = $task->‪getTargetFile()->‪getProcessingConfiguration();
256  $targetFileExtension = $task->‪getSourceFile()->‪getExtension();
257  $processedFileExtension = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif';
258  if (is_array($configuration['maskImages']) && ‪$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'] && $task->‪getSourceFile()->‪getExtension() != $processedFileExtension) {
259  $targetFileExtension = 'jpg';
260  } elseif ($configuration['fileExtension']) {
261  $targetFileExtension = $configuration['fileExtension'];
262  }
263 
264  return $task->‪getTargetFile()->‪generateProcessedFileNameWithoutExtension() . '.' . ltrim(trim($targetFileExtension), '.');
265  }
266 
274  protected function ‪modifyImageMagickStripProfileParameters(string $parameters, array $configuration)
275  {
276  if (!isset($configuration['stripProfile'])) {
277  return $parameters;
278  }
279 
280  $gfxConf = ‪$GLOBALS['TYPO3_CONF_VARS']['GFX'] ?? [];
281  // Use legacy processor_stripColorProfileCommand setting if defined, otherwise
282  // use the preferred configuration option processor_stripColorProfileParameters
283  $stripColorProfileCommand = $gfxConf['processor_stripColorProfileCommand'] ??
284  implode(' ', array_map([CommandUtility::class, 'escapeShellArgument'], $gfxConf['processor_stripColorProfileParameters'] ?? []));
285 
286  // Strips profile information of image to save some space:
287  if ($configuration['stripProfile'] && $stripColorProfileCommand !== '') {
288  return $stripColorProfileCommand . $parameters;
289  }
290  return $parameters . '###SkipStripProfile###';
291  }
292 
293  protected function ‪isTemporaryFile(string $filePath): bool
294  {
295  return str_starts_with($filePath, ‪Environment::getPublicPath() . '/typo3temp/');
296  }
297 }
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\modifyImageMagickStripProfileParameters
‪string modifyImageMagickStripProfileParameters(string $parameters, array $configuration)
Definition: LocalCropScaleMaskHelper.php:274
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:22
‪TYPO3\CMS\Core\Resource\AbstractFile\getForLocalProcessing
‪string getForLocalProcessing($writable=true)
Definition: AbstractFile.php:583
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\isTemporaryFile
‪isTemporaryFile(string $filePath)
Definition: LocalCropScaleMaskHelper.php:293
‪TYPO3\CMS\Core\Resource\Processing\TaskInterface
Definition: TaskInterface.php:33
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\processWithLocalFile
‪array null processWithLocalFile(TaskInterface $task, string $originalFileName)
Definition: LocalCropScaleMaskHelper.php:64
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\getFilenameForImageCropScaleMask
‪string getFilenameForImageCropScaleMask(TaskInterface $task)
Definition: LocalCropScaleMaskHelper.php:253
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Core\Resource\Processing\TaskInterface\getSourceFile
‪Resource File getSourceFile()
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\getConfigurationForImageCropScaleMask
‪array getConfigurationForImageCropScaleMask(ProcessedFile $processedFile, GifBuilder $gifBuilder)
Definition: LocalCropScaleMaskHelper.php:221
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper
Definition: LocalCropScaleMaskHelper.php:31
‪TYPO3\CMS\Core\Resource\Processing
Definition: AbstractGraphicalTask.php:16
‪TYPO3\CMS\Core\Resource\ProcessedFile\getProcessingConfiguration
‪array getProcessingConfiguration()
Definition: ProcessedFile.php:543
‪TYPO3\CMS\Core\Resource\ProcessedFile\generateProcessedFileNameWithoutExtension
‪string generateProcessedFileNameWithoutExtension()
Definition: ProcessedFile.php:578
‪TYPO3\CMS\Core\Resource\Processing\TaskInterface\getTargetFile
‪Resource ProcessedFile getTargetFile()
‪TYPO3\CMS\Frontend\Imaging\GifBuilder
Definition: GifBuilder.php:57
‪TYPO3\CMS\Core\Resource
Definition: generateMimeTypes.php:52
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:45
‪TYPO3\CMS\Core\Resource\AbstractFile\getExtension
‪string getExtension()
Definition: AbstractFile.php:255
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Resource\Processing\LocalCropScaleMaskHelper\process
‪array null process(TaskInterface $task)
Definition: LocalCropScaleMaskHelper.php:51
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Core\Utility\CommandUtility
Definition: CommandUtility.php:49
‪TYPO3\CMS\Core\Resource\Processing\TaskInterface\getTargetFileExtension
‪string getTargetFileExtension()