f6e38f3e167e8b317defae70c052af516b02fc44
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Processing / LocalCropScaleMaskHelper.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Processing;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012-2013 Andreas Wolf <andreas.wolf@typo3.org>
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
30 use \TYPO3\CMS\Core\Resource, \TYPO3\CMS\Core\Utility;
31
32 /**
33 * Helper class to locally perform a crop/scale/mask task with the TYPO3 image processing classes.
34 */
35 class LocalCropScaleMaskHelper {
36 /**
37 * @var LocalImageProcessor
38 */
39 protected $processor;
40
41
42 /**
43 * @param LocalImageProcessor $processor
44 */
45 public function __construct(LocalImageProcessor $processor) {
46 $this->processor = $processor;
47 }
48
49 /**
50 * This method actually does the processing of files locally
51 *
52 * Takes the original file (for remote storages this will be fetched from the remote server),
53 * does the IM magic on the local server by creating a temporary typo3temp/ file,
54 * copies the typo3temp/ file to the processing folder of the target storage and
55 * removes the typo3temp/ file.
56 *
57 * @param TaskInterface $task
58 * @return array
59 */
60 public function process(TaskInterface $task) {
61 $result = NULL;
62 $targetFile = $task->getTargetFile();
63 $sourceFile = $task->getSourceFile();
64
65 $originalFileName = $sourceFile->getForLocalProcessing(FALSE);
66 /** @var $gifBuilder \TYPO3\CMS\Frontend\Imaging\GifBuilder */
67 $gifBuilder = Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Imaging\\GifBuilder');
68 $gifBuilder->init();
69
70 $configuration = $targetFile->getProcessingConfiguration();
71 $configuration['additionalParameters'] = $this->modifyImageMagickStripProfileParameters($configuration['additionalParameters'], $configuration);
72
73 if (empty($configuration['fileExtension'])) {
74 $configuration['fileExtension'] = $task->getTargetFileExtension();
75 }
76
77 $options = $this->getConfigurationForImageCropScaleMask($targetFile, $gifBuilder);
78
79 // Normal situation (no masking)
80 if (!(is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'])) {
81 // the result info is an array with 0=width,1=height,2=extension,3=filename
82 $result = $gifBuilder->imageMagickConvert(
83 $originalFileName,
84 $configuration['fileExtension'],
85 $configuration['width'],
86 $configuration['height'],
87 $configuration['additionalParameters'],
88 $configuration['frame'],
89 $options
90 );
91 } else {
92 $targetFileName = $this->getFilenameForImageCropScaleMask($task);
93 $temporaryFileName = $gifBuilder->tempPath . $targetFileName;
94 $maskImage = $configuration['maskImages']['maskImage'];
95 $maskBackgroundImage = $configuration['maskImages']['backgroundImage'];
96 if ($maskImage instanceof Resource\FileInterface && $maskBackgroundImage instanceof Resource\FileInterface) {
97 $negate = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_negate_mask'] ? ' -negate' : '';
98 $temporaryExtension = 'png';
99 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_gif']) {
100 // If ImageMagick version 5+
101 $temporaryExtension = $gifBuilder->gifExtension;
102 }
103 $tempFileInfo = $gifBuilder->imageMagickConvert(
104 $originalFileName,
105 $temporaryExtension,
106 $configuration['width'],
107 $configuration['height'],
108 $configuration['additionalParameters'],
109 $configuration['frame'],
110 $options
111 );
112 if (is_array($tempFileInfo)) {
113 $maskBottomImage = $configuration['maskImages']['maskBottomImage'];
114 if ($maskBottomImage instanceof $maskBottomImage) {
115 $maskBottomImageMask = $configuration['maskImages']['maskBottomImageMask'];
116 } else {
117 $maskBottomImageMask = NULL;
118 }
119
120 // Scaling: ****
121 $tempScale = array();
122 $command = '-geometry ' . $tempFileInfo[0] . 'x' . $tempFileInfo[1] . '!';
123 $command = $this->modifyImageMagickStripProfileParameters($command, $configuration);
124 $tmpStr = $gifBuilder->randomName();
125 // m_mask
126 $tempScale['m_mask'] = $tmpStr . '_mask.' . $temporaryExtension;
127 $gifBuilder->imageMagickExec($maskImage->getForLocalProcessing(TRUE), $tempScale['m_mask'], $command . $negate);
128 // m_bgImg
129 $tempScale['m_bgImg'] = $tmpStr . '_bgImg.' . trim($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_noloss']);
130 $gifBuilder->imageMagickExec($maskBackgroundImage->getForLocalProcessing(), $tempScale['m_bgImg'], $command);
131 // m_bottomImg / m_bottomImg_mask
132 if ($maskBottomImage instanceof Resource\FileInterface && $maskBottomImageMask instanceof Resource\FileInterface) {
133 $tempScale['m_bottomImg'] = $tmpStr . '_bottomImg.' . $temporaryExtension;
134 $gifBuilder->imageMagickExec($maskBottomImage->getForLocalProcessing(), $tempScale['m_bottomImg'], $command);
135 $tempScale['m_bottomImg_mask'] = ($tmpStr . '_bottomImg_mask.') . $temporaryExtension;
136 $gifBuilder->imageMagickExec($maskBottomImageMask->getForLocalProcessing(), $tempScale['m_bottomImg_mask'], $command . $negate);
137 // BEGIN combining:
138 // The image onto the background
139 $gifBuilder->combineExec($tempScale['m_bgImg'], $tempScale['m_bottomImg'], $tempScale['m_bottomImg_mask'], $tempScale['m_bgImg']);
140 }
141 // The image onto the background
142 $gifBuilder->combineExec($tempScale['m_bgImg'], $tempFileInfo[3], $tempScale['m_mask'], $temporaryFileName);
143 // Unlink the temp-images...
144 foreach ($tempScale as $tempFile) {
145 if (@is_file($tempFile)) {
146 unlink($tempFile);
147 }
148 }
149 }
150 $result = $tempFileInfo;
151 }
152 }
153 // check if the processing really generated a new file
154 if ($result !== NULL) {
155 if ($result[3] !== $originalFileName) {
156 $result = array(
157 'width' => $result[0],
158 'height' => $result[1],
159 'filePath' => $result[3],
160 );
161 } else {
162 // No file was generated
163 $result = NULL;
164 }
165 }
166
167 return $result;
168 }
169
170 /**
171 * @param Resource\ProcessedFile $processedFile
172 * @param \TYPO3\CMS\Frontend\Imaging\GifBuilder $gifBuilder
173 *
174 * @return array
175 */
176 protected function getConfigurationForImageCropScaleMask(Resource\ProcessedFile $processedFile, \TYPO3\CMS\Frontend\Imaging\GifBuilder $gifBuilder) {
177 $configuration = $processedFile->getProcessingConfiguration();
178
179 if ($configuration['useSample']) {
180 $gifBuilder->scalecmd = '-sample';
181 }
182 $options = array();
183 if ($configuration['maxWidth']) {
184 $options['maxW'] = $configuration['maxWidth'];
185 }
186 if ($configuration['maxHeight']) {
187 $options['maxH'] = $configuration['maxHeight'];
188 }
189 if ($configuration['minWidth']) {
190 $options['minW'] = $configuration['minWidth'];
191 }
192 if ($configuration['minHeight']) {
193 $options['minH'] = $configuration['minHeight'];
194 }
195
196 $options['noScale'] = $configuration['noScale'];
197
198 return $options;
199 }
200
201 /**
202 * Returns the filename for a cropped/scaled/masked file.
203 *
204 * @param TaskInterface $task
205 * @return string
206 */
207 protected function getFilenameForImageCropScaleMask(TaskInterface $task) {
208
209 $configuration = $task->getTargetFile()->getProcessingConfiguration();
210 $targetFileExtension = $task->getSourceFile()->getExtension();
211 $processedFileExtension = $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif';
212 if (is_array($configuration['maskImages']) && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && $task->getSourceFile()->getExtension() != $processedFileExtension) {
213 $targetFileExtension = 'jpg';
214 } elseif ($configuration['fileExtension']) {
215 $targetFileExtension = $configuration['fileExtension'];
216 }
217
218 return $task->getTargetFile()->generateProcessedFileNameWithoutExtension() . '.' . ltrim(trim($targetFileExtension), '.');
219 }
220
221 /**
222 * Modifies the parameters for ImageMagick for stripping of profile information.
223 *
224 * @param string $parameters The parameters to be modified (if required)
225 * @param array $configuration The TypoScript configuration of [IMAGE].file
226 * @return string
227 */
228 protected function modifyImageMagickStripProfileParameters($parameters, array $configuration) {
229 // Strips profile information of image to save some space:
230 if (isset($configuration['stripProfile'])) {
231 if ($configuration['stripProfile']) {
232 $parameters = $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_stripProfileCommand'] . $parameters;
233 } else {
234 $parameters .= '###SkipStripProfile###';
235 }
236 }
237 return $parameters;
238 }
239 }
240
241 ?>