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