7d71827c225ad9da7f486bcf3b23f6b8b87d3dea
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Service / ImageService.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Service;
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\LinkHandling\LinkService;
18 use TYPO3\CMS\Core\Resource\File;
19 use TYPO3\CMS\Core\Resource\FileInterface;
20 use TYPO3\CMS\Core\Resource\FileReference;
21 use TYPO3\CMS\Core\Resource\ProcessedFile;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Core\Utility\MathUtility;
24
25 /**
26 * Service for processing images
27 */
28 class ImageService implements \TYPO3\CMS\Core\SingletonInterface
29 {
30 /**
31 * @var \TYPO3\CMS\Core\Resource\ResourceFactory
32 */
33 protected $resourceFactory;
34
35 /**
36 * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
37 */
38 protected $environmentService;
39
40 /**
41 * @param \TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory
42 */
43 public function injectResourceFactory(\TYPO3\CMS\Core\Resource\ResourceFactory $resourceFactory)
44 {
45 $this->resourceFactory = $resourceFactory;
46 }
47
48 /**
49 * @param \TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService
50 */
51 public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService)
52 {
53 $this->environmentService = $environmentService;
54 }
55
56 /**
57 * Create a processed file
58 *
59 * @param FileInterface|FileReference $image
60 * @param array $processingInstructions
61 * @return ProcessedFile
62 * @api
63 */
64 public function applyProcessingInstructions($image, $processingInstructions)
65 {
66 if (is_callable([$image, 'getOriginalFile'])) {
67 // Get the original file from the file reference
68 $image = $image->getOriginalFile();
69 }
70
71 $processedImage = $image->process(ProcessedFile::CONTEXT_IMAGECROPSCALEMASK, $processingInstructions);
72 $this->setCompatibilityValues($processedImage);
73
74 return $processedImage;
75 }
76
77 /**
78 * Get public url of image depending on the environment
79 *
80 * @param FileInterface $image
81 * @param bool|FALSE $absolute Force absolute URL
82 * @return string
83 * @api
84 */
85 public function getImageUri(FileInterface $image, $absolute = false)
86 {
87 $imageUrl = $image->getPublicUrl();
88 $parsedUrl = parse_url($imageUrl);
89 // no prefix in case of an already fully qualified URL
90 if (isset($parsedUrl['host'])) {
91 $uriPrefix = '';
92 } elseif ($this->environmentService->isEnvironmentInFrontendMode()) {
93 $uriPrefix = $GLOBALS['TSFE']->absRefPrefix;
94 } else {
95 $uriPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
96 }
97
98 // Prevent double / when concatenating $uriPrefix and $imageUrl
99 if ($imageUrl[0] === '/') {
100 $uriPrefix = rtrim($uriPrefix, '/');
101 }
102
103 if ($absolute) {
104 // If full URL has no scheme we add the same scheme as used by the site
105 // so we have an absolute URL also usable outside of browser scope (e.g. in an email message)
106 if (isset($parsedUrl['host']) && !isset($parsedUrl['scheme'])) {
107 $uriPrefix = (GeneralUtility::getIndpEnv('TYPO3_SSL') ? 'https:' : 'http:') . $uriPrefix;
108 }
109 return GeneralUtility::locationHeaderUrl($uriPrefix . $imageUrl);
110 } else {
111 return $uriPrefix . $imageUrl;
112 }
113 }
114
115 /**
116 * Get File or FileReference object
117 *
118 * This method is a factory and compatibility method that does not belong to
119 * this service, but is put here for pragmatic reasons for the time being.
120 * It should be removed once we do not support string sources for images anymore.
121 *
122 * @param string $src
123 * @param mixed $image
124 * @param bool $treatIdAsReference
125 * @return FileInterface|FileReference
126 * @throws \UnexpectedValueException
127 * @internal
128 */
129 public function getImage($src, $image, $treatIdAsReference)
130 {
131 if (is_null($image)) {
132 $image = $this->getImageFromSourceString($src, $treatIdAsReference);
133 } elseif (is_callable([$image, 'getOriginalResource'])) {
134 // We have a domain model, so we need to fetch the FAL resource object from there
135 $image = $image->getOriginalResource();
136 }
137
138 if (!($image instanceof File || $image instanceof FileReference)) {
139 throw new \UnexpectedValueException('Supplied file object type ' . get_class($image) . ' for ' . $src . ' must be File or FileReference.', 1382687163);
140 }
141
142 return $image;
143 }
144
145 /**
146 * Get File or FileReference object by src
147 *
148 * @param string $src
149 * @param bool $treatIdAsReference
150 * @return FileInterface|FileReference|\TYPO3\CMS\Core\Resource\Folder
151 */
152 protected function getImageFromSourceString($src, $treatIdAsReference)
153 {
154 if ($this->environmentService->isEnvironmentInBackendMode() && substr($src, 0, 3) === '../') {
155 $src = substr($src, 3);
156 }
157 if (MathUtility::canBeInterpretedAsInteger($src)) {
158 if ($treatIdAsReference) {
159 $image = $this->resourceFactory->getFileReferenceObject($src);
160 } else {
161 $image = $this->resourceFactory->getFileObject($src);
162 }
163 } elseif (strpos($src, 't3://file') === 0) {
164 // We have a t3://file link to a file in FAL
165 $linkService = GeneralUtility::makeInstance(LinkService::class);
166 $data = $linkService->resolveByStringRepresentation($src);
167 $image = $data['file'];
168 } else {
169 // We have a combined identifier or legacy (storage 0) path
170 $image = $this->resourceFactory->retrieveFileOrFolderObject($src);
171 }
172 return $image;
173 }
174
175 /**
176 * Set compatibility values to frontend controller object
177 * in case we are in frontend environment.
178 *
179 * @param ProcessedFile $processedImage
180 */
181 protected function setCompatibilityValues(ProcessedFile $processedImage)
182 {
183 if ($this->environmentService->isEnvironmentInFrontendMode()) {
184 $imageInfo = $this->getCompatibilityImageResourceValues($processedImage);
185 $GLOBALS['TSFE']->lastImageInfo = $imageInfo;
186 $GLOBALS['TSFE']->imagesOnPage[] = $imageInfo[3];
187 }
188 }
189
190 /**
191 * Calculates the compatibility values
192 * This is duplicate code taken from ContentObjectRenderer::getImgResource()
193 * Ideally we should get rid of this code in both places.
194 *
195 * @param ProcessedFile $processedImage
196 * @return array
197 */
198 protected function getCompatibilityImageResourceValues(ProcessedFile $processedImage)
199 {
200 $hash = $processedImage->calculateChecksum();
201 if (isset($GLOBALS['TSFE']->tmpl->fileCache[$hash])) {
202 $compatibilityImageResourceValues = $GLOBALS['TSFE']->tmpl->fileCache[$hash];
203 } else {
204 $compatibilityImageResourceValues = [
205 0 => $processedImage->getProperty('width'),
206 1 => $processedImage->getProperty('height'),
207 2 => $processedImage->getExtension(),
208 3 => $processedImage->getPublicUrl(),
209 'origFile' => $processedImage->getOriginalFile()->getPublicUrl(),
210 'origFile_mtime' => $processedImage->getOriginalFile()->getModificationTime(),
211 // This is needed by \TYPO3\CMS\Frontend\Imaging\GifBuilder,
212 // in order for the setup-array to create a unique filename hash.
213 'originalFile' => $processedImage->getOriginalFile(),
214 'processedFile' => $processedImage,
215 'fileCacheHash' => $hash
216 ];
217 }
218 return $compatibilityImageResourceValues;
219 }
220 }