TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
GifBuilder.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Frontend\Imaging;
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 
26 
50 {
56  public $combinedTextStrings = [];
57 
63  public $combinedFileNames = [];
64 
70  public $data = [];
71 
75  public $objBB = [];
76 
80  public $myClassName = 'gifbuilder';
81 
85  public $charRangeMap = [];
86 
90  public $XY = [];
91 
95  public $cObj;
96 
100  public $defaultWorkArea = [];
101 
113  public function start($conf, $data)
114  {
115  if (is_array($conf)) {
116  $this->setup = $conf;
117  $this->data = $data;
118  $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
119  $this->cObj->start($this->data);
120  // Hook preprocess gifbuilder conf
121  // Added by Julle for 3.8.0
122  //
123  // Let's you pre-process the gifbuilder configuration. for
124  // example you can split a string up into lines and render each
125  // line as TEXT obj, see extension julle_gifbconf
126  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'])) {
127  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] as $_funcRef) {
128  $_params = $this->setup;
129  $this->setup = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
130  }
131  }
132  // Initializing global Char Range Map
133  $this->charRangeMap = [];
134  if (is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) {
135  foreach ($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) {
136  if (is_array($cRMcfg)) {
137  // Initializing:
138  $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey, 0, -1)];
139  $this->charRangeMap[$cRMkey] = [];
140  $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.'];
141  $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey, 0, -1);
142  $this->charRangeMap[$cRMkey]['multiplicator'] = (double) $cRMcfg['fontSizeMultiplicator'];
143  $this->charRangeMap[$cRMkey]['pixelSpace'] = (int)$cRMcfg['pixelSpaceFontSizeRef'];
144  }
145  }
146  }
147  // Getting sorted list of TypoScript keys from setup.
148  $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($this->setup);
149  // Setting the background color, passing it through stdWrap
150  if ($conf['backColor.'] || $conf['backColor']) {
151  $this->setup['backColor'] = isset($this->setup['backColor.']) ? trim($this->cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])) : $this->setup['backColor'];
152  }
153  if (!$this->setup['backColor']) {
154  $this->setup['backColor'] = 'white';
155  }
156  if ($conf['transparentColor.'] || $conf['transparentColor']) {
157  $this->setup['transparentColor_array'] = isset($this->setup['transparentColor.']) ? explode('|', trim($this->cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))) : explode('|', trim($this->setup['transparentColor']));
158  }
159  if (isset($this->setup['transparentBackground.'])) {
160  $this->setup['transparentBackground'] = $this->cObj->stdWrap($this->setup['transparentBackground'], $this->setup['transparentBackground.']);
161  }
162  if (isset($this->setup['reduceColors.'])) {
163  $this->setup['reduceColors'] = $this->cObj->stdWrap($this->setup['reduceColors'], $this->setup['reduceColors.']);
164  }
165  // Set default dimensions
166  if (isset($this->setup['XY.'])) {
167  $this->setup['XY'] = $this->cObj->stdWrap($this->setup['XY'], $this->setup['XY.']);
168  }
169  if (!$this->setup['XY']) {
170  $this->setup['XY'] = '120,50';
171  }
172  // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared.
173  // The Bounding Box for the objects is stored in an array
174  foreach ($sKeyArray as $theKey) {
175  $theValue = $this->setup[$theKey];
176  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
177  // Swipes through TEXT and IMAGE-objects
178  switch ($theValue) {
179  case 'TEXT':
180  if ($this->setup[$theKey . '.'] = $this->checkTextObj($conf)) {
181  // Adjust font width if max size is set:
182  $maxWidth = isset($this->setup[$theKey . '.']['maxWidth.']) ? $this->cObj->stdWrap($this->setup[$theKey . '.']['maxWidth'], $this->setup[$theKey . '.']['maxWidth.']) : $this->setup[$theKey . '.']['maxWidth'];
183  if ($maxWidth) {
184  $this->setup[$theKey . '.']['fontSize'] = $this->fontResize($this->setup[$theKey . '.']);
185  }
186  // Calculate bounding box:
187  $txtInfo = $this->calcBBox($this->setup[$theKey . '.']);
188  $this->setup[$theKey . '.']['BBOX'] = $txtInfo;
189  $this->objBB[$theKey] = $txtInfo;
190  $this->setup[$theKey . '.']['imgMap'] = 0;
191  }
192  break;
193  case 'IMAGE':
194  $fileInfo = $this->getResource($conf['file'], $conf['file.']);
195  if ($fileInfo) {
196  $this->combinedFileNames[] = preg_replace('/\\.[[:alnum:]]+$/', '', basename($fileInfo[3]));
197  if ($fileInfo['processedFile'] instanceof ProcessedFile) {
198  // Use processed file, if a FAL file has been processed by GIFBUILDER (e.g. scaled/cropped)
199  $this->setup[$theKey . '.']['file'] = $fileInfo['processedFile']->getForLocalProcessing(false);
200  } elseif (!isset($fileInfo['origFile']) && $fileInfo['originalFile'] instanceof File) {
201  // Use FAL file with getForLocalProcessing to circumvent problems with umlauts, if it is a FAL file (origFile not set)
203  $originalFile = $fileInfo['originalFile'];
204  $this->setup[$theKey . '.']['file'] = $originalFile->getForLocalProcessing(false);
205  } else {
206  // 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)
207  $this->setup[$theKey . '.']['file'] = $fileInfo[3];
208  }
209  $this->setup[$theKey . '.']['BBOX'] = $fileInfo;
210  $this->objBB[$theKey] = $fileInfo;
211  if ($conf['mask']) {
212  $maskInfo = $this->getResource($conf['mask'], $conf['mask.']);
213  if ($maskInfo) {
214  // the same selection criteria as regarding fileInfo above apply here
215  if ($maskInfo['processedFile'] instanceof ProcessedFile) {
216  $this->setup[$theKey . '.']['mask'] = $maskInfo['processedFile']->getForLocalProcessing(false);
217  } elseif (!isset($maskInfo['origFile']) && $maskInfo['originalFile'] instanceof File) {
219  $originalFile = $maskInfo['originalFile'];
220  $this->setup[$theKey . '.']['mask'] = $originalFile->getForLocalProcessing(false);
221  } else {
222  $this->setup[$theKey . '.']['mask'] = $maskInfo[3];
223  }
224  } else {
225  $this->setup[$theKey . '.']['mask'] = '';
226  }
227  }
228  } else {
229  unset($this->setup[$theKey . '.']);
230  }
231  break;
232  }
233  // Checks if disabled is set... (this is also done in menu.php / imgmenu!!)
234  if ($conf['if.']) {
235  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
236  $cObj->start($this->data);
237  if (!$cObj->checkIf($conf['if.'])) {
238  unset($this->setup[$theKey]);
239  unset($this->setup[$theKey . '.']);
240  unset($this->objBB[$theKey]);
241  }
242  }
243  }
244  }
245  // Calculate offsets on elements
246  $this->setup['XY'] = $this->calcOffset($this->setup['XY']);
247  if (isset($this->setup['offset.'])) {
248  $this->setup['offset'] = $this->cObj->stdWrap($this->setup['offset'], $this->setup['offset.']);
249  }
250  $this->setup['offset'] = $this->calcOffset($this->setup['offset']);
251  if (isset($this->setup['workArea.'])) {
252  $this->setup['workArea'] = $this->cObj->stdWrap($this->setup['workArea'], $this->setup['workArea.']);
253  }
254  $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']);
255  foreach ($sKeyArray as $theKey) {
256  $theValue = $this->setup[$theKey];
257  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
258  switch ($theValue) {
259  case 'TEXT':
260 
261  case 'IMAGE':
262  if (isset($this->setup[$theKey . '.']['offset.'])) {
263  $this->setup[$theKey . '.']['offset'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['offset'], $this->setup[$theKey . '.']['offset.']);
264  unset($this->setup[$theKey . '.']['offset.']);
265  }
266  if ($this->setup[$theKey . '.']['offset']) {
267  $this->setup[$theKey . '.']['offset'] = $this->calcOffset($this->setup[$theKey . '.']['offset']);
268  }
269  break;
270  case 'BOX':
271 
272  case 'ELLIPSE':
273  if (isset($this->setup[$theKey . '.']['dimensions.'])) {
274  $this->setup[$theKey . '.']['dimensions'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['dimensions'], $this->setup[$theKey . '.']['dimensions.']);
275  unset($this->setup[$theKey . '.']['dimensions.']);
276  }
277  if ($this->setup[$theKey . '.']['dimensions']) {
278  $this->setup[$theKey . '.']['dimensions'] = $this->calcOffset($this->setup[$theKey . '.']['dimensions']);
279  }
280  break;
281  case 'WORKAREA':
282  if (isset($this->setup[$theKey . '.']['set.'])) {
283  $this->setup[$theKey . '.']['set'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['set'], $this->setup[$theKey . '.']['set.']);
284  unset($this->setup[$theKey . '.']['set.']);
285  }
286  if ($this->setup[$theKey . '.']['set']) {
287  $this->setup[$theKey . '.']['set'] = $this->calcOffset($this->setup[$theKey . '.']['set']);
288  }
289  break;
290  case 'CROP':
291  if (isset($this->setup[$theKey . '.']['crop.'])) {
292  $this->setup[$theKey . '.']['crop'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['crop'], $this->setup[$theKey . '.']['crop.']);
293  unset($this->setup[$theKey . '.']['crop.']);
294  }
295  if ($this->setup[$theKey . '.']['crop']) {
296  $this->setup[$theKey . '.']['crop'] = $this->calcOffset($this->setup[$theKey . '.']['crop']);
297  }
298  break;
299  case 'SCALE':
300  if (isset($this->setup[$theKey . '.']['width.'])) {
301  $this->setup[$theKey . '.']['width'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['width'], $this->setup[$theKey . '.']['width.']);
302  unset($this->setup[$theKey . '.']['width.']);
303  }
304  if ($this->setup[$theKey . '.']['width']) {
305  $this->setup[$theKey . '.']['width'] = $this->calcOffset($this->setup[$theKey . '.']['width']);
306  }
307  if (isset($this->setup[$theKey . '.']['height.'])) {
308  $this->setup[$theKey . '.']['height'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['height'], $this->setup[$theKey . '.']['height.']);
309  unset($this->setup[$theKey . '.']['height.']);
310  }
311  if ($this->setup[$theKey . '.']['height']) {
312  $this->setup[$theKey . '.']['height'] = $this->calcOffset($this->setup[$theKey . '.']['height']);
313  }
314  break;
315  }
316  }
317  }
318  // Get trivial data
319  $XY = GeneralUtility::intExplode(',', $this->setup['XY']);
320  $maxWidth = isset($this->setup['maxWidth.']) ? (int)$this->cObj->stdWrap($this->setup['maxWidth'], $this->setup['maxWidth.']) : (int)$this->setup['maxWidth'];
321  $maxHeight = isset($this->setup['maxHeight.']) ? (int)$this->cObj->stdWrap($this->setup['maxHeight'], $this->setup['maxHeight.']) : (int)$this->setup['maxHeight'];
322  $XY[0] = MathUtility::forceIntegerInRange($XY[0], 1, $maxWidth ?: 2000);
323  $XY[1] = MathUtility::forceIntegerInRange($XY[1], 1, $maxHeight ?: 2000);
324  $this->XY = $XY;
325  $this->w = $XY[0];
326  $this->h = $XY[1];
327  $this->OFFSET = GeneralUtility::intExplode(',', $this->setup['offset']);
328  // this sets the workArea
329  $this->setWorkArea($this->setup['workArea']);
330  // this sets the default to the current;
331  $this->defaultWorkArea = $this->workArea;
332  }
333  }
334 
343  public function gifBuild()
344  {
345  if ($this->setup) {
346  // Relative to PATH_site
347  $gifFileName = $this->fileName('images/');
348  // File exists
349  if (!file_exists($gifFileName)) {
350  // Create temporary directory if not done:
351  $this->createTempSubDir('images/');
352  // Create file:
353  $this->make();
354  $this->output($gifFileName);
355  $this->destroy();
356  }
357  return $gifFileName;
358  }
359  return '';
360  }
361 
372  public function make()
373  {
374  // Get trivial data
375  $XY = $this->XY;
376  // Reset internal properties
377  $this->saveAlphaLayer = false;
378  // Gif-start
379  $this->im = imagecreatetruecolor($XY[0], $XY[1]);
380  $this->w = $XY[0];
381  $this->h = $XY[1];
382  // Transparent layer as background if set and requirements are met
383  if (!empty($this->setup['backColor']) && $this->setup['backColor'] === 'transparent' && $this->png_truecolor && !$this->setup['reduceColors'] && (empty($this->setup['format']) || $this->setup['format'] === 'png')) {
384  // Set transparency properties
385  imagesavealpha($this->im, true);
386  // Fill with a transparent background
387  $transparentColor = imagecolorallocatealpha($this->im, 0, 0, 0, 127);
388  imagefill($this->im, 0, 0, $transparentColor);
389  // Set internal properties to keep the transparency over the rendering process
390  $this->saveAlphaLayer = true;
391  // Force PNG in case no format is set
392  $this->setup['format'] = 'png';
393  $BGcols = [];
394  } else {
395  // Fill the background with the given color
396  $BGcols = $this->convertColor($this->setup['backColor']);
397  $Bcolor = imagecolorallocate($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
398  imagefilledrectangle($this->im, 0, 0, $XY[0], $XY[1], $Bcolor);
399  }
400  // Traverse the GIFBUILDER objects an render each one:
401  if (is_array($this->setup)) {
402  $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($this->setup);
403  foreach ($sKeyArray as $theKey) {
404  $theValue = $this->setup[$theKey];
405  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
406  // apply stdWrap to all properties, except for TEXT objects
407  // all properties of the TEXT sub-object have already been stdWrap-ped
408  // before in ->checkTextObj()
409  if ($theValue !== 'TEXT') {
410  $isStdWrapped = [];
411  foreach ($conf as $key => $value) {
412  $parameter = rtrim($key, '.');
413  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
414  $conf[$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
415  $isStdWrapped[$parameter] = 1;
416  }
417  }
418  }
419 
420  switch ($theValue) {
421  case 'IMAGE':
422  if ($conf['mask']) {
423  $this->maskImageOntoImage($this->im, $conf, $this->workArea);
424  } else {
425  $this->copyImageOntoImage($this->im, $conf, $this->workArea);
426  }
427  break;
428  case 'TEXT':
429  if (!$conf['hide']) {
430  if (is_array($conf['shadow.'])) {
431  $isStdWrapped = [];
432  foreach ($conf['shadow.'] as $key => $value) {
433  $parameter = rtrim($key, '.');
434  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
435  $conf['shadow.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
436  $isStdWrapped[$parameter] = 1;
437  }
438  }
439  $this->makeShadow($this->im, $conf['shadow.'], $this->workArea, $conf);
440  }
441  if (is_array($conf['emboss.'])) {
442  $isStdWrapped = [];
443  foreach ($conf['emboss.'] as $key => $value) {
444  $parameter = rtrim($key, '.');
445  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
446  $conf['emboss.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
447  $isStdWrapped[$parameter] = 1;
448  }
449  }
450  $this->makeEmboss($this->im, $conf['emboss.'], $this->workArea, $conf);
451  }
452  if (is_array($conf['outline.'])) {
453  $isStdWrapped = [];
454  foreach ($conf['outline.'] as $key => $value) {
455  $parameter = rtrim($key, '.');
456  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
457  $conf['outline.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
458  $isStdWrapped[$parameter] = 1;
459  }
460  }
461  $this->makeOutline($this->im, $conf['outline.'], $this->workArea, $conf);
462  }
463  $conf['imgMap'] = 1;
464  $this->makeText($this->im, $conf, $this->workArea);
465  }
466  break;
467  case 'OUTLINE':
468  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
469  $this->makeOutline($this->im, $conf, $this->workArea, $txtConf);
470  }
471  break;
472  case 'EMBOSS':
473  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
474  $this->makeEmboss($this->im, $conf, $this->workArea, $txtConf);
475  }
476  break;
477  case 'SHADOW':
478  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
479  $this->makeShadow($this->im, $conf, $this->workArea, $txtConf);
480  }
481  break;
482  case 'BOX':
483  $this->makeBox($this->im, $conf, $this->workArea);
484  break;
485  case 'EFFECT':
486  $this->makeEffect($this->im, $conf);
487  break;
488  case 'ADJUST':
489  $this->adjust($this->im, $conf);
490  break;
491  case 'CROP':
492  $this->crop($this->im, $conf);
493  break;
494  case 'SCALE':
495  $this->scale($this->im, $conf);
496  break;
497  case 'WORKAREA':
498  if ($conf['set']) {
499  // this sets the workArea
500  $this->setWorkArea($conf['set']);
501  }
502  if (isset($conf['clear'])) {
503  // This sets the current to the default;
504  $this->workArea = $this->defaultWorkArea;
505  }
506  break;
507  case 'ELLIPSE':
508  $this->makeEllipse($this->im, $conf, $this->workArea);
509  break;
510  }
511  }
512  }
513  }
514  // Preserve alpha transparency
515  if (!$this->saveAlphaLayer) {
516  if ($this->setup['transparentBackground']) {
517  // Auto transparent background is set
518  $Bcolor = imagecolorclosest($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
519  imagecolortransparent($this->im, $Bcolor);
520  } elseif (is_array($this->setup['transparentColor_array'])) {
521  // Multiple transparent colors are set. This is done via the trick that all transparent colors get
522  // converted to one color and then this one gets set as transparent as png/gif can just have one
523  // transparent color.
524  $Tcolor = $this->unifyColors($this->im, $this->setup['transparentColor_array'], (int)$this->setup['transparentColor.']['closest']);
525  if ($Tcolor >= 0) {
526  imagecolortransparent($this->im, $Tcolor);
527  }
528  }
529  }
530  }
531 
532  /*********************************************
533  *
534  * Various helper functions
535  *
536  ********************************************/
548  public function checkTextObj($conf)
549  {
550  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
551  $cObj->start($this->data);
552  $isStdWrapped = [];
553  foreach ($conf as $key => $value) {
554  $parameter = rtrim($key, '.');
555  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
556  $conf[$parameter] = $cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
557  $isStdWrapped[$parameter] = 1;
558  }
559  }
560  $conf['fontFile'] = $this->checkFile($conf['fontFile']);
561  if (!$conf['fontFile']) {
562  $conf['fontFile'] = ExtensionManagementUtility::siteRelPath('core') . 'Resources/Private/Font/nimbus.ttf';
563  }
564  if (!$conf['iterations']) {
565  $conf['iterations'] = 1;
566  }
567  if (!$conf['fontSize']) {
568  $conf['fontSize'] = 12;
569  }
570  // If any kind of spacing applys, we cannot use angles!!
571  if ($conf['spacing'] || $conf['wordSpacing']) {
572  $conf['angle'] = 0;
573  }
574  if (!isset($conf['antiAlias'])) {
575  $conf['antiAlias'] = 1;
576  }
577  $conf['fontColor'] = trim($conf['fontColor']);
578  // Strip HTML
579  if (!$conf['doNotStripHTML']) {
580  $conf['text'] = strip_tags($conf['text']);
581  }
582  $this->combinedTextStrings[] = strip_tags($conf['text']);
583  // Max length = 100 if automatic line braks are not defined:
584  if (!isset($conf['breakWidth']) || !$conf['breakWidth']) {
585  $tlen = (int)$conf['textMaxLength'] ?: 100;
586  $conf['text'] = mb_substr($conf['text'], 0, $tlen, 'utf-8');
587  }
588  if ((string)$conf['text'] != '') {
589  // Char range map thingie:
590  $fontBaseName = basename($conf['fontFile']);
591  if (is_array($this->charRangeMap[$fontBaseName])) {
592  // Initialize splitRendering array:
593  if (!is_array($conf['splitRendering.'])) {
594  $conf['splitRendering.'] = [];
595  }
596  $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
597  // Do not impose settings if a splitRendering object already exists:
598  if (!isset($conf['splitRendering.'][$cfgK])) {
599  // Set configuration:
600  $conf['splitRendering.'][$cfgK] = 'charRange';
601  $conf['splitRendering.'][$cfgK . '.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
602  // Multiplicator of fontsize:
603  if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
604  $conf['splitRendering.'][$cfgK . '.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
605  }
606  // Multiplicator of pixelSpace:
607  if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
608  $travKeys = ['xSpaceBefore', 'xSpaceAfter', 'ySpaceBefore', 'ySpaceAfter'];
609  foreach ($travKeys as $pxKey) {
610  if (isset($conf['splitRendering.'][$cfgK . '.'][$pxKey])) {
611  $conf['splitRendering.'][$cfgK . '.'][$pxKey] = round($conf['splitRendering.'][$cfgK . '.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
612  }
613  }
614  }
615  }
616  }
617  if (is_array($conf['splitRendering.'])) {
618  foreach ($conf['splitRendering.'] as $key => $value) {
619  if (is_array($conf['splitRendering.'][$key])) {
620  if (isset($conf['splitRendering.'][$key]['fontFile'])) {
621  $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']);
622  }
623  }
624  }
625  }
626  return $conf;
627  }
628  return null;
629  }
630 
642  public function calcOffset($string)
643  {
644  $value = [];
645  $numbers = GeneralUtility::trimExplode(',', $this->calculateFunctions($string));
646  foreach ($numbers as $key => $val) {
647  if ((string)$val == (string)(int)$val) {
648  $value[$key] = (int)$val;
649  } else {
650  $value[$key] = $this->calculateValue($val);
651  }
652  }
653  $string = implode(',', $value);
654  return $string;
655  }
656 
666  public function getResource($file, $fileArray)
667  {
668  if (!GeneralUtility::inList($this->imageFileExt, $fileArray['ext'])) {
669  $fileArray['ext'] = $this->gifExtension;
670  }
672  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
673  $cObj->start($this->data);
674  return $cObj->getImgResource($file, $fileArray);
675  }
676 
685  public function checkFile($file)
686  {
687  return $GLOBALS['TSFE']->tmpl->getFileName($file);
688  }
689 
700  public function fileName($pre)
701  {
703  $basicFileFunctions = GeneralUtility::makeInstance(BasicFileUtility::class);
704  $filePrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
705  $filePrefix = $basicFileFunctions->cleanFileName($filePrefix);
706 
707  return $this->tempPath . $pre . $filePrefix . '_' . GeneralUtility::shortMD5(serialize($this->setup)) . '.' . $this->extension();
708  }
709 
716  public function extension()
717  {
718  switch (strtolower($this->setup['format'])) {
719  case 'jpg':
720 
721  case 'jpeg':
722  return 'jpg';
723  break;
724  case 'png':
725  return 'png';
726  break;
727  case 'gif':
728  return 'gif';
729  break;
730  default:
731  return $this->gifExtension;
732  }
733  }
734 
742  protected function calculateValue($string)
743  {
744  $calculatedValue = 0;
745  $parts = GeneralUtility::splitCalc($string, '+-*/%');
746  foreach ($parts as $part) {
747  $theVal = $part[1];
748  $sign = $part[0];
749  if (((string)(int)$theVal) == ((string)$theVal)) {
750  $theVal = (int)$theVal;
751  } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
752  $objParts = explode('.', substr($theVal, 1, -1));
753  $theVal = 0;
754  if (isset($this->objBB[$objParts[0]])) {
755  if ($objParts[1] == 'w') {
756  $theVal = $this->objBB[$objParts[0]][0];
757  } elseif ($objParts[1] == 'h') {
758  $theVal = $this->objBB[$objParts[0]][1];
759  } elseif ($objParts[1] == 'lineHeight') {
760  $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
761  }
762  $theVal = (int)$theVal;
763  }
764  } elseif ((float)$theVal) {
765  $theVal = (float)$theVal;
766  } else {
767  $theVal = 0;
768  }
769  if ($sign == '-') {
770  $calculatedValue -= $theVal;
771  } elseif ($sign == '+') {
772  $calculatedValue += $theVal;
773  } elseif ($sign == '/' && $theVal) {
774  $calculatedValue = $calculatedValue / $theVal;
775  } elseif ($sign == '*') {
776  $calculatedValue = $calculatedValue * $theVal;
777  } elseif ($sign == '%' && $theVal) {
778  $calculatedValue %= $theVal;
779  }
780  }
781  return round($calculatedValue);
782  }
783 
791  protected function calculateFunctions($string)
792  {
793  if (preg_match_all('#max\\(([^)]+)\\)#', $string, $matches)) {
794  foreach ($matches[1] as $index => $maxExpression) {
795  $string = str_replace($matches[0][$index], $this->calculateMaximum($maxExpression), $string);
796  }
797  }
798  return $string;
799  }
800 
807  protected function calculateMaximum($string)
808  {
809  $parts = GeneralUtility::trimExplode(',', $this->calcOffset($string), true);
810  $maximum = !empty($parts) ? max($parts) : 0;
811  return $maximum;
812  }
813 }
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
makeEmboss(&$im, $conf, $workArea, $txtConf)
makeEllipse(&$im, array $conf, array $workArea)
makeShadow(&$im, $conf, $workArea, $txtConf)
makeOutline(&$im, $conf, $workArea, $txtConf)
static splitCalc($string, $operators)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $_= '', $errorMode=0)
unifyColors(&$img, $colArr, $closest=false)