[TASK] Remove compat layer for new 6.0 classes
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Service / ImageProcessingService.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Service;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 // TODO should this be a singleton?
30 /**
31 * Thumbnail service
32 *
33 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
34 * @package TYPO3
35 * @subpackage t3lib
36 */
37 class ImageProcessingService {
38
39 /**
40 * Renders the actual image
41 *
42 * @param \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject
43 * @param $file
44 * @param array $fileConfiguration
45 * @return array
46 */
47 public function getImgResource(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $contentObject, $file, array $fileConfiguration) {
48 if ($fileConfiguration['import.']) {
49 $ifile = $contentObject->stdWrap('', $fileConfiguration['import.']);
50 if ($ifile) {
51 $file = $fileConfiguration['import'] . $ifile;
52 }
53 }
54 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($file)) {
55 $file = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory')->getFileObject($file);
56 }
57 if ($file instanceof \TYPO3\CMS\Core\Resource\FileInterface) {
58 $theImage = $file->getForLocalProcessing(FALSE);
59 } else {
60 // clean ../ sections of the path and resolve to proper string.
61 // This is necessary for the \TYPO3\CMS\Core\Resource\Service\FrontendContentAdapterService to work.
62 $file = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($file);
63 $theImage = $GLOBALS['TSFE']->tmpl->getFileName($file);
64 if (!$theImage) {
65 return array();
66 }
67 }
68 $fileConfiguration = $this->processFileConfiguration($fileConfiguration, $contentObject);
69 $maskArray = $fileConfiguration['m.'];
70 $maskImages = array();
71 // Must render mask images and include in hash-calculating - else we
72 // cannot be sure the filename is unique for the setup!
73 if (is_array($maskArray)) {
74 $maskImages['m_mask'] = $this->getImgResource($contentObject, $maskArray['mask'], $maskArray['mask.']);
75 $maskImages['m_bgImg'] = $this->getImgResource($contentObject, $maskArray['bgImg'], $maskArray['bgImg.']);
76 $maskImages['m_bottomImg'] = $this->getImgResource($contentObject, $maskArray['bottomImg'], $maskArray['bottomImg.']);
77 $maskImages['m_bottomImg_mask'] = $this->getImgResource($contentObject, $maskArray['bottomImg_mask'], $maskArray['bottomImg_mask.']);
78 }
79 // TODO use \TYPO3\CMS\Core\Resource\FileInterface here
80 if ($file instanceof \TYPO3\CMS\Core\Resource\FileReference) {
81 $hash = $file->getOriginalFile()->calculateChecksum();
82 } else {
83 $hash = \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5(($theImage . serialize($fileConfiguration)) . serialize($maskImages));
84 }
85 if (isset($GLOBALS['TSFE']->tmpl->fileCache[$hash])) {
86 return $GLOBALS['TSFE']->tmpl->fileCache[$hash];
87 }
88 /** @var $gifCreator tslib_gifbuilder */
89 $gifCreator = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tslib_gifbuilder');
90 $gifCreator->init();
91 if ($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']) {
92 $filename = basename($theImage);
93 // Remove extension
94 $filename = substr($filename, 0, strrpos($filename, '.'));
95 $tempFilePrefixLength = intval($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']);
96 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
97 /** @var $t3libCsInstance \TYPO3\CMS\Core\Charset\CharsetConverter */
98 $t3libCsInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
99 $filenamePrefix = $t3libCsInstance->substr('utf-8', $filename, 0, $tempFilePrefixLength);
100 } else {
101 // Strip everything non-ascii
102 $filename = preg_replace('/[^A-Za-z0-9_-]/', '', trim($filename));
103 $filenamePrefix = substr($filename, 0, $tempFilePrefixLength);
104 }
105 $gifCreator->filenamePrefix = $filenamePrefix . '_';
106 unset($filename);
107 }
108 if ($fileConfiguration['sample']) {
109 $gifCreator->scalecmd = '-sample';
110 $GLOBALS['TT']->setTSlogMessage('Sample option: Images are scaled with -sample.');
111 }
112 if ($fileConfiguration['alternativeTempPath'] && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['allowedTempPaths'], $fileConfiguration['alternativeTempPath'])) {
113 $gifCreator->tempPath = $fileConfiguration['alternativeTempPath'];
114 $GLOBALS['TT']->setTSlogMessage('Set alternativeTempPath: ' . $fileConfiguration['alternativeTempPath']);
115 }
116 if (!trim($fileConfiguration['ext'])) {
117 $fileConfiguration['ext'] = 'web';
118 }
119 $options = array();
120 if ($fileConfiguration['maxW']) {
121 $options['maxW'] = $fileConfiguration['maxW'];
122 }
123 if ($fileConfiguration['maxH']) {
124 $options['maxH'] = $fileConfiguration['maxH'];
125 }
126 if ($fileConfiguration['minW']) {
127 $options['minW'] = $fileConfiguration['minW'];
128 }
129 if ($fileConfiguration['minH']) {
130 $options['minH'] = $fileConfiguration['minH'];
131 }
132 if ($fileConfiguration['noScale']) {
133 $options['noScale'] = $fileConfiguration['noScale'];
134 }
135 $fileInformation = \TYPO3\CMS\Core\Utility\GeneralUtility::split_fileref($theImage);
136 $imgExt = strtolower($fileInformation['fileext']) == $gifCreator->gifExtension ? $gifCreator->gifExtension : 'jpg';
137 // If no mask is used or ImageMagick is disabled, processing is quite simple
138 if (!is_array($maskArray) || !$GLOBALS['TYPO3_CONF_VARS']['GFX']['im']) {
139 $fileConfiguration['params'] = $this->modifyImageMagickStripProfileParameters($fileConfiguration['params'], $fileConfiguration);
140 $GLOBALS['TSFE']->tmpl->fileCache[$hash] = $gifCreator->imageMagickConvert($theImage, $fileConfiguration['ext'], $fileConfiguration['width'], $fileConfiguration['height'], $fileConfiguration['params'], $fileConfiguration['frame'], $options);
141 if (($fileConfiguration['reduceColors'] || $imgExt === 'png' && !$gifCreator->png_truecolor) && is_file($GLOBALS['TSFE']->tmpl->fileCache[$hash][3])) {
142 $reduced = $gifCreator->IMreduceColors($GLOBALS['TSFE']->tmpl->fileCache[$hash][3], \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($fileConfiguration['reduceColors'], 256, $gifCreator->truecolorColors, 256));
143 if (is_file($reduced)) {
144 unlink($GLOBALS['TSFE']->tmpl->fileCache[$hash][3]);
145 rename($reduced, $GLOBALS['TSFE']->tmpl->fileCache[$hash][3]);
146 }
147 }
148 } else {
149 // Filename:
150 $fileDestination = (($gifCreator->tempPath . $hash) . '.') . $imgExt;
151 // Generate!
152 if (!file_exists($fileDestination)) {
153 $this->processMask($maskImages, $gifCreator, $theImage, $fileConfiguration, $options, $fileDestination);
154 }
155 // Finish off
156 if (($fileConfiguration['reduceColors'] || $imgExt === 'png' && !$gifCreator->png_truecolor) && is_file($fileDestination)) {
157 $reduced = $gifCreator->IMreduceColors($fileDestination, \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($fileConfiguration['reduceColors'], 256, $gifCreator->truecolorColors, 256));
158 if (is_file($reduced)) {
159 unlink($fileDestination);
160 rename($reduced, $fileDestination);
161 }
162 }
163 $GLOBALS['TSFE']->tmpl->fileCache[$hash] = $gifCreator->getImageDimensions($fileDestination);
164 }
165 $GLOBALS['TSFE']->tmpl->fileCache[$hash]['origFile'] = $theImage;
166 // This is needed by tslib_gifbuilder, in order for the setup-array to create a unique filename hash.
167 $GLOBALS['TSFE']->tmpl->fileCache[$hash]['origFile_mtime'] = @filemtime($theImage);
168 $GLOBALS['TSFE']->tmpl->fileCache[$hash]['fileCacheHash'] = $hash;
169 if ($file instanceof \TYPO3\CMS\Core\Resource\FileInterface && \TYPO3\CMS\Core\Utility\GeneralUtility::isAbsPath($GLOBALS['TSFE']->tmpl->fileCache[$hash][3])) {
170 $GLOBALS['TSFE']->tmpl->fileCache[$hash][3] = $file->getPublicUrl();
171 }
172 $imageResource = $GLOBALS['TSFE']->tmpl->fileCache[$hash];
173 return $imageResource;
174 }
175
176 /**
177 * Renders the mask configuration
178 *
179 * @param $maskImages
180 * @param $gifCreator
181 * @param $theImage
182 * @param $fileConfiguration
183 * @param $options
184 * @param $dest
185 */
186 protected function processMask($maskImages, $gifCreator, $theImage, $fileConfiguration, $options, $dest) {
187 $m_mask = $maskImages['m_mask'];
188 $m_bgImg = $maskImages['m_bgImg'];
189 if ($m_mask && $m_bgImg) {
190 $negate = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_negate_mask'] ? ' -negate' : '';
191 $temp_ext = 'png';
192 // If ImageMagick version 5+
193 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_gif']) {
194 $temp_ext = $gifCreator->gifExtension;
195 }
196 $tempFileInfo = $gifCreator->imageMagickConvert($theImage, $temp_ext, $fileConfiguration['width'], $fileConfiguration['height'], $fileConfiguration['params'], $fileConfiguration['frame'], $options);
197 if (is_array($tempFileInfo)) {
198 $m_bottomImg = $maskImages['m_bottomImg'];
199 if ($m_bottomImg) {
200 $m_bottomImg_mask = $maskImages['m_bottomImg_mask'];
201 }
202 // Scaling:
203 $tempScale = array();
204 $command = ((('-geometry ' . $tempFileInfo[0]) . 'x') . $tempFileInfo[1]) . '!';
205 $command = $this->modifyImageMagickStripProfileParameters($command, $fileConfiguration);
206 $tmpStr = $gifCreator->randomName();
207 // m_mask
208 $tempScale['m_mask'] = ($tmpStr . '_mask.') . $temp_ext;
209 $gifCreator->imageMagickExec($m_mask[3], $tempScale['m_mask'], $command . $negate);
210 // m_bgImg
211 $tempScale['m_bgImg'] = ($tmpStr . '_bgImg.') . trim($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_noloss']);
212 $gifCreator->imageMagickExec($m_bgImg[3], $tempScale['m_bgImg'], $command);
213 // m_bottomImg / m_bottomImg_mask
214 if ($m_bottomImg && $m_bottomImg_mask) {
215 $tempScale['m_bottomImg'] = ($tmpStr . '_bottomImg.') . $temp_ext;
216 $gifCreator->imageMagickExec($m_bottomImg[3], $tempScale['m_bottomImg'], $command);
217 $tempScale['m_bottomImg_mask'] = ($tmpStr . '_bottomImg_mask.') . $temp_ext;
218 $gifCreator->imageMagickExec($m_bottomImg_mask[3], $tempScale['m_bottomImg_mask'], $command . $negate);
219 // BEGIN combining:
220 // The image onto the background (including the mask here)
221 $gifCreator->combineExec($tempScale['m_bgImg'], $tempScale['m_bottomImg'], $tempScale['m_bottomImg_mask'], $tempScale['m_bgImg']);
222 }
223 // The image onto the background
224 $gifCreator->combineExec($tempScale['m_bgImg'], $tempFileInfo[3], $tempScale['m_mask'], $dest);
225 // Remove the temporary images
226 foreach ($tempScale as $file) {
227 if (@is_file($file)) {
228 unlink($file);
229 }
230 }
231 }
232 }
233 }
234
235 /**
236 * Cleans and sets-up the image-processing configuration array
237 *
238 * @param $fileConfiguration
239 * @param $contentObject
240 * @return array
241 */
242 protected function processFileConfiguration($fileConfiguration, $contentObject) {
243 $fileConfiguration['width'] = isset($fileConfiguration['width.']) ? $contentObject->stdWrap($fileConfiguration['width'], $fileConfiguration['width.']) : $fileConfiguration['width'];
244 $fileConfiguration['height'] = isset($fileConfiguration['height.']) ? $contentObject->stdWrap($fileConfiguration['height'], $fileConfiguration['height.']) : $fileConfiguration['height'];
245 $fileConfiguration['ext'] = isset($fileConfiguration['ext.']) ? $contentObject->stdWrap($fileConfiguration['ext'], $fileConfiguration['ext.']) : $fileConfiguration['ext'];
246 $fileConfiguration['maxW'] = isset($fileConfiguration['maxW.']) ? intval($contentObject->stdWrap($fileConfiguration['maxW'], $fileConfiguration['maxW.'])) : intval($fileConfiguration['maxW']);
247 $fileConfiguration['maxH'] = isset($fileConfiguration['maxH.']) ? intval($contentObject->stdWrap($fileConfiguration['maxH'], $fileConfiguration['maxH.'])) : intval($fileConfiguration['maxH']);
248 $fileConfiguration['minW'] = isset($fileConfiguration['minW.']) ? intval($contentObject->stdWrap($fileConfiguration['minW'], $fileConfiguration['minW.'])) : intval($fileConfiguration['minW']);
249 $fileConfiguration['minH'] = isset($fileConfiguration['minH.']) ? intval($contentObject->stdWrap($fileConfiguration['minH'], $fileConfiguration['minH.'])) : intval($fileConfiguration['minH']);
250 $fileConfiguration['noScale'] = isset($fileConfiguration['noScale.']) ? $contentObject->stdWrap($fileConfiguration['noScale'], $fileConfiguration['noScale.']) : $fileConfiguration['noScale'];
251 $fileConfiguration['params'] = isset($fileConfiguration['params.']) ? $contentObject->stdWrap($fileConfiguration['params'], $fileConfiguration['params.']) : $fileConfiguration['params'];
252 return $fileConfiguration;
253 }
254
255 /**
256 * Modifies the parameters for ImageMagick for stripping of profile information.
257 *
258 * @param string $parameters: The parameters to be modified (if required)
259 * @param array $configuration: The TypoScript configuration of [IMAGE].file
260 * @return string ImageMagick parameters
261 */
262 protected function modifyImageMagickStripProfileParameters($parameters, array $configuration) {
263 // Strips profile information of image to save some space:
264 if (isset($configuration['stripProfile'])) {
265 if ($configuration['stripProfile']) {
266 $parameters = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_stripProfileCommand'] . $parameters;
267 } else {
268 $parameters .= '###SkipStripProfile###';
269 }
270 }
271 return $parameters;
272 }
273
274 }
275
276
277 ?>