[BUGFIX] Add missing initialization of GraphicalFunctions
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / OnlineMedia / Processing / PreviewProcessing.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\OnlineMedia\Processing;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
18 use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
19 use TYPO3\CMS\Core\Resource\File;
20 use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
21 use TYPO3\CMS\Core\Resource\ProcessedFile;
22 use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
23 use TYPO3\CMS\Core\Resource\Processing\LocalImageProcessor;
24 use TYPO3\CMS\Core\Resource\Service\FileProcessingService;
25 use TYPO3\CMS\Core\Utility\CommandUtility;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Frontend\Imaging\GifBuilder;
28
29 /**
30 * Preview of Online Media item Processing
31 */
32 class PreviewProcessing
33 {
34 /**
35 * @var LocalImageProcessor
36 */
37 protected $processor;
38
39 /**
40 * @param ProcessedFile $processedFile
41 * @return bool
42 */
43 protected function needsReprocessing($processedFile)
44 {
45 return $processedFile->isNew()
46 || (!$processedFile->usesOriginalFile() && !$processedFile->exists())
47 || $processedFile->isOutdated();
48 }
49
50 /**
51 * Process file
52 * Create static image preview for Online Media item when possible
53 *
54 * @param FileProcessingService $fileProcessingService
55 * @param DriverInterface $driver
56 * @param ProcessedFile $processedFile
57 * @param File $file
58 * @param string $taskType
59 * @param array $configuration
60 */
61 public function processFile(FileProcessingService $fileProcessingService, DriverInterface $driver, ProcessedFile $processedFile, File $file, $taskType, array $configuration)
62 {
63 if ($taskType !== 'Image.Preview' && $taskType !== 'Image.CropScaleMask') {
64 return;
65 }
66 // Check if processing is needed
67 if (!$this->needsReprocessing($processedFile)) {
68 return;
69 }
70 // Check if there is a OnlineMediaHelper registered for this file type
71 $helper = OnlineMediaHelperRegistry::getInstance()->getOnlineMediaHelper($file);
72 if ($helper === false) {
73 return;
74 }
75 // Check if helper provides a preview image
76 $temporaryFileName = $helper->getPreviewImage($file);
77 if (empty($temporaryFileName) || !file_exists($temporaryFileName)) {
78 return;
79 }
80 $temporaryFileNameForResizedThumb = uniqid(PATH_site . 'typo3temp/var/transient/online_media_' . $file->getHashedIdentifier()) . '.jpg';
81 $configuration = $processedFile->getProcessingConfiguration();
82 switch ($taskType) {
83 case 'Image.Preview':
84 $this->resizeImage($temporaryFileName, $temporaryFileNameForResizedThumb, $configuration);
85 break;
86
87 case 'Image.CropScaleMask':
88 $this->cropScaleImage($temporaryFileName, $temporaryFileNameForResizedThumb, $configuration);
89 break;
90 }
91 GeneralUtility::unlink_tempfile($temporaryFileName);
92 if (is_file($temporaryFileNameForResizedThumb)) {
93 $processedFile->setName($this->getTargetFileName($processedFile));
94 list($width, $height) = getimagesize($temporaryFileNameForResizedThumb);
95 $processedFile->updateProperties(
96 [
97 'width' => $width,
98 'height' => $height,
99 'size' => filesize($temporaryFileNameForResizedThumb),
100 'checksum' => $processedFile->getTask()->getConfigurationChecksum()
101 ]
102 );
103 $processedFile->updateWithLocalFile($temporaryFileNameForResizedThumb);
104 GeneralUtility::unlink_tempfile($temporaryFileNameForResizedThumb);
105
106 /** @var ProcessedFileRepository $processedFileRepository */
107 $processedFileRepository = GeneralUtility::makeInstance(ProcessedFileRepository::class);
108 $processedFileRepository->add($processedFile);
109 }
110 }
111
112 /**
113 * @param ProcessedFile $processedFile
114 * @param string $prefix
115 * @return string
116 */
117 protected function getTargetFileName(ProcessedFile $processedFile, $prefix = 'preview_')
118 {
119 return $prefix . $processedFile->getTask()->getConfigurationChecksum() . '_' . $processedFile->getOriginalFile()->getNameWithoutExtension() . '.jpg';
120 }
121
122 /**
123 * @param string $originalFileName
124 * @param string $temporaryFileName
125 * @param array $configuration
126 */
127 protected function resizeImage($originalFileName, $temporaryFileName, $configuration)
128 {
129 // Create the temporary file
130 if (empty($GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'])) {
131 return;
132 }
133
134 if (file_exists($originalFileName)) {
135 $arguments = CommandUtility::escapeShellArguments([
136 'width' => $configuration['width'],
137 'height' => $configuration['height'],
138 'originalFileName' => $originalFileName,
139 'temporaryFileName' => $temporaryFileName,
140 ]);
141 $parameters = '-sample ' . $arguments['width'] . 'x' . $arguments['height'] . ' '
142 . $arguments['originalFileName'] . '[0] ' . $arguments['temporaryFileName'];
143
144 $cmd = CommandUtility::imageMagickCommand('convert', $parameters) . ' 2>&1';
145 CommandUtility::exec($cmd);
146 }
147
148 if (!file_exists($temporaryFileName)) {
149 // Create a error image
150 $graphicalFunctions = $this->getGraphicalFunctionsObject();
151 $graphicalFunctions->getTemporaryImageWithText($temporaryFileName, 'No thumb', 'generated!', basename($originalFileName));
152 }
153 }
154
155 /**
156 * cropScaleImage
157 *
158 * @param string $originalFileName
159 * @param string $temporaryFileName
160 * @param array $configuration
161 */
162 protected function cropScaleImage($originalFileName, $temporaryFileName, $configuration)
163 {
164 if (file_exists($originalFileName)) {
165 /** @var $gifBuilder GifBuilder */
166 $gifBuilder = GeneralUtility::makeInstance(GifBuilder::class);
167 $gifBuilder->init();
168
169 $options = $this->getConfigurationForImageCropScaleMask($configuration, $gifBuilder);
170 $info = $gifBuilder->getImageDimensions($originalFileName);
171 $data = $gifBuilder->getImageScale($info, $configuration['width'], $configuration['height'], $options);
172
173 $info[0] = $data[0];
174 $info[1] = $data[1];
175 $frame = '';
176 $params = $gifBuilder->cmds['jpg'];
177
178 // Cropscaling:
179 if ($data['crs']) {
180 if (!$data['origW']) {
181 $data['origW'] = $data[0];
182 }
183 if (!$data['origH']) {
184 $data['origH'] = $data[1];
185 }
186 $offsetX = (int)(($data[0] - $data['origW']) * ($data['cropH'] + 100) / 200);
187 $offsetY = (int)(($data[1] - $data['origH']) * ($data['cropV'] + 100) / 200);
188 $params .= ' -crop ' . $data['origW'] . 'x' . $data['origH'] . '+' . $offsetX . '+' . $offsetY . '! ';
189 }
190 $command = $gifBuilder->scalecmd . ' ' . $info[0] . 'x' . $info[1] . '! ' . $params . ' ';
191 $gifBuilder->imageMagickExec($originalFileName, $temporaryFileName, $command, $frame);
192 }
193 if (!file_exists($temporaryFileName)) {
194 // Create a error image
195 $graphicalFunctions = $this->getGraphicalFunctionsObject();
196 $graphicalFunctions->getTemporaryImageWithText($temporaryFileName, 'No thumb', 'generated!', basename($originalFileName));
197 }
198 }
199
200 /**
201 * Get configuration for ImageCropScaleMask processing
202 *
203 * @param array $configuration
204 * @param GifBuilder $gifBuilder
205 * @return array
206 */
207 protected function getConfigurationForImageCropScaleMask(array $configuration, GifBuilder $gifBuilder)
208 {
209 if (!empty($configuration['useSample'])) {
210 $gifBuilder->scalecmd = '-sample';
211 }
212 $options = [];
213 if (!empty($configuration['maxWidth'])) {
214 $options['maxW'] = $configuration['maxWidth'];
215 }
216 if (!empty($configuration['maxHeight'])) {
217 $options['maxH'] = $configuration['maxHeight'];
218 }
219 if (!empty($configuration['minWidth'])) {
220 $options['minW'] = $configuration['minWidth'];
221 }
222 if (!empty($configuration['minHeight'])) {
223 $options['minH'] = $configuration['minHeight'];
224 }
225
226 $options['noScale'] = $configuration['noScale'];
227
228 return $options;
229 }
230
231 /**
232 * @return LocalImageProcessor
233 */
234 protected function getProcessor()
235 {
236 if (!$this->processor) {
237 $this->processor = GeneralUtility::makeInstance(LocalImageProcessor::class);
238 }
239 return $this->processor;
240 }
241
242 /**
243 * @return GraphicalFunctions
244 */
245 protected function getGraphicalFunctionsObject()
246 {
247 static $graphicalFunctionsObject = null;
248 if ($graphicalFunctionsObject === null) {
249 $graphicalFunctionsObject = GeneralUtility::makeInstance(GraphicalFunctions::class);
250 $graphicalFunctionsObject->init();
251 }
252 return $graphicalFunctionsObject;
253 }
254 }