‪TYPO3CMS  10.4
GifBuilder.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 
32 
56 {
62  public ‪$combinedTextStrings = [];
63 
69  public ‪$combinedFileNames = [];
70 
76  public ‪$data = [];
77 
81  public ‪$objBB = [];
82 
86  public ‪$myClassName = 'gifbuilder';
87 
91  public ‪$charRangeMap = [];
92 
96  public ‪$XY = [];
97 
101  public ‪$cObj;
102 
106  public ‪$defaultWorkArea = [];
107 
117  public function ‪start($conf, ‪$data)
118  {
119  if (is_array($conf)) {
120  $this->setup = $conf;
121  $this->data = ‪$data;
122  $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
123  $this->cObj->start($this->data);
124  // Hook preprocess gifbuilder conf
125  // Added by Julle for 3.8.0
126  //
127  // Let's you pre-process the gifbuilder configuration. for
128  // example you can split a string up into lines and render each
129  // line as TEXT obj, see extension julle_gifbconf
130  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] ?? [] as $_funcRef) {
131  $_params = ‪$this->setup;
132  $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
133  $this->setup = GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
134  }
135  // Initializing global Char Range Map
136  $this->charRangeMap = [];
137  if (is_array(‪$GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) {
138  foreach (‪$GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) {
139  if (is_array($cRMcfg)) {
140  // Initializing:
141  $cRMkey = ‪$GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey, 0, -1)];
142  $this->charRangeMap[$cRMkey] = [];
143  $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.'];
144  $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey, 0, -1);
145  $this->charRangeMap[$cRMkey]['multiplicator'] = (double)$cRMcfg['fontSizeMultiplicator'];
146  $this->charRangeMap[$cRMkey]['pixelSpace'] = (int)$cRMcfg['pixelSpaceFontSizeRef'];
147  }
148  }
149  }
150  // Getting sorted list of TypoScript keys from setup.
151  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($this->setup);
152  // Setting the background color, passing it through stdWrap
153  if ($conf['backColor.'] || $conf['backColor']) {
154  $this->setup['backColor'] = isset($this->setup['backColor.']) ? trim($this->cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])) : $this->setup['backColor'];
155  }
156  if (!$this->setup['backColor']) {
157  $this->setup['backColor'] = 'white';
158  }
159  if ($conf['transparentColor.'] || $conf['transparentColor']) {
160  $this->setup['transparentColor_array'] = isset($this->setup['transparentColor.']) ? explode('|', trim($this->cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))) : explode('|', trim($this->setup['transparentColor']));
161  }
162  if (isset($this->setup['transparentBackground.'])) {
163  $this->setup['transparentBackground'] = $this->cObj->stdWrap($this->setup['transparentBackground'], $this->setup['transparentBackground.']);
164  }
165  if (isset($this->setup['reduceColors.'])) {
166  $this->setup['reduceColors'] = $this->cObj->stdWrap($this->setup['reduceColors'], $this->setup['reduceColors.']);
167  }
168  // Set default dimensions
169  if (isset($this->setup['XY.'])) {
170  $this->setup['XY'] = $this->cObj->stdWrap($this->setup['XY'], $this->setup['XY.']);
171  }
172  if (!$this->setup['XY']) {
173  $this->setup['XY'] = '120,50';
174  }
175  // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared.
176  // The Bounding Box for the objects is stored in an array
177  foreach ($sKeyArray as $theKey) {
178  $theValue = $this->setup[$theKey];
179  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
180  // Swipes through TEXT and IMAGE-objects
181  switch ($theValue) {
182  case 'TEXT':
183  if ($this->setup[$theKey . '.'] = $this->‪checkTextObj($conf)) {
184  // Adjust font width if max size is set:
185  $maxWidth = isset($this->setup[$theKey . '.']['maxWidth.']) ? $this->cObj->stdWrap($this->setup[$theKey . '.']['maxWidth'], $this->setup[$theKey . '.']['maxWidth.']) : $this->setup[$theKey . '.']['maxWidth'];
186  if ($maxWidth) {
187  $this->setup[$theKey . '.']['fontSize'] = $this->‪fontResize($this->setup[$theKey . '.']);
188  }
189  // Calculate bounding box:
190  $txtInfo = $this->‪calcBBox($this->setup[$theKey . '.']);
191  $this->setup[$theKey . '.']['BBOX'] = $txtInfo;
192  $this->objBB[$theKey] = $txtInfo;
193  $this->setup[$theKey . '.']['imgMap'] = 0;
194  }
195  break;
196  case 'IMAGE':
197  $fileInfo = $this->‪getResource($conf['file'], $conf['file.']);
198  if ($fileInfo) {
199  $this->combinedFileNames[] = preg_replace('/\\.[[:alnum:]]+$/', '', ‪PathUtility::basename($fileInfo[3]));
200  if ($fileInfo['processedFile'] instanceof ‪ProcessedFile) {
201  // Use processed file, if a FAL file has been processed by GIFBUILDER (e.g. scaled/cropped)
202  $this->setup[$theKey . '.']['file'] = $fileInfo['processedFile']->getForLocalProcessing(false);
203  } elseif (!isset($fileInfo['origFile']) && $fileInfo['originalFile'] instanceof ‪File) {
204  // Use FAL file with getForLocalProcessing to circumvent problems with umlauts, if it is a FAL file (origFile not set)
206  $originalFile = $fileInfo['originalFile'];
207  $this->setup[$theKey . '.']['file'] = $originalFile->getForLocalProcessing(false);
208  } else {
209  // Use normal path from fileInfo if it is a non-FAL file (even non-FAL files have originalFile set, but only non-FAL files have origFile set)
210  $this->setup[$theKey . '.']['file'] = $fileInfo[3];
211  }
212 
213  // only pass necessary parts of fileInfo further down, to not incorporate facts as
214  // CropScaleMask runs in this request, that may not occur in subsequent calls and change
215  // the md5 of the generated file name
216  $essentialFileInfo = $fileInfo;
217  unset($essentialFileInfo['originalFile'], $essentialFileInfo['processedFile']);
218 
219  $this->setup[$theKey . '.']['BBOX'] = $essentialFileInfo;
220  $this->objBB[$theKey] = $essentialFileInfo;
221  if ($conf['mask']) {
222  $maskInfo = $this->‪getResource($conf['mask'], $conf['mask.']);
223  if ($maskInfo) {
224  // the same selection criteria as regarding fileInfo above apply here
225  if ($maskInfo['processedFile'] instanceof ‪ProcessedFile) {
226  $this->setup[$theKey . '.']['mask'] = $maskInfo['processedFile']->getForLocalProcessing(false);
227  } elseif (!isset($maskInfo['origFile']) && $maskInfo['originalFile'] instanceof ‪File) {
229  $originalFile = $maskInfo['originalFile'];
230  $this->setup[$theKey . '.']['mask'] = $originalFile->getForLocalProcessing(false);
231  } else {
232  $this->setup[$theKey . '.']['mask'] = $maskInfo[3];
233  }
234  } else {
235  $this->setup[$theKey . '.']['mask'] = '';
236  }
237  }
238  } else {
239  unset($this->setup[$theKey . '.']);
240  }
241  break;
242  }
243  // Checks if disabled is set... (this is also done in menu.php / imgmenu!!)
244  if ($conf['if.']) {
245  ‪$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
246  ‪$cObj->‪start($this->data);
247  if (!‪$cObj->‪checkIf($conf['if.'])) {
248  unset($this->setup[$theKey]);
249  unset($this->setup[$theKey . '.']);
250  unset($this->objBB[$theKey]);
251  }
252  }
253  }
254  }
255  // Calculate offsets on elements
256  $this->setup['XY'] = $this->‪calcOffset($this->setup['XY']);
257  if (isset($this->setup['offset.'])) {
258  $this->setup['offset'] = $this->cObj->stdWrap($this->setup['offset'], $this->setup['offset.']);
259  }
260  $this->setup['offset'] = $this->‪calcOffset($this->setup['offset']);
261  if (isset($this->setup['workArea.'])) {
262  $this->setup['workArea'] = $this->cObj->stdWrap($this->setup['workArea'], $this->setup['workArea.']);
263  }
264  $this->setup['workArea'] = $this->‪calcOffset($this->setup['workArea']);
265  foreach ($sKeyArray as $theKey) {
266  $theValue = $this->setup[$theKey];
267  if ((int)$theKey && $this->setup[$theKey . '.']) {
268  switch ($theValue) {
269  case 'TEXT':
270 
271  case 'IMAGE':
272  if (isset($this->setup[$theKey . '.']['offset.'])) {
273  $this->setup[$theKey . '.']['offset'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['offset'], $this->setup[$theKey . '.']['offset.']);
274  unset($this->setup[$theKey . '.']['offset.']);
275  }
276  if ($this->setup[$theKey . '.']['offset']) {
277  $this->setup[$theKey . '.']['offset'] = $this->‪calcOffset($this->setup[$theKey . '.']['offset']);
278  }
279  break;
280  case 'BOX':
281 
282  case 'ELLIPSE':
283  if (isset($this->setup[$theKey . '.']['dimensions.'])) {
284  $this->setup[$theKey . '.']['dimensions'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['dimensions'], $this->setup[$theKey . '.']['dimensions.']);
285  unset($this->setup[$theKey . '.']['dimensions.']);
286  }
287  if ($this->setup[$theKey . '.']['dimensions']) {
288  $this->setup[$theKey . '.']['dimensions'] = $this->‪calcOffset($this->setup[$theKey . '.']['dimensions']);
289  }
290  break;
291  case 'WORKAREA':
292  if (isset($this->setup[$theKey . '.']['set.'])) {
293  $this->setup[$theKey . '.']['set'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['set'], $this->setup[$theKey . '.']['set.']);
294  unset($this->setup[$theKey . '.']['set.']);
295  }
296  if ($this->setup[$theKey . '.']['set']) {
297  $this->setup[$theKey . '.']['set'] = $this->‪calcOffset($this->setup[$theKey . '.']['set']);
298  }
299  break;
300  case 'CROP':
301  if (isset($this->setup[$theKey . '.']['crop.'])) {
302  $this->setup[$theKey . '.']['crop'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['crop'], $this->setup[$theKey . '.']['crop.']);
303  unset($this->setup[$theKey . '.']['crop.']);
304  }
305  if ($this->setup[$theKey . '.']['crop']) {
306  $this->setup[$theKey . '.']['crop'] = $this->‪calcOffset($this->setup[$theKey . '.']['crop']);
307  }
308  break;
309  case 'SCALE':
310  if (isset($this->setup[$theKey . '.']['width.'])) {
311  $this->setup[$theKey . '.']['width'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['width'], $this->setup[$theKey . '.']['width.']);
312  unset($this->setup[$theKey . '.']['width.']);
313  }
314  if ($this->setup[$theKey . '.']['width']) {
315  $this->setup[$theKey . '.']['width'] = $this->‪calcOffset($this->setup[$theKey . '.']['width']);
316  }
317  if (isset($this->setup[$theKey . '.']['height.'])) {
318  $this->setup[$theKey . '.']['height'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['height'], $this->setup[$theKey . '.']['height.']);
319  unset($this->setup[$theKey . '.']['height.']);
320  }
321  if ($this->setup[$theKey . '.']['height']) {
322  $this->setup[$theKey . '.']['height'] = $this->‪calcOffset($this->setup[$theKey . '.']['height']);
323  }
324  break;
325  }
326  }
327  }
328  // Get trivial data
329  ‪$XY = ‪GeneralUtility::intExplode(',', $this->setup['XY']);
330  $maxWidth = isset($this->setup['maxWidth.']) ? (int)$this->cObj->stdWrap($this->setup['maxWidth'], $this->setup['maxWidth.']) : (int)$this->setup['maxWidth'];
331  $maxHeight = isset($this->setup['maxHeight.']) ? (int)$this->cObj->stdWrap($this->setup['maxHeight'], $this->setup['maxHeight.']) : (int)$this->setup['maxHeight'];
332  ‪$XY[0] = ‪MathUtility::forceIntegerInRange(‪$XY[0], 1, $maxWidth ?: 2000);
333  ‪$XY[1] = ‪MathUtility::forceIntegerInRange(‪$XY[1], 1, $maxHeight ?: 2000);
334  $this->XY = ‪$XY;
335  $this->w = ‪$XY[0];
336  $this->h = ‪$XY[1];
337  $this->OFFSET = ‪GeneralUtility::intExplode(',', $this->setup['offset']);
338  // this sets the workArea
339  $this->‪setWorkArea($this->setup['workArea']);
340  // this sets the default to the current;
341  $this->defaultWorkArea = ‪$this->workArea;
342  }
343  }
344 
354  public function ‪gifBuild()
355  {
356  if ($this->setup) {
357  // Relative to Environment::getPublicPath()
358  $gifFileName = $this->‪fileName('assets/images/');
359  // File exists
360  if (!file_exists($gifFileName)) {
361  // Create temporary directory if not done:
362  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/typo3temp/assets/images/');
363  // Create file:
364  $this->‪make();
365  $this->‪output($gifFileName);
366  $this->‪destroy();
367  }
368  return $gifFileName;
369  }
370  return '';
371  }
372 
382  public function ‪make()
383  {
384  // Get trivial data
386  // Reset internal properties
387  $this->saveAlphaLayer = false;
388  // Gif-start
389  ‪$im = imagecreatetruecolor(‪$XY[0], ‪$XY[1]);
390  if (‪$im === false) {
391  throw new \RuntimeException('imagecreatetruecolor returned false', 1598350445);
392  }
393  $this->im = ‪$im;
394  $this->w = ‪$XY[0];
395  $this->h = ‪$XY[1];
396  // Transparent layer as background if set and requirements are met
397  if (!empty($this->setup['backColor']) && $this->setup['backColor'] === 'transparent' && !$this->setup['reduceColors'] && (empty($this->setup['format']) || $this->setup['format'] === 'png')) {
398  // Set transparency properties
399  imagesavealpha($this->im, true);
400  // Fill with a transparent background
401  $transparentColor = imagecolorallocatealpha($this->im, 0, 0, 0, 127);
402  imagefill($this->im, 0, 0, $transparentColor);
403  // Set internal properties to keep the transparency over the rendering process
404  $this->saveAlphaLayer = true;
405  // Force PNG in case no format is set
406  $this->setup['format'] = 'png';
407  $BGcols = [];
408  } else {
409  // Fill the background with the given color
410  $BGcols = $this->‪convertColor($this->setup['backColor']);
411  $Bcolor = imagecolorallocate($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
412  imagefilledrectangle($this->im, 0, 0, ‪$XY[0], ‪$XY[1], $Bcolor);
413  }
414  // Traverse the GIFBUILDER objects and render each one:
415  if (is_array($this->setup)) {
416  $sKeyArray = ‪ArrayUtility::filterAndSortByNumericKeys($this->setup);
417  foreach ($sKeyArray as $theKey) {
418  $theValue = $this->setup[$theKey];
419  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
420  // apply stdWrap to all properties, except for TEXT objects
421  // all properties of the TEXT sub-object have already been stdWrap-ped
422  // before in ->checkTextObj()
423  if ($theValue !== 'TEXT') {
424  $isStdWrapped = [];
425  foreach ($conf as $key => $value) {
426  $parameter = rtrim($key, '.');
427  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
428  $conf[$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
429  $isStdWrapped[$parameter] = 1;
430  }
431  }
432  }
433 
434  switch ($theValue) {
435  case 'IMAGE':
436  if ($conf['mask']) {
437  $this->‪maskImageOntoImage($this->im, $conf, $this->workArea);
438  } else {
439  $this->‪copyImageOntoImage($this->im, $conf, $this->workArea);
440  }
441  break;
442  case 'TEXT':
443  if (!$conf['hide']) {
444  if (is_array($conf['shadow.'])) {
445  $isStdWrapped = [];
446  foreach ($conf['shadow.'] as $key => $value) {
447  $parameter = rtrim($key, '.');
448  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
449  $conf['shadow.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
450  $isStdWrapped[$parameter] = 1;
451  }
452  }
453  $this->‪makeShadow($this->im, $conf['shadow.'], $this->workArea, $conf);
454  }
455  if (is_array($conf['emboss.'])) {
456  $isStdWrapped = [];
457  foreach ($conf['emboss.'] as $key => $value) {
458  $parameter = rtrim($key, '.');
459  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
460  $conf['emboss.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
461  $isStdWrapped[$parameter] = 1;
462  }
463  }
464  $this->‪makeEmboss($this->im, $conf['emboss.'], $this->workArea, $conf);
465  }
466  if (is_array($conf['outline.'])) {
467  $isStdWrapped = [];
468  foreach ($conf['outline.'] as $key => $value) {
469  $parameter = rtrim($key, '.');
470  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
471  $conf['outline.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
472  $isStdWrapped[$parameter] = 1;
473  }
474  }
475  $this->‪makeOutline($this->im, $conf['outline.'], $this->workArea, $conf);
476  }
477  $conf['imgMap'] = 1;
478  $this->‪makeText($this->im, $conf, $this->workArea);
479  }
480  break;
481  case 'OUTLINE':
482  if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->‪checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
483  $this->‪makeOutline($this->im, $conf, $this->workArea, $txtConf);
484  }
485  break;
486  case 'EMBOSS':
487  if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->‪checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
488  $this->‪makeEmboss($this->im, $conf, $this->workArea, $txtConf);
489  }
490  break;
491  case 'SHADOW':
492  if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->‪checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
493  $this->‪makeShadow($this->im, $conf, $this->workArea, $txtConf);
494  }
495  break;
496  case 'BOX':
497  $this->‪makeBox($this->im, $conf, $this->workArea);
498  break;
499  case 'EFFECT':
500  $this->‪makeEffect($this->im, $conf);
501  break;
502  case 'ADJUST':
503  $this->‪adjust($this->im, $conf);
504  break;
505  case 'CROP':
506  $this->‪crop($this->im, $conf);
507  break;
508  case 'SCALE':
509  $this->‪scale($this->im, $conf);
510  break;
511  case 'WORKAREA':
512  if ($conf['set']) {
513  // this sets the workArea
514  $this->‪setWorkArea($conf['set']);
515  }
516  if (isset($conf['clear'])) {
517  // This sets the current to the default;
518  $this->workArea = ‪$this->defaultWorkArea;
519  }
520  break;
521  case 'ELLIPSE':
522  $this->‪makeEllipse($this->im, $conf, $this->workArea);
523  break;
524  }
525  }
526  }
527  }
528  // Preserve alpha transparency
529  if (!$this->saveAlphaLayer) {
530  if ($this->setup['transparentBackground']) {
531  // Auto transparent background is set
532  $Bcolor = imagecolorclosest($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
533  imagecolortransparent($this->im, $Bcolor);
534  } elseif (is_array($this->setup['transparentColor_array'])) {
535  // Multiple transparent colors are set. This is done via the trick that all transparent colors get
536  // converted to one color and then this one gets set as transparent as png/gif can just have one
537  // transparent color.
538  $Tcolor = $this->‪unifyColors($this->im, $this->setup['transparentColor_array'], (bool)$this->setup['transparentColor.']['closest']);
539  if ($Tcolor >= 0) {
540  imagecolortransparent($this->im, $Tcolor);
541  }
542  }
543  }
544  }
545 
546  /*********************************************
547  *
548  * Various helper functions
549  *
550  ********************************************/
562  public function ‪checkTextObj($conf)
563  {
564  ‪$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
565  ‪$cObj->‪start($this->data);
566  $isStdWrapped = [];
567  foreach ($conf as $key => $value) {
568  $parameter = rtrim($key, '.');
569  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
570  $conf[$parameter] = ‪$cObj->‪stdWrap($conf[$parameter], $conf[$parameter . '.']);
571  $isStdWrapped[$parameter] = 1;
572  }
573  }
574 
575  if (!is_null($conf['fontFile'])) {
576  $conf['fontFile'] = $this->‪checkFile($conf['fontFile']);
577  }
578  if (!$conf['fontFile']) {
579  $conf['fontFile'] = $this->‪checkFile('EXT:core/Resources/Private/Font/nimbus.ttf');
580  }
581  if (!$conf['iterations']) {
582  $conf['iterations'] = 1;
583  }
584  if (!$conf['fontSize']) {
585  $conf['fontSize'] = 12;
586  }
587  // If any kind of spacing applies, we cannot use angles!!
588  if ($conf['spacing'] || $conf['wordSpacing']) {
589  $conf['angle'] = 0;
590  }
591  if (!isset($conf['antiAlias'])) {
592  $conf['antiAlias'] = 1;
593  }
594  $conf['fontColor'] = trim($conf['fontColor']);
595  // Strip HTML
596  if (!$conf['doNotStripHTML']) {
597  $conf['text'] = strip_tags($conf['text']);
598  }
599  $this->combinedTextStrings[] = strip_tags($conf['text']);
600  // Max length = 100 if automatic line braks are not defined:
601  if (!isset($conf['breakWidth']) || !$conf['breakWidth']) {
602  $tlen = (int)$conf['textMaxLength'] ?: 100;
603  $conf['text'] = mb_substr($conf['text'], 0, $tlen, 'utf-8');
604  }
605  if ((string)$conf['text'] != '') {
606  // Char range map thingie:
607  $fontBaseName = ‪PathUtility::basename($conf['fontFile']);
608  if (is_array($this->charRangeMap[$fontBaseName])) {
609  // Initialize splitRendering array:
610  if (!is_array($conf['splitRendering.'])) {
611  $conf['splitRendering.'] = [];
612  }
613  $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
614  // Do not impose settings if a splitRendering object already exists:
615  if (!isset($conf['splitRendering.'][$cfgK])) {
616  // Set configuration:
617  $conf['splitRendering.'][$cfgK] = 'charRange';
618  $conf['splitRendering.'][$cfgK . '.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
619  // Multiplicator of fontsize:
620  if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
621  $conf['splitRendering.'][$cfgK . '.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
622  }
623  // Multiplicator of pixelSpace:
624  if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
625  $travKeys = ['xSpaceBefore', 'xSpaceAfter', 'ySpaceBefore', 'ySpaceAfter'];
626  foreach ($travKeys as $pxKey) {
627  if (isset($conf['splitRendering.'][$cfgK . '.'][$pxKey])) {
628  $conf['splitRendering.'][$cfgK . '.'][$pxKey] = round($conf['splitRendering.'][$cfgK . '.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
629  }
630  }
631  }
632  }
633  }
634  if (is_array($conf['splitRendering.'])) {
635  foreach ($conf['splitRendering.'] as $key => $value) {
636  if (is_array($conf['splitRendering.'][$key])) {
637  if (isset($conf['splitRendering.'][$key]['fontFile'])) {
638  $conf['splitRendering.'][$key]['fontFile'] = $this->‪checkFile($conf['splitRendering.'][$key]['fontFile']);
639  }
640  }
641  }
642  }
643  return $conf;
644  }
645  return null;
646  }
647 
659  public function ‪calcOffset($string)
660  {
661  $value = [];
662  $numbers = ‪GeneralUtility::trimExplode(',', $this->‪calculateFunctions($string));
663  foreach ($numbers as $key => $val) {
664  if ((string)$val == (string)(int)$val) {
665  $value[$key] = (int)$val;
666  } else {
667  $value[$key] = $this->‪calculateValue($val);
668  }
669  }
670  $string = implode(',', $value);
671  return $string;
672  }
673 
683  public function ‪getResource($file, $fileArray)
684  {
685  $context = GeneralUtility::makeInstance(Context::class);
686  $deferProcessing = !$context->hasAspect('fileProcessing') || $context->getPropertyFromAspect('fileProcessing', 'deferProcessing');
687  $context->setAspect('fileProcessing', new FileProcessingAspect(false));
688  try {
689  if (!in_array($fileArray['ext'], $this->imageFileExt, true)) {
690  $fileArray['ext'] = ‪$this->gifExtension;
691  }
693  ‪$cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
694  ‪$cObj->‪start($this->data);
695  return ‪$cObj->‪getImgResource($file, $fileArray);
696  } finally {
697  $context->setAspect('fileProcessing', new FileProcessingAspect($deferProcessing));
698  }
699  }
700 
709  public function ‪checkFile($file)
710  {
711  try {
712  return GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($file);
713  } catch (‪Exception $e) {
714  return null;
715  }
716  }
717 
728  public function ‪fileName($pre)
729  {
730  $basicFileFunctions = GeneralUtility::makeInstance(BasicFileUtility::class);
731  $filePrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
732  $filePrefix = $basicFileFunctions->cleanFileName(ltrim($filePrefix, '.'));
733 
734  // shorten prefix to avoid overly long file names
735  $filePrefix = substr($filePrefix, 0, 100);
736 
737  // Only take relevant parameters to ease the pain for json_encode and make the final string short
738  // so shortMD5 is not as slow. see https://forge.typo3.org/issues/64158
739  $hashInputForFileName = [
740  array_keys($this->setup),
741  $filePrefix,
742  ‪$this->im,
743  ‪$this->w,
744  ‪$this->h,
750  ];
751  return 'typo3temp/' . $pre . $filePrefix . '_' . GeneralUtility::shortMD5((string)json_encode($hashInputForFileName)) . '.' . $this->‪extension();
752  }
753 
760  public function ‪extension()
761  {
762  switch (strtolower($this->setup['format'])) {
763  case 'jpg':
764  case 'jpeg':
765  return 'jpg';
766  case 'png':
767  return 'png';
768  case 'gif':
769  return 'gif';
770  default:
771  return ‪$this->gifExtension;
772  }
773  }
774 
782  protected function ‪calculateValue($string)
783  {
784  $calculatedValue = 0;
785  $parts = GeneralUtility::splitCalc($string, '+-*/%');
786  foreach ($parts as $part) {
787  $theVal = $part[1];
788  $sign = $part[0];
789  if (((string)(int)$theVal) == ((string)$theVal)) {
790  $theVal = (int)$theVal;
791  } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
792  $objParts = explode('.', substr($theVal, 1, -1));
793  $theVal = 0;
794  if (isset($this->objBB[$objParts[0]])) {
795  if ($objParts[1] === 'w') {
796  $theVal = $this->objBB[$objParts[0]][0];
797  } elseif ($objParts[1] === 'h') {
798  $theVal = $this->objBB[$objParts[0]][1];
799  } elseif ($objParts[1] === 'lineHeight') {
800  $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
801  }
802  $theVal = (int)$theVal;
803  }
804  } elseif ((float)$theVal) {
805  $theVal = (float)$theVal;
806  } else {
807  $theVal = 0;
808  }
809  if ($sign === '-') {
810  $calculatedValue -= $theVal;
811  } elseif ($sign === '+') {
812  $calculatedValue += $theVal;
813  } elseif ($sign === '/' && $theVal) {
814  $calculatedValue = $calculatedValue / $theVal;
815  } elseif ($sign === '*') {
816  $calculatedValue = $calculatedValue * $theVal;
817  } elseif ($sign === '%' && $theVal) {
818  $calculatedValue %= $theVal;
819  }
820  }
821  return round($calculatedValue);
822  }
823 
831  protected function ‪calculateFunctions($string)
832  {
833  if (preg_match_all('#max\\(([^)]+)\\)#', $string, $matches)) {
834  foreach ($matches[1] as $index => $maxExpression) {
835  $string = str_replace($matches[0][$index], (string)$this->‪calculateMaximum($maxExpression), $string);
836  }
837  }
838  return $string;
839  }
840 
847  protected function ‪calculateMaximum($string)
848  {
849  $parts = ‪GeneralUtility::trimExplode(',', $this->‪calcOffset($string), true);
850  $maximum = !empty($parts) ? max($parts) : 0;
851  return $maximum;
852  }
853 }
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$im
‪resource $im
Definition: GraphicalFunctions.php:268
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\calcOffset
‪string calcOffset($string)
Definition: GifBuilder.php:650
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\fontResize
‪int fontResize($conf)
Definition: GraphicalFunctions.php:869
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\checkFile
‪string null checkFile($file)
Definition: GifBuilder.php:700
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\extension
‪string extension()
Definition: GifBuilder.php:751
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEffect
‪makeEffect(&$im, $conf)
Definition: GraphicalFunctions.php:1534
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\fileName
‪string fileName($pre)
Definition: GifBuilder.php:719
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:24
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\convertColor
‪array convertColor($string)
Definition: GraphicalFunctions.php:1940
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\scale
‪scale(&$im, $conf)
Definition: GraphicalFunctions.php:1703
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeShadow
‪makeShadow(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1376
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\checkTextObj
‪array checkTextObj($conf)
Definition: GifBuilder.php:553
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\setWorkArea
‪setWorkArea($workArea)
Definition: GraphicalFunctions.php:1734
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:180
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeOutline
‪makeOutline(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1293
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\calculateFunctions
‪string calculateFunctions($string)
Definition: GifBuilder.php:822
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeBox
‪makeBox(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:1474
‪TYPO3\CMS\Core\Context\FileProcessingAspect
Definition: FileProcessingAspect.php:29
‪TYPO3\CMS\Core\Utility\File\BasicFileUtility
Definition: BasicFileUtility.php:35
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\start
‪start($data, $table='')
Definition: ContentObjectRenderer.php:533
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\stdWrap
‪string stdWrap($content='', $conf=[])
Definition: ContentObjectRenderer.php:1590
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\output
‪string output($file)
Definition: GraphicalFunctions.php:2658
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$w
‪int $w
Definition: GraphicalFunctions.php:256
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$myClassName
‪string $myClassName
Definition: GifBuilder.php:81
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\maskImageOntoImage
‪maskImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:332
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$workArea
‪array $workArea
Definition: GraphicalFunctions.php:178
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$h
‪int $h
Definition: GraphicalFunctions.php:260
‪TYPO3\CMS\Frontend\Resource\FilePathSanitizer
Definition: FilePathSanitizer.php:39
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\make
‪make()
Definition: GifBuilder.php:373
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$map
‪string $map
Definition: GraphicalFunctions.php:245
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\calculateValue
‪int calculateValue($string)
Definition: GifBuilder.php:773
‪TYPO3\CMS\Core\Utility\PathUtility\basename
‪static string basename($path)
Definition: PathUtility.php:165
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$XY
‪int[] $XY
Definition: GifBuilder.php:89
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEmboss
‪makeEmboss(&$im, $conf, $workArea, $txtConf)
Definition: GraphicalFunctions.php:1352
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions
Definition: GraphicalFunctions.php:37
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\calcBBox
‪array calcBBox($conf)
Definition: GraphicalFunctions.php:698
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\adjust
‪adjust(&$im, $conf)
Definition: GraphicalFunctions.php:1630
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:2022
‪TYPO3\CMS\Frontend\Imaging
Definition: GifBuilder.php:16
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeText
‪makeText(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:547
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:24
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$defaultWorkArea
‪array $defaultWorkArea
Definition: GifBuilder.php:97
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\unifyColors
‪int unifyColors(&$img, $colArr, $closest=false)
Definition: GraphicalFunctions.php:2832
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\destroy
‪destroy()
Definition: GraphicalFunctions.php:2700
‪TYPO3\CMS\Frontend\Imaging\GifBuilder
Definition: GifBuilder.php:56
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\getResource
‪array null getResource($file, $fileArray)
Definition: GifBuilder.php:674
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$data
‪array $data
Definition: GifBuilder.php:73
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Resource\ProcessedFile
Definition: ProcessedFile.php:44
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$objBB
‪array $objBB
Definition: GifBuilder.php:77
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$gifExtension
‪string $gifExtension
Definition: GraphicalFunctions.php:48
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:24
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\start
‪start($conf, $data)
Definition: GifBuilder.php:108
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:40
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\$setup
‪array $setup
Definition: GraphicalFunctions.php:252
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$cObj
‪ContentObjectRenderer $cObj
Definition: GifBuilder.php:93
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:97
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$combinedTextStrings
‪array $combinedTextStrings
Definition: GifBuilder.php:61
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\gifBuild
‪string gifBuild()
Definition: GifBuilder.php:345
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\getImgResource
‪array null getImgResource($file, $fileArray)
Definition: ContentObjectRenderer.php:4384
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$charRangeMap
‪array $charRangeMap
Definition: GifBuilder.php:85
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\$combinedFileNames
‪array $combinedFileNames
Definition: GifBuilder.php:67
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\makeEllipse
‪makeEllipse(&$im, array $conf, array $workArea)
Definition: GraphicalFunctions.php:1513
‪TYPO3\CMS\Core\Utility\ArrayUtility\filterAndSortByNumericKeys
‪static array filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
Definition: ArrayUtility.php:844
‪TYPO3\CMS\Core\Resource\Exception
Definition: AbstractFileOperationException.php:16
‪TYPO3\CMS\Frontend\Imaging\GifBuilder\calculateMaximum
‪int calculateMaximum($string)
Definition: GifBuilder.php:838
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\copyImageOntoImage
‪copyImageOntoImage(&$im, $conf, $workArea)
Definition: GraphicalFunctions.php:417
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer\checkIf
‪bool checkIf($conf)
Definition: ContentObjectRenderer.php:3074
‪TYPO3\CMS\Core\Imaging\GraphicalFunctions\crop
‪crop(&$im, $conf)
Definition: GraphicalFunctions.php:1665