TYPO3  7.6
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 
25 
49 {
55  public $im = '';
56 
62  public $w = 0;
63 
69  public $h = 0;
70 
76  public $map;
77 
81  public $workArea;
82 
88  public $setup = array();
89 
95  public $combinedTextStrings = array();
96 
102  public $combinedFileNames = array();
103 
109  public $data = array();
110 
114  public $objBB = array();
115 
119  public $myClassName = 'gifbuilder';
120 
124  public $charRangeMap = array();
125 
129  public $XY = array();
130 
134  public $OFFSET = array();
135 
139  public $cObj;
140 
144  public $defaultWorkArea = array();
145 
157  public function start($conf, $data)
158  {
159  if (is_array($conf)) {
160  $this->setup = $conf;
161  $this->data = $data;
162  $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
163  $this->cObj->start($this->data);
164  // Hook preprocess gifbuilder conf
165  // Added by Julle for 3.8.0
166  //
167  // Let's you pre-process the gifbuilder configuration. for
168  // example you can split a string up into lines and render each
169  // line as TEXT obj, see extension julle_gifbconf
170  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'])) {
171  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] as $_funcRef) {
172  $_params = $this->setup;
173  $this->setup = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
174  }
175  }
176  // Initializing global Char Range Map
177  $this->charRangeMap = array();
178  if (is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) {
179  foreach ($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) {
180  if (is_array($cRMcfg)) {
181  // Initializing:
182  $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey, 0, -1)];
183  $this->charRangeMap[$cRMkey] = array();
184  $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.'];
185  $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey, 0, -1);
186  $this->charRangeMap[$cRMkey]['multiplicator'] = (double) $cRMcfg['fontSizeMultiplicator'];
187  $this->charRangeMap[$cRMkey]['pixelSpace'] = (int)$cRMcfg['pixelSpaceFontSizeRef'];
188  }
189  }
190  }
191  // Getting sorted list of TypoScript keys from setup.
192  $sKeyArray = TemplateService::sortedKeyList($this->setup);
193  // Setting the background color, passing it through stdWrap
194  if ($conf['backColor.'] || $conf['backColor']) {
195  $this->setup['backColor'] = isset($this->setup['backColor.']) ? trim($this->cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])) : $this->setup['backColor'];
196  }
197  if (!$this->setup['backColor']) {
198  $this->setup['backColor'] = 'white';
199  }
200  if ($conf['transparentColor.'] || $conf['transparentColor']) {
201  $this->setup['transparentColor_array'] = isset($this->setup['transparentColor.']) ? explode('|', trim($this->cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))) : explode('|', trim($this->setup['transparentColor']));
202  }
203  if (isset($this->setup['transparentBackground.'])) {
204  $this->setup['transparentBackground'] = $this->cObj->stdWrap($this->setup['transparentBackground'], $this->setup['transparentBackground.']);
205  }
206  if (isset($this->setup['reduceColors.'])) {
207  $this->setup['reduceColors'] = $this->cObj->stdWrap($this->setup['reduceColors'], $this->setup['reduceColors.']);
208  }
209  // Set default dimensions
210  if (isset($this->setup['XY.'])) {
211  $this->setup['XY'] = $this->cObj->stdWrap($this->setup['XY'], $this->setup['XY.']);
212  }
213  if (!$this->setup['XY']) {
214  $this->setup['XY'] = '120,50';
215  }
216  // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared.
217  // The Bounding Box for the objects is stored in an array
218  foreach ($sKeyArray as $theKey) {
219  $theValue = $this->setup[$theKey];
220  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
221  // Swipes through TEXT and IMAGE-objects
222  switch ($theValue) {
223  case 'TEXT':
224  if ($this->setup[$theKey . '.'] = $this->checkTextObj($conf)) {
225  // Adjust font width if max size is set:
226  $maxWidth = isset($this->setup[$theKey . '.']['maxWidth.']) ? $this->cObj->stdWrap($this->setup[$theKey . '.']['maxWidth'], $this->setup[$theKey . '.']['maxWidth.']) : $this->setup[$theKey . '.']['maxWidth'];
227  if ($maxWidth) {
228  $this->setup[$theKey . '.']['fontSize'] = $this->fontResize($this->setup[$theKey . '.']);
229  }
230  // Calculate bounding box:
231  $txtInfo = $this->calcBBox($this->setup[$theKey . '.']);
232  $this->setup[$theKey . '.']['BBOX'] = $txtInfo;
233  $this->objBB[$theKey] = $txtInfo;
234  $this->setup[$theKey . '.']['imgMap'] = 0;
235  }
236  break;
237  case 'IMAGE':
238  $fileInfo = $this->getResource($conf['file'], $conf['file.']);
239  if ($fileInfo) {
240  $this->combinedFileNames[] = preg_replace('/\\.[[:alnum:]]+$/', '', basename($fileInfo[3]));
241  if ($fileInfo['processedFile'] instanceof ProcessedFile) {
242  // Use processed file, if a FAL file has been processed by GIFBUILDER (e.g. scaled/cropped)
243  $this->setup[$theKey . '.']['file'] = $fileInfo['processedFile']->getForLocalProcessing(false);
244  } elseif (!isset($fileInfo['origFile']) && $fileInfo['originalFile'] instanceof File) {
245  // Use FAL file with getForLocalProcessing to circumvent problems with umlauts, if it is a FAL file (origFile not set)
247  $originalFile = $fileInfo['originalFile'];
248  $this->setup[$theKey . '.']['file'] = $originalFile->getForLocalProcessing(false);
249  } else {
250  // 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)
251  $this->setup[$theKey . '.']['file'] = $fileInfo[3];
252  }
253  $this->setup[$theKey . '.']['BBOX'] = $fileInfo;
254  $this->objBB[$theKey] = $fileInfo;
255  if ($conf['mask']) {
256  $maskInfo = $this->getResource($conf['mask'], $conf['mask.']);
257  if ($maskInfo) {
258  // the same selection criteria as regarding fileInfo above apply here
259  if ($maskInfo['processedFile'] instanceof ProcessedFile) {
260  $this->setup[$theKey . '.']['mask'] = $maskInfo['processedFile']->getForLocalProcessing(false);
261  } elseif (!isset($maskInfo['origFile']) && $maskInfo['originalFile'] instanceof File) {
263  $originalFile = $maskInfo['originalFile'];
264  $this->setup[$theKey . '.']['mask'] = $originalFile->getForLocalProcessing(false);
265  } else {
266  $this->setup[$theKey . '.']['mask'] = $maskInfo[3];
267  }
268  } else {
269  $this->setup[$theKey . '.']['mask'] = '';
270  }
271  }
272  } else {
273  unset($this->setup[$theKey . '.']);
274  }
275  break;
276  }
277  // Checks if disabled is set... (this is also done in menu.php / imgmenu!!)
278  if ($conf['if.']) {
279  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
280  $cObj->start($this->data);
281  if (!$cObj->checkIf($conf['if.'])) {
282  unset($this->setup[$theKey]);
283  unset($this->setup[$theKey . '.']);
284  unset($this->objBB[$theKey]);
285  }
286  }
287  }
288  }
289  // Calculate offsets on elements
290  $this->setup['XY'] = $this->calcOffset($this->setup['XY']);
291  if (isset($this->setup['offset.'])) {
292  $this->setup['offset'] = $this->cObj->stdWrap($this->setup['offset'], $this->setup['offset.']);
293  }
294  $this->setup['offset'] = $this->calcOffset($this->setup['offset']);
295  if (isset($this->setup['workArea.'])) {
296  $this->setup['workArea'] = $this->cObj->stdWrap($this->setup['workArea'], $this->setup['workArea.']);
297  }
298  $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']);
299  foreach ($sKeyArray as $theKey) {
300  $theValue = $this->setup[$theKey];
301  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
302  switch ($theValue) {
303  case 'TEXT':
304 
305  case 'IMAGE':
306  if (isset($this->setup[$theKey . '.']['offset.'])) {
307  $this->setup[$theKey . '.']['offset'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['offset'], $this->setup[$theKey . '.']['offset.']);
308  unset($this->setup[$theKey . '.']['offset.']);
309  }
310  if ($this->setup[$theKey . '.']['offset']) {
311  $this->setup[$theKey . '.']['offset'] = $this->calcOffset($this->setup[$theKey . '.']['offset']);
312  }
313  break;
314  case 'BOX':
315 
316  case 'ELLIPSE':
317  if (isset($this->setup[$theKey . '.']['dimensions.'])) {
318  $this->setup[$theKey . '.']['dimensions'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['dimensions'], $this->setup[$theKey . '.']['dimensions.']);
319  unset($this->setup[$theKey . '.']['dimensions.']);
320  }
321  if ($this->setup[$theKey . '.']['dimensions']) {
322  $this->setup[$theKey . '.']['dimensions'] = $this->calcOffset($this->setup[$theKey . '.']['dimensions']);
323  }
324  break;
325  case 'WORKAREA':
326  if (isset($this->setup[$theKey . '.']['set.'])) {
327  $this->setup[$theKey . '.']['set'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['set'], $this->setup[$theKey . '.']['set.']);
328  unset($this->setup[$theKey . '.']['set.']);
329  }
330  if ($this->setup[$theKey . '.']['set']) {
331  $this->setup[$theKey . '.']['set'] = $this->calcOffset($this->setup[$theKey . '.']['set']);
332  }
333  break;
334  case 'CROP':
335  if (isset($this->setup[$theKey . '.']['crop.'])) {
336  $this->setup[$theKey . '.']['crop'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['crop'], $this->setup[$theKey . '.']['crop.']);
337  unset($this->setup[$theKey . '.']['crop.']);
338  }
339  if ($this->setup[$theKey . '.']['crop']) {
340  $this->setup[$theKey . '.']['crop'] = $this->calcOffset($this->setup[$theKey . '.']['crop']);
341  }
342  break;
343  case 'SCALE':
344  if (isset($this->setup[$theKey . '.']['width.'])) {
345  $this->setup[$theKey . '.']['width'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['width'], $this->setup[$theKey . '.']['width.']);
346  unset($this->setup[$theKey . '.']['width.']);
347  }
348  if ($this->setup[$theKey . '.']['width']) {
349  $this->setup[$theKey . '.']['width'] = $this->calcOffset($this->setup[$theKey . '.']['width']);
350  }
351  if (isset($this->setup[$theKey . '.']['height.'])) {
352  $this->setup[$theKey . '.']['height'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['height'], $this->setup[$theKey . '.']['height.']);
353  unset($this->setup[$theKey . '.']['height.']);
354  }
355  if ($this->setup[$theKey . '.']['height']) {
356  $this->setup[$theKey . '.']['height'] = $this->calcOffset($this->setup[$theKey . '.']['height']);
357  }
358  break;
359  }
360  }
361  }
362  // Get trivial data
363  $XY = GeneralUtility::intExplode(',', $this->setup['XY']);
364  $maxWidth = isset($this->setup['maxWidth.']) ? (int)$this->cObj->stdWrap($this->setup['maxWidth'], $this->setup['maxWidth.']) : (int)$this->setup['maxWidth'];
365  $maxHeight = isset($this->setup['maxHeight.']) ? (int)$this->cObj->stdWrap($this->setup['maxHeight'], $this->setup['maxHeight.']) : (int)$this->setup['maxHeight'];
366  $XY[0] = MathUtility::forceIntegerInRange($XY[0], 1, $maxWidth ?: 2000);
367  $XY[1] = MathUtility::forceIntegerInRange($XY[1], 1, $maxHeight ?: 2000);
368  $this->XY = $XY;
369  $this->w = $XY[0];
370  $this->h = $XY[1];
371  $this->OFFSET = GeneralUtility::intExplode(',', $this->setup['offset']);
372  // this sets the workArea
373  $this->setWorkArea($this->setup['workArea']);
374  // this sets the default to the current;
375  $this->defaultWorkArea = $this->workArea;
376  }
377  }
378 
387  public function gifBuild()
388  {
389  if ($this->setup) {
390  // Relative to PATH_site
391  $gifFileName = $this->fileName('GB/');
392  // File exists
393  if (!file_exists($gifFileName)) {
394  // Create temporary directory if not done:
395  $this->createTempSubDir('GB/');
396  // Create file:
397  $this->make();
398  $this->output($gifFileName);
399  $this->destroy();
400  }
401  return $gifFileName;
402  }
403  return '';
404  }
405 
416  public function make()
417  {
418  // Get trivial data
419  $XY = $this->XY;
420  // Reset internal properties
421  $this->saveAlphaLayer = false;
422  // Gif-start
423  $this->im = imagecreatetruecolor($XY[0], $XY[1]);
424  $this->w = $XY[0];
425  $this->h = $XY[1];
426  // Transparent layer as background if set and requirements are met
427  if (!empty($this->setup['backColor']) && $this->setup['backColor'] === 'transparent' && $this->png_truecolor && !$this->setup['reduceColors'] && (empty($this->setup['format']) || $this->setup['format'] === 'png')) {
428  // Set transparency properties
429  imagesavealpha($this->im, true);
430  // Fill with a transparent background
431  $transparentColor = imagecolorallocatealpha($this->im, 0, 0, 0, 127);
432  imagefill($this->im, 0, 0, $transparentColor);
433  // Set internal properties to keep the transparency over the rendering process
434  $this->saveAlphaLayer = true;
435  // Force PNG in case no format is set
436  $this->setup['format'] = 'png';
437  $BGcols = array();
438  } else {
439  // Fill the background with the given color
440  $BGcols = $this->convertColor($this->setup['backColor']);
441  $Bcolor = ImageColorAllocate($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
442  ImageFilledRectangle($this->im, 0, 0, $XY[0], $XY[1], $Bcolor);
443  }
444  // Traverse the GIFBUILDER objects an render each one:
445  if (is_array($this->setup)) {
446  $sKeyArray = TemplateService::sortedKeyList($this->setup);
447  foreach ($sKeyArray as $theKey) {
448  $theValue = $this->setup[$theKey];
449  if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
450  // apply stdWrap to all properties, except for TEXT objects
451  // all properties of the TEXT sub-object have already been stdWrap-ped
452  // before in ->checkTextObj()
453  if ($theValue !== 'TEXT') {
454  $isStdWrapped = array();
455  foreach ($conf as $key => $value) {
456  $parameter = rtrim($key, '.');
457  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
458  $conf[$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
459  $isStdWrapped[$parameter] = 1;
460  }
461  }
462  }
463 
464  switch ($theValue) {
465  case 'IMAGE':
466  if ($conf['mask']) {
467  $this->maskImageOntoImage($this->im, $conf, $this->workArea);
468  } else {
469  $this->copyImageOntoImage($this->im, $conf, $this->workArea);
470  }
471  break;
472  case 'TEXT':
473  if (!$conf['hide']) {
474  if (is_array($conf['shadow.'])) {
475  $isStdWrapped = array();
476  foreach ($conf['shadow.'] as $key => $value) {
477  $parameter = rtrim($key, '.');
478  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
479  $conf['shadow.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
480  $isStdWrapped[$parameter] = 1;
481  }
482  }
483  $this->makeShadow($this->im, $conf['shadow.'], $this->workArea, $conf);
484  }
485  if (is_array($conf['emboss.'])) {
486  $isStdWrapped = array();
487  foreach ($conf['emboss.'] as $key => $value) {
488  $parameter = rtrim($key, '.');
489  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
490  $conf['emboss.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
491  $isStdWrapped[$parameter] = 1;
492  }
493  }
494  $this->makeEmboss($this->im, $conf['emboss.'], $this->workArea, $conf);
495  }
496  if (is_array($conf['outline.'])) {
497  $isStdWrapped = array();
498  foreach ($conf['outline.'] as $key => $value) {
499  $parameter = rtrim($key, '.');
500  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
501  $conf['outline.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
502  $isStdWrapped[$parameter] = 1;
503  }
504  }
505  $this->makeOutline($this->im, $conf['outline.'], $this->workArea, $conf);
506  }
507  $conf['imgMap'] = 1;
508  $this->makeText($this->im, $conf, $this->workArea);
509  }
510  break;
511  case 'OUTLINE':
512  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
513  $this->makeOutline($this->im, $conf, $this->workArea, $txtConf);
514  }
515  break;
516  case 'EMBOSS':
517  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
518  $this->makeEmboss($this->im, $conf, $this->workArea, $txtConf);
519  }
520  break;
521  case 'SHADOW':
522  if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
523  $this->makeShadow($this->im, $conf, $this->workArea, $txtConf);
524  }
525  break;
526  case 'BOX':
527  $this->makeBox($this->im, $conf, $this->workArea);
528  break;
529  case 'EFFECT':
530  $this->makeEffect($this->im, $conf);
531  break;
532  case 'ADJUST':
533  $this->adjust($this->im, $conf);
534  break;
535  case 'CROP':
536  $this->crop($this->im, $conf);
537  break;
538  case 'SCALE':
539  $this->scale($this->im, $conf);
540  break;
541  case 'WORKAREA':
542  if ($conf['set']) {
543  // this sets the workArea
544  $this->setWorkArea($conf['set']);
545  }
546  if (isset($conf['clear'])) {
547  // This sets the current to the default;
548  $this->workArea = $this->defaultWorkArea;
549  }
550  break;
551  case 'ELLIPSE':
552  $this->makeEllipse($this->im, $conf, $this->workArea);
553  break;
554  }
555  }
556  }
557  }
558  // Preserve alpha transparency
559  if (!$this->saveAlphaLayer) {
560  if ($this->setup['transparentBackground']) {
561  // Auto transparent background is set
562  $Bcolor = ImageColorClosest($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
563  imagecolortransparent($this->im, $Bcolor);
564  } elseif (is_array($this->setup['transparentColor_array'])) {
565  // Multiple transparent colors are set. This is done via the trick that all transparent colors get
566  // converted to one color and then this one gets set as transparent as png/gif can just have one
567  // transparent color.
568  $Tcolor = $this->unifyColors($this->im, $this->setup['transparentColor_array'], (int)$this->setup['transparentColor.']['closest']);
569  if ($Tcolor >= 0) {
570  imagecolortransparent($this->im, $Tcolor);
571  }
572  }
573  }
574  }
575 
576  /*********************************************
577  *
578  * Various helper functions
579  *
580  ********************************************/
592  public function checkTextObj($conf)
593  {
594  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
595  $cObj->start($this->data);
596  $isStdWrapped = array();
597  foreach ($conf as $key => $value) {
598  $parameter = rtrim($key, '.');
599  if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
600  $conf[$parameter] = $cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
601  $isStdWrapped[$parameter] = 1;
602  }
603  }
604  $conf['fontFile'] = $this->checkFile($conf['fontFile']);
605  if (!$conf['fontFile']) {
606  $conf['fontFile'] = 'typo3/sysext/core/Resources/Private/Font/nimbus.ttf';
607  }
608  if (!$conf['iterations']) {
609  $conf['iterations'] = 1;
610  }
611  if (!$conf['fontSize']) {
612  $conf['fontSize'] = 12;
613  }
614  // If any kind of spacing applys, we cannot use angles!!
615  if ($conf['spacing'] || $conf['wordSpacing']) {
616  $conf['angle'] = 0;
617  }
618  if (!isset($conf['antiAlias'])) {
619  $conf['antiAlias'] = 1;
620  }
621  $conf['fontColor'] = trim($conf['fontColor']);
622  // Strip HTML
623  if (!$conf['doNotStripHTML']) {
624  $conf['text'] = strip_tags($conf['text']);
625  }
626  $this->combinedTextStrings[] = strip_tags($conf['text']);
627  // Max length = 100 if automatic line braks are not defined:
628  if (!isset($conf['breakWidth']) || !$conf['breakWidth']) {
629  $tlen = (int)$conf['textMaxLength'] ?: 100;
630  if ($this->nativeCharset) {
631  $conf['text'] = $this->csConvObj->substr($this->nativeCharset, $conf['text'], 0, $tlen);
632  } else {
633  $conf['text'] = substr($conf['text'], 0, $tlen);
634  }
635  }
636  if ((string)$conf['text'] != '') {
637  // Char range map thingie:
638  $fontBaseName = basename($conf['fontFile']);
639  if (is_array($this->charRangeMap[$fontBaseName])) {
640  // Initialize splitRendering array:
641  if (!is_array($conf['splitRendering.'])) {
642  $conf['splitRendering.'] = array();
643  }
644  $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
645  // Do not impose settings if a splitRendering object already exists:
646  if (!isset($conf['splitRendering.'][$cfgK])) {
647  // Set configuration:
648  $conf['splitRendering.'][$cfgK] = 'charRange';
649  $conf['splitRendering.'][$cfgK . '.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
650  // Multiplicator of fontsize:
651  if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
652  $conf['splitRendering.'][$cfgK . '.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
653  }
654  // Multiplicator of pixelSpace:
655  if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
656  $travKeys = array('xSpaceBefore', 'xSpaceAfter', 'ySpaceBefore', 'ySpaceAfter');
657  foreach ($travKeys as $pxKey) {
658  if (isset($conf['splitRendering.'][$cfgK . '.'][$pxKey])) {
659  $conf['splitRendering.'][$cfgK . '.'][$pxKey] = round($conf['splitRendering.'][($cfgK . '.')][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
660  }
661  }
662  }
663  }
664  }
665  if (is_array($conf['splitRendering.'])) {
666  foreach ($conf['splitRendering.'] as $key => $value) {
667  if (is_array($conf['splitRendering.'][$key])) {
668  if (isset($conf['splitRendering.'][$key]['fontFile'])) {
669  $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']);
670  }
671  }
672  }
673  }
674  return $conf;
675  }
676  return null;
677  }
678 
690  public function calcOffset($string)
691  {
692  $value = array();
693  $numbers = GeneralUtility::trimExplode(',', $this->calculateFunctions($string));
694  foreach ($numbers as $key => $val) {
695  if ((string)$val == (string)(int)$val) {
696  $value[$key] = (int)$val;
697  } else {
698  $value[$key] = $this->calculateValue($val);
699  }
700  }
701  $string = implode(',', $value);
702  return $string;
703  }
704 
714  public function getResource($file, $fileArray)
715  {
716  if (!GeneralUtility::inList($this->imageFileExt, $fileArray['ext'])) {
717  $fileArray['ext'] = $this->gifExtension;
718  }
720  $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
721  $cObj->start($this->data);
722  return $cObj->getImgResource($file, $fileArray);
723  }
724 
733  public function checkFile($file)
734  {
735  return $GLOBALS['TSFE']->tmpl->getFileName($file);
736  }
737 
748  public function fileName($pre)
749  {
751  $basicFileFunctions = GeneralUtility::makeInstance(BasicFileUtility::class);
752  $filePrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
753  $filePrefix = $basicFileFunctions->cleanFileName($filePrefix);
754 
755  return $this->tempPath . $pre . $filePrefix . '_' . GeneralUtility::shortMD5(serialize($this->setup)) . '.' . $this->extension();
756  }
757 
764  public function extension()
765  {
766  switch (strtolower($this->setup['format'])) {
767  case 'jpg':
768 
769  case 'jpeg':
770  return 'jpg';
771  break;
772  case 'png':
773  return 'png';
774  break;
775  case 'gif':
776  return 'gif';
777  break;
778  default:
779  return $this->gifExtension;
780  }
781  }
782 
790  protected function calculateValue($string)
791  {
792  $calculatedValue = 0;
793  $parts = GeneralUtility::splitCalc($string, '+-*/%');
794  foreach ($parts as $part) {
795  $theVal = $part[1];
796  $sign = $part[0];
797  if (((string)(int)$theVal) == ((string)$theVal)) {
798  $theVal = (int)$theVal;
799  } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
800  $objParts = explode('.', substr($theVal, 1, -1));
801  $theVal = 0;
802  if (isset($this->objBB[$objParts[0]])) {
803  if ($objParts[1] == 'w') {
804  $theVal = $this->objBB[$objParts[0]][0];
805  } elseif ($objParts[1] == 'h') {
806  $theVal = $this->objBB[$objParts[0]][1];
807  } elseif ($objParts[1] == 'lineHeight') {
808  $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
809  }
810  $theVal = (int)$theVal;
811  }
812  } elseif (floatval($theVal)) {
813  $theVal = floatval($theVal);
814  } else {
815  $theVal = 0;
816  }
817  if ($sign == '-') {
818  $calculatedValue -= $theVal;
819  } elseif ($sign == '+') {
820  $calculatedValue += $theVal;
821  } elseif ($sign == '/' && $theVal) {
822  $calculatedValue = $calculatedValue / $theVal;
823  } elseif ($sign == '*') {
824  $calculatedValue = $calculatedValue * $theVal;
825  } elseif ($sign == '%' && $theVal) {
826  $calculatedValue %= $theVal;
827  }
828  }
829  return round($calculatedValue);
830  }
831 
839  protected function calculateFunctions($string)
840  {
841  if (preg_match_all('#max\\(([^)]+)\\)#', $string, $matches)) {
842  foreach ($matches[1] as $index => $maxExpression) {
843  $string = str_replace($matches[0][$index], $this->calculateMaximum($maxExpression), $string);
844  }
845  }
846  return $string;
847  }
848 
855  protected function calculateMaximum($string)
856  {
857  $parts = GeneralUtility::trimExplode(',', $this->calcOffset($string), true);
858  $maximum = !empty($parts) ? max($parts) : 0;
859  return $maximum;
860  }
861 }