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