‪TYPO3CMS  11.5
ImageContentObject.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
23 
28 {
35  public function ‪render($conf = [])
36  {
37  if (!empty($conf['if.']) && !$this->cObj->checkIf($conf['if.'])) {
38  return '';
39  }
40 
41  $theValue = $this->‪cImage($conf['file'] ?? '', $conf);
42  if (isset($conf['stdWrap.'])) {
43  $theValue = $this->cObj->stdWrap($theValue, $conf['stdWrap.']);
44  }
45  return $theValue;
46  }
47 
56  protected function ‪cImage($file, $conf)
57  {
58  $tsfe = $this->‪getTypoScriptFrontendController();
59  $info = $this->cObj->getImgResource($file, $conf['file.'] ?? []);
60  if (!is_array($info)) {
61  return '';
62  }
63  // $info['originalFile'] will be set, when the file is processed by FAL.
64  // In that case the URL is final and we must not add a prefix
65  if (!isset($info['originalFile']) && is_file(‪Environment::getPublicPath() . '/' . ($info['3'] ?? ''))) {
66  $source = $tsfe->absRefPrefix . str_replace('%2F', '/', rawurlencode($info['3'] ?? ''));
67  } else {
68  $source = $info[3] ?? '';
69  }
70  // Remove file objects for AssetCollector, as it only allows to store scalar values
71  $infoOriginalFile = $info['originalFile'] ?? null;
72  unset($info['originalFile'], $info['processedFile']);
73  GeneralUtility::makeInstance(AssetCollector::class)->addMedia(
74  $source,
75  $info
76  );
77 
78  $layoutKey = (string)$this->cObj->stdWrapValue('layoutKey', $conf ?? []);
79  $imageTagTemplate = $this->‪getImageTagTemplate($layoutKey, $conf);
80  $sourceCollection = $this->‪getImageSourceCollection($layoutKey, $conf, $file);
81 
82  $altParam = $this->‪getAltParam($conf);
83  $params = $this->cObj->stdWrapValue('params', $conf ?? []);
84  if ($params !== '' && $params[0] !== ' ') {
85  $params = ' ' . $params;
86  }
87 
88  $imageTagValues = [
89  'width' => (int)$info[0],
90  'height' => (int)$info[1],
91  'src' => htmlspecialchars($source),
92  'params' => $params,
93  'altParams' => $altParam,
94  'border' => $this->‪getBorderAttr(' border="' . (int)($conf['border'] ?? 0) . '"'),
95  'sourceCollection' => $sourceCollection,
96  'selfClosingTagSlash' => !empty($tsfe->xhtmlDoctype) ? ' /' : '',
97  ];
98 
99  $markerTemplateEngine = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
100  $theValue = $markerTemplateEngine->substituteMarkerArray($imageTagTemplate, $imageTagValues, '###|###', true, true);
101 
102  $linkWrap = (string)$this->cObj->stdWrapValue('linkWrap', $conf ?? []);
103  if ($linkWrap !== '') {
104  $theValue = $this->‪linkWrap((string)$theValue, $linkWrap);
105  } elseif ($conf['imageLinkWrap'] ?? false) {
106  $originalFile = !empty($infoOriginalFile) ? $infoOriginalFile : urldecode($info['origFile']);
107  $theValue = $this->cObj->imageLinkWrap($theValue, $originalFile, $conf['imageLinkWrap.']);
108  }
109  $wrap = $this->cObj->stdWrapValue('wrap', $conf ?? []);
110  if ((string)$wrap !== '') {
111  $theValue = $this->cObj->wrap($theValue, $conf['wrap']);
112  }
113  return $theValue;
114  }
115 
123  protected function ‪getBorderAttr($borderAttr)
124  {
125  $tsfe = $this->‪getTypoScriptFrontendController();
126  $docType = $tsfe->xhtmlDoctype;
127  if (
128  $docType !== 'xhtml_strict' && $docType !== 'xhtml_11'
129  && ($tsfe->config['config']['doctype'] ?? '') !== 'html5'
130  && !($tsfe->config['config']['disableImgBorderAttr'] ?? false)
131  ) {
132  return $borderAttr;
133  }
134  return '';
135  }
136 
145  protected function ‪getImageTagTemplate($layoutKey, $conf): string
146  {
147  if ($layoutKey && isset($conf['layout.']) && isset($conf['layout.'][$layoutKey . '.'])) {
148  return $this->cObj->stdWrapValue('element', $conf['layout.'][$layoutKey . '.']);
149  }
150  return '<img src="###SRC###" width="###WIDTH###" height="###HEIGHT###" ###PARAMS### ###ALTPARAMS### ###BORDER######SELFCLOSINGTAGSLASH###>';
151  }
152 
162  protected function ‪getImageSourceCollection($layoutKey, $conf, $file)
163  {
164  $sourceCollection = '';
165  if ($layoutKey
166  && isset($conf['sourceCollection.']) && $conf['sourceCollection.']
167  && (
168  isset($conf['layout.'][$layoutKey . '.']['source']) && $conf['layout.'][$layoutKey . '.']['source']
169  || isset($conf['layout.'][$layoutKey . '.']['source.']) && $conf['layout.'][$layoutKey . '.']['source.']
170  )
171  ) {
172  // find active sourceCollection
173  $activeSourceCollections = [];
174  foreach ($conf['sourceCollection.'] as $sourceCollectionKey => $sourceCollectionConfiguration) {
175  if (substr($sourceCollectionKey, -1) === '.') {
176  if (empty($sourceCollectionConfiguration['if.']) || $this->cObj->checkIf($sourceCollectionConfiguration['if.'])) {
177  $activeSourceCollections[] = $sourceCollectionConfiguration;
178  }
179  }
180  }
181 
182  // apply option split to configurations
183  $tsfe = $this->‪getTypoScriptFrontendController();
184  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
185  $srcLayoutOptionSplitted = $typoScriptService->explodeConfigurationForOptionSplit((array)$conf['layout.'][$layoutKey . '.'], count($activeSourceCollections));
186 
187  // render sources
188  foreach ($activeSourceCollections as $key => $sourceConfiguration) {
189  $sourceLayout = $this->cObj->stdWrapValue('source', $srcLayoutOptionSplitted[$key] ?? []);
190 
191  $sourceRenderConfiguration = [
192  'file' => $file,
193  'file.' => $conf['file.'] ?? null,
194  ];
195 
196  $imageQuality = $this->cObj->stdWrapValue('quality', $sourceConfiguration ?? []);
197  if ($imageQuality) {
198  $sourceRenderConfiguration['file.']['params'] = '-quality ' . (int)$imageQuality;
199  }
200 
201  $pixelDensity = (int)$this->cObj->stdWrapValue('pixelDensity', $sourceConfiguration, 1);
202  $dimensionKeys = ['width', 'height', 'maxW', 'minW', 'maxH', 'minH', 'maxWidth', 'maxHeight', 'XY'];
203  foreach ($dimensionKeys as $dimensionKey) {
204  $dimension = (string)$this->cObj->stdWrapValue($dimensionKey, $sourceConfiguration);
205  if ($dimension === '') {
206  $dimension = (string)$this->cObj->stdWrapValue($dimensionKey, $conf['file.'] ?? []);
207  }
208  if ($dimension !== '') {
209  if (str_contains($dimension, 'c') && ($dimensionKey === 'width' || $dimensionKey === 'height')) {
210  $dimensionParts = explode('c', $dimension, 2);
211  $dimension = ((int)$dimensionParts[0] * $pixelDensity) . 'c';
212  if ($dimensionParts[1]) {
213  $dimension .= $dimensionParts[1];
214  }
215  } elseif ($dimensionKey === 'XY') {
216  $dimensionParts = ‪GeneralUtility::intExplode(',', $dimension, false, 2);
217  $dimension = $dimensionParts[0] * $pixelDensity;
218  if ($dimensionParts[1]) {
219  $dimension .= ',' . $dimensionParts[1] * $pixelDensity;
220  }
221  } else {
222  $dimension = (int)$dimension * $pixelDensity;
223  }
224  $sourceRenderConfiguration['file.'][$dimensionKey] = $dimension;
225  // Remove the stdWrap properties for dimension as they have been processed already above.
226  unset($sourceRenderConfiguration['file.'][$dimensionKey . '.']);
227  }
228  }
229  $sourceInfo = $this->cObj->getImgResource($sourceRenderConfiguration['file'], $sourceRenderConfiguration['file.']);
230  if ($sourceInfo) {
231  $sourceConfiguration['width'] = $sourceInfo[0];
232  $sourceConfiguration['height'] = $sourceInfo[1];
233 
234  $urlPrefix = '';
235 
236  // Prepend 'absRefPrefix' to file path only if file was not processed
237  // by FAL, e.g. GIFBUILDER
238  if (!isset($sourceInfo['originalFile']) && is_file(‪Environment::getPublicPath() . '/' . $sourceInfo['3'])) {
239  $urlPrefix = $tsfe->absRefPrefix;
240  }
241 
242  $sourceConfiguration['src'] = htmlspecialchars($urlPrefix . $sourceInfo[3]);
243  $sourceConfiguration['selfClosingTagSlash'] = !empty($tsfe->xhtmlDoctype) ? ' /' : '';
244 
245  $markerTemplateEngine = GeneralUtility::makeInstance(MarkerBasedTemplateService::class);
246  $oneSourceCollection = $markerTemplateEngine->substituteMarkerArray($sourceLayout, $sourceConfiguration, '###|###', true, true);
247 
248  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_content.php']['getImageSourceCollection'] ?? [] as $className) {
249  $hookObject = GeneralUtility::makeInstance($className);
250  if (!$hookObject instanceof ‪ContentObjectOneSourceCollectionHookInterface) {
251  throw new \UnexpectedValueException(
252  '$hookObject must implement interface ' . ContentObjectOneSourceCollectionHookInterface::class,
253  1380017853
254  );
255  }
256  $oneSourceCollection = $hookObject->getOneSourceCollection((array)$sourceRenderConfiguration, (array)$sourceConfiguration, $oneSourceCollection, $this->cObj);
257  }
258 
259  $sourceCollection .= $oneSourceCollection;
260  }
261  }
262  }
263  return $sourceCollection;
264  }
265 
273  protected function ‪linkWrap(string $content, string $wrap): string
274  {
275  $wrapArr = explode('|', $wrap);
276  if (preg_match('/\\{([0-9]*)\\}/', $wrapArr[0], $reg)) {
277  $uid = $this->‪getTypoScriptFrontendController()->tmpl->rootLine[$reg[1]]['uid'] ?? null;
278  if ($uid) {
279  $wrapArr[0] = str_replace($reg[0], $uid, $wrapArr[0]);
280  }
281  }
282  return trim($wrapArr[0] ?? '') . $content . trim($wrapArr[1] ?? '');
283  }
284 
294  public function ‪getAltParam($conf, $longDesc = true)
295  {
296  $altText = trim((string)$this->cObj->stdWrapValue('altText', $conf ?? []));
297  $titleText = trim((string)$this->cObj->stdWrapValue('titleText', $conf ?? []));
298  $frontendController = $this->‪hasTypoScriptFrontendController()
300  : null;
301  if (isset($conf['longdescURL.']) && ($frontendController->config['config']['doctype'] ?? '') !== 'html5') {
302  $longDescUrl = $this->cObj->typoLink_URL($conf['longdescURL.']);
303  } else {
304  $longDescUrl = trim($conf['longdescURL'] ?? '');
305  }
306  $longDescUrl = strip_tags($longDescUrl);
307 
308  // "alt":
309  $altParam = ' alt="' . htmlspecialchars($altText) . '"';
310  // "title":
311  $emptyTitleHandling = $this->cObj->stdWrapValue('emptyTitleHandling', $conf ?? []);
312  // Choices: 'keepEmpty' | 'useAlt' | 'removeAttr'
313  if ($titleText || $emptyTitleHandling === 'keepEmpty') {
314  $altParam .= ' title="' . htmlspecialchars($titleText) . '"';
315  } elseif (!$titleText && $emptyTitleHandling === 'useAlt') {
316  $altParam .= ' title="' . htmlspecialchars($altText) . '"';
317  }
318  // "longDesc" URL
319  if ($longDesc && !empty($longDescUrl)) {
320  $altParam .= ' longdesc="' . htmlspecialchars($longDescUrl) . '"';
321  }
322  return $altParam;
323  }
324 }
‪TYPO3\CMS\Core\Page\AssetCollector
Definition: AssetCollector.php:42
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\linkWrap
‪linkWrap(string $content, string $wrap)
Definition: ImageContentObject.php:273
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:206
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject
Definition: ImageContentObject.php:28
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\getBorderAttr
‪string getBorderAttr($borderAttr)
Definition: ImageContentObject.php:123
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\cImage
‪string cImage($file, $conf)
Definition: ImageContentObject.php:56
‪TYPO3\CMS\Frontend\ContentObject
Definition: AbstractContentObject.php:16
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\render
‪string render($conf=[])
Definition: ImageContentObject.php:35
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject\hasTypoScriptFrontendController
‪hasTypoScriptFrontendController()
Definition: AbstractContentObject.php:78
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject\getTypoScriptFrontendController
‪TypoScriptFrontendController getTypoScriptFrontendController()
Definition: AbstractContentObject.php:86
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\getImageSourceCollection
‪string getImageSourceCollection($layoutKey, $conf, $file)
Definition: ImageContentObject.php:162
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\getAltParam
‪string getAltParam($conf, $longDesc=true)
Definition: ImageContentObject.php:294
‪TYPO3\CMS\Frontend\ContentObject\ImageContentObject\getImageTagTemplate
‪string getImageTagTemplate($layoutKey, $conf)
Definition: ImageContentObject.php:145
‪TYPO3\CMS\Frontend\ContentObject\AbstractContentObject
Definition: AbstractContentObject.php:29
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:25
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectOneSourceCollectionHookInterface
Definition: ContentObjectOneSourceCollectionHookInterface.php:22
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:43
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:927
‪TYPO3\CMS\Core\Service\MarkerBasedTemplateService
Definition: MarkerBasedTemplateService.php:27
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50