GifBuilder::gifBuild()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 17
rs 9.9666
c 0
b 0
f 0
cc 3
nc 3
nop 0
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
16
namespace TYPO3\CMS\Frontend\Imaging;
17
18
use TYPO3\CMS\Core\Context\Context;
19
use TYPO3\CMS\Core\Context\FileProcessingAspect;
20
use TYPO3\CMS\Core\Core\Environment;
21
use TYPO3\CMS\Core\Imaging\GraphicalFunctions;
22
use TYPO3\CMS\Core\Resource\Exception;
23
use TYPO3\CMS\Core\Resource\File;
24
use TYPO3\CMS\Core\Resource\ProcessedFile;
25
use TYPO3\CMS\Core\Utility\ArrayUtility;
26
use TYPO3\CMS\Core\Utility\File\BasicFileUtility;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Core\Utility\MathUtility;
29
use TYPO3\CMS\Core\Utility\PathUtility;
30
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
31
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
32
use TYPO3\CMS\Frontend\Resource\FilePathSanitizer;
33
34
/**
35
 * GIFBUILDER
36
 *
37
 * Generating gif/png-files from TypoScript
38
 * Used by the menu-objects and imgResource in TypoScript.
39
 *
40
 * This class allows for advanced rendering of images with various layers of images, text and graphical primitives.
41
 * The concept is known from TypoScript as "GIFBUILDER" where you can define a "numerical array" (TypoScript term as well) of "GIFBUILDER OBJECTS" (like "TEXT", "IMAGE", etc.) and they will be rendered onto an image one by one.
42
 * The name "GIFBUILDER" comes from the time where GIF was the only file format supported. PNG is just as well to create today (configured with TYPO3_CONF_VARS[GFX])
43
 * Not all instances of this class is truly building gif/png files by layers; You may also see the class instantiated for the purpose of using the scaling functions in the parent class.
44
 *
45
 * Here is an example of how to use this class (from tslib_content.php, function getImgResource):
46
 *
47
 * $gifCreator = GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Imaging\GifBuilder::class);
48
 * $gifCreator->init();
49
 * $theImage='';
50
 * if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
51
 * $gifCreator->start($fileArray, $this->data);
52
 * $theImage = $gifCreator->gifBuild();
53
 * }
54
 * return $gifCreator->getImageDimensions($theImage);
55
 */
56
class GifBuilder extends GraphicalFunctions
57
{
58
    /**
59
     * Contains all text strings used on this image
60
     *
61
     * @var array
62
     */
63
    public $combinedTextStrings = [];
64
65
    /**
66
     * Contains all filenames (basename without extension) used on this image
67
     *
68
     * @var array
69
     */
70
    public $combinedFileNames = [];
71
72
    /**
73
     * This is the array from which data->field: [key] is fetched. So this is the current record!
74
     *
75
     * @var array
76
     */
77
    public $data = [];
78
79
    /**
80
     * @var array
81
     */
82
    public $objBB = [];
83
84
    /**
85
     * @var string
86
     */
87
    public $myClassName = 'gifbuilder';
88
89
    /**
90
     * @var array
91
     */
92
    public $charRangeMap = [];
93
94
    /**
95
     * @var int[]
96
     */
97
    public $XY = [];
98
99
    /**
100
     * @var ContentObjectRenderer
101
     * @deprecated Set to protected in v12.
102
     * @todo: Signature in v12: protected ?ContentObjectRenderer $cObj = null;
103
     */
104
    public $cObj;
105
106
    /**
107
     * @var array
108
     */
109
    public $defaultWorkArea = [];
110
111
    /**
112
     * Initialization of the GIFBUILDER objects, in particular TEXT and IMAGE. This includes finding the bounding box, setting dimensions and offset values before the actual rendering is started.
113
     * Modifies the ->setup, ->objBB internal arrays
114
     * Should be called after the ->init() function which initializes the parent class functions/variables in general.
115
     *
116
     * @param array $conf TypoScript properties for the GIFBUILDER session. Stored internally in the variable ->setup
117
     * @param array $data The current data record from \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer. Stored internally in the variable ->data
118
     * @see ContentObjectRenderer::getImgResource()
119
     */
120
    public function start($conf, $data)
121
    {
122
        if (is_array($conf)) {
0 ignored issues
show
introduced by
The condition is_array($conf) is always true.
Loading history...
123
            $this->setup = $conf;
124
            $this->data = $data;
125
            $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

125
            /** @scrutinizer ignore-deprecated */ $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
126
            $this->cObj->start($this->data);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

126
            /** @scrutinizer ignore-deprecated */ $this->cObj->start($this->data);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
127
            // Hook preprocess gifbuilder conf
128
            // Added by Julle for 3.8.0
129
            //
130
            // Let's you pre-process the gifbuilder configuration. for
131
            // example you can split a string up into lines and render each
132
            // line as TEXT obj, see extension julle_gifbconf
133
            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] ?? [] as $_funcRef) {
134
                $_params = $this->setup;
135
                $ref = $this; // introduced for phpstan to not lose type information when passing $this into callUserFunction
136
                $this->setup = GeneralUtility::callUserFunction($_funcRef, $_params, $ref);
137
            }
138
            // Initializing global Char Range Map
139
            $this->charRangeMap = [];
140
            if (($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController && is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) {
141
                foreach ($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) {
142
                    if (is_array($cRMcfg)) {
143
                        // Initializing:
144
                        $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey, 0, -1)];
145
                        $this->charRangeMap[$cRMkey] = [];
146
                        $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.'] ?? [];
147
                        $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey, 0, -1);
148
                        $this->charRangeMap[$cRMkey]['multiplicator'] = (double)$cRMcfg['fontSizeMultiplicator'];
149
                        $this->charRangeMap[$cRMkey]['pixelSpace'] = (int)$cRMcfg['pixelSpaceFontSizeRef'];
150
                    }
151
                }
152
            }
153
            // Getting sorted list of TypoScript keys from setup.
154
            $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($this->setup);
155
            // Setting the background color, passing it through stdWrap
156
            $this->setup['backColor'] = $this->cObj->stdWrapValue('backColor', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

156
            $this->setup['backColor'] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('backColor', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
157
            if (!$this->setup['backColor']) {
158
                $this->setup['backColor'] = 'white';
159
            }
160
            $this->setup['transparentColor_array'] = explode('|', trim((string)$this->cObj->stdWrapValue('transparentColor', $this->setup ?? [])));
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

160
            $this->setup['transparentColor_array'] = explode('|', trim((string)/** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('transparentColor', $this->setup ?? [])));

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
161
            $this->setup['transparentBackground'] = $this->cObj->stdWrapValue('transparentBackground', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

161
            $this->setup['transparentBackground'] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('transparentBackground', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
162
            $this->setup['reduceColors'] = $this->cObj->stdWrapValue('reduceColors', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

162
            $this->setup['reduceColors'] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('reduceColors', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
163
            // Set default dimensions
164
            $this->setup['XY'] = $this->cObj->stdWrapValue('XY', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

164
            $this->setup['XY'] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('XY', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
165
            if (!$this->setup['XY']) {
166
                $this->setup['XY'] = '120,50';
167
            }
168
            // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared.
169
            // The Bounding Box for the objects is stored in an array
170
            foreach ($sKeyArray as $theKey) {
171
                $theValue = $this->setup[$theKey];
172
                if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
173
                    // Swipes through TEXT and IMAGE-objects
174
                    switch ($theValue) {
175
                        case 'TEXT':
176
                            if ($this->setup[$theKey . '.'] = $this->checkTextObj($conf)) {
177
                                // Adjust font width if max size is set:
178
                                $maxWidth = $this->cObj->stdWrapValue('maxWidth', $this->setup[$theKey . '.'] ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

178
                                $maxWidth = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('maxWidth', $this->setup[$theKey . '.'] ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
179
                                if ($maxWidth) {
180
                                    $this->setup[$theKey . '.']['fontSize'] = $this->fontResize($this->setup[$theKey . '.']);
181
                                }
182
                                // Calculate bounding box:
183
                                $txtInfo = $this->calcBBox($this->setup[$theKey . '.']);
184
                                $this->setup[$theKey . '.']['BBOX'] = $txtInfo;
185
                                $this->objBB[$theKey] = $txtInfo;
186
                                $this->setup[$theKey . '.']['imgMap'] = 0;
187
                            }
188
                            break;
189
                        case 'IMAGE':
190
                            $fileInfo = $this->getResource($conf['file'] ?? '', $conf['file.'] ?? []);
191
                            if ($fileInfo) {
192
                                $this->combinedFileNames[] = preg_replace('/\\.[[:alnum:]]+$/', '', PathUtility::basename($fileInfo[3]));
193
                                if ($fileInfo['processedFile'] instanceof ProcessedFile) {
194
                                    // Use processed file, if a FAL file has been processed by GIFBUILDER (e.g. scaled/cropped)
195
                                    $this->setup[$theKey . '.']['file'] = $fileInfo['processedFile']->getForLocalProcessing(false);
196
                                } elseif (!isset($fileInfo['origFile']) && $fileInfo['originalFile'] instanceof File) {
197
                                    // Use FAL file with getForLocalProcessing to circumvent problems with umlauts, if it is a FAL file (origFile not set)
198
                                    /** @var File $originalFile */
199
                                    $originalFile = $fileInfo['originalFile'];
200
                                    $this->setup[$theKey . '.']['file'] = $originalFile->getForLocalProcessing(false);
201
                                } else {
202
                                    // 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)
203
                                    $this->setup[$theKey . '.']['file'] = $fileInfo[3];
204
                                }
205
206
                                // only pass necessary parts of fileInfo further down, to not incorporate facts as
207
                                // CropScaleMask runs in this request, that may not occur in subsequent calls and change
208
                                // the md5 of the generated file name
209
                                $essentialFileInfo = $fileInfo;
210
                                unset($essentialFileInfo['originalFile'], $essentialFileInfo['processedFile']);
211
212
                                $this->setup[$theKey . '.']['BBOX'] = $essentialFileInfo;
213
                                $this->objBB[$theKey] = $essentialFileInfo;
214
                                if ($conf['mask'] ?? false) {
215
                                    $maskInfo = $this->getResource($conf['mask'], $conf['mask.']);
216
                                    if ($maskInfo) {
217
                                        // the same selection criteria as regarding fileInfo above apply here
218
                                        if (($maskInfo['processedFile'] ?? null) instanceof ProcessedFile) {
219
                                            $this->setup[$theKey . '.']['mask'] = $maskInfo['processedFile']->getForLocalProcessing(false);
220
                                        } elseif (!isset($maskInfo['origFile']) && $maskInfo['originalFile'] instanceof File) {
221
                                            /** @var File $originalFile */
222
                                            $originalFile = $maskInfo['originalFile'];
223
                                            $this->setup[$theKey . '.']['mask'] = $originalFile->getForLocalProcessing(false);
224
                                        } else {
225
                                            $this->setup[$theKey . '.']['mask'] = $maskInfo[3];
226
                                        }
227
                                    } else {
228
                                        $this->setup[$theKey . '.']['mask'] = '';
229
                                    }
230
                                }
231
                            } else {
232
                                unset($this->setup[$theKey . '.']);
233
                            }
234
                            break;
235
                    }
236
                    // Checks if disabled is set... (this is also done in menu.php / imgmenu!!)
237
                    if ($conf['if.'] ?? false) {
238
                        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
239
                        $cObj->start($this->data);
240
                        if (!$cObj->checkIf($conf['if.'])) {
241
                            unset($this->setup[$theKey]);
242
                            unset($this->setup[$theKey . '.']);
243
                            unset($this->objBB[$theKey]);
244
                        }
245
                    }
246
                }
247
            }
248
            // Calculate offsets on elements
249
            $this->setup['XY'] = $this->calcOffset($this->setup['XY']);
250
            $this->setup['offset'] = (string)$this->cObj->stdWrapValue('offset', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

250
            $this->setup['offset'] = (string)/** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('offset', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
251
            $this->setup['offset'] = $this->calcOffset($this->setup['offset']);
252
            $this->setup['workArea'] = (string)$this->cObj->stdWrapValue('workArea', $this->setup ?? []);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

252
            $this->setup['workArea'] = (string)/** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue('workArea', $this->setup ?? []);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
253
            $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']);
254
            foreach ($sKeyArray as $theKey) {
255
                $theValue = $this->setup[$theKey];
256
                if ((int)$theKey && ($this->setup[$theKey . '.'] ?? false)) {
257
                    switch ($theValue) {
258
                        case 'TEXT':
259
260
                        case 'IMAGE':
261
                            if (isset($this->setup[$theKey . '.']['offset.'])) {
262
                                $this->setup[$theKey . '.']['offset'] = $this->cObj->stdWrapValue('offset', $this->setup[$theKey . '.']);
263
                                unset($this->setup[$theKey . '.']['offset.']);
264
                            }
265
                            if ($this->setup[$theKey . '.']['offset'] ?? false) {
266
                                $this->setup[$theKey . '.']['offset'] = $this->calcOffset($this->setup[$theKey . '.']['offset']);
267
                            }
268
                            break;
269
                        case 'BOX':
270
271
                        case 'ELLIPSE':
272
                            if (isset($this->setup[$theKey . '.']['dimensions.'])) {
273
                                $this->setup[$theKey . '.']['dimensions'] = $this->cObj->stdWrapValue('dimensions', $this->setup[$theKey . '.']);
274
                                unset($this->setup[$theKey . '.']['dimensions.']);
275
                            }
276
                            if ($this->setup[$theKey . '.']['dimensions'] ?? false) {
277
                                $this->setup[$theKey . '.']['dimensions'] = $this->calcOffset($this->setup[$theKey . '.']['dimensions']);
278
                            }
279
                            break;
280
                        case 'WORKAREA':
281
                            if (isset($this->setup[$theKey . '.']['set.'])) {
282
                                $this->setup[$theKey . '.']['set'] = $this->cObj->stdWrapValue('set', $this->setup[$theKey . '.']);
283
                                unset($this->setup[$theKey . '.']['set.']);
284
                            }
285
                            if ($this->setup[$theKey . '.']['set'] ?? false) {
286
                                $this->setup[$theKey . '.']['set'] = $this->calcOffset($this->setup[$theKey . '.']['set']);
287
                            }
288
                            break;
289
                        case 'CROP':
290
                            if (isset($this->setup[$theKey . '.']['crop.'])) {
291
                                $this->setup[$theKey . '.']['crop'] = $this->cObj->stdWrapValue('crop', $this->setup[$theKey . '.']);
292
                                unset($this->setup[$theKey . '.']['crop.']);
293
                            }
294
                            if ($this->setup[$theKey . '.']['crop'] ?? false) {
295
                                $this->setup[$theKey . '.']['crop'] = $this->calcOffset($this->setup[$theKey . '.']['crop']);
296
                            }
297
                            break;
298
                        case 'SCALE':
299
                            if (isset($this->setup[$theKey . '.']['width.'])) {
300
                                $this->setup[$theKey . '.']['width'] = $this->cObj->stdWrapValue('width', $this->setup[$theKey . '.']);
301
                                unset($this->setup[$theKey . '.']['width.']);
302
                            }
303
                            if ($this->setup[$theKey . '.']['width'] ?? false) {
304
                                $this->setup[$theKey . '.']['width'] = $this->calcOffset($this->setup[$theKey . '.']['width']);
305
                            }
306
                            if (isset($this->setup[$theKey . '.']['height.'])) {
307
                                $this->setup[$theKey . '.']['height'] = $this->cObj->stdWrapValue('height', $this->setup[$theKey . '.']);
308
                                unset($this->setup[$theKey . '.']['height.']);
309
                            }
310
                            if ($this->setup[$theKey . '.']['height'] ?? false) {
311
                                $this->setup[$theKey . '.']['height'] = $this->calcOffset($this->setup[$theKey . '.']['height']);
312
                            }
313
                            break;
314
                    }
315
                }
316
            }
317
            // Get trivial data
318
            $XY = GeneralUtility::intExplode(',', $this->setup['XY']);
319
            $maxWidth = (int)$this->cObj->stdWrapValue('maxWidth', $this->setup ?? []);
320
            $maxHeight = (int)$this->cObj->stdWrapValue('maxHeight', $this->setup ?? []);
321
            $XY[0] = MathUtility::forceIntegerInRange($XY[0], 1, $maxWidth ?: 2000);
322
            $XY[1] = MathUtility::forceIntegerInRange($XY[1], 1, $maxHeight ?: 2000);
323
            $this->XY = $XY;
324
            $this->w = $XY[0];
325
            $this->h = $XY[1];
326
            $this->OFFSET = GeneralUtility::intExplode(',', $this->setup['offset']);
327
            // this sets the workArea
328
            $this->setWorkArea($this->setup['workArea']);
329
            // this sets the default to the current;
330
            $this->defaultWorkArea = $this->workArea;
331
        }
332
    }
333
334
    /**
335
     * Initiates the image file generation if ->setup is TRUE and if the file did not exist already.
336
     * Gets filename from fileName() and if file exists in typo3temp/assets/images/ dir it will - of course - not be rendered again.
337
     * Otherwise rendering means calling ->make(), then ->output(), then ->destroy()
338
     *
339
     * @return string The filename for the created GIF/PNG file. The filename will be prefixed "GB_
340
     * @see make()
341
     * @see fileName()
342
     */
343
    public function gifBuild()
344
    {
345
        if ($this->setup) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->setup of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
346
            // Relative to Environment::getPublicPath()
347
            $gifFileName = $this->fileName('assets/images/');
348
            // File exists
349
            if (!file_exists($gifFileName)) {
350
                // Create temporary directory if not done:
351
                GeneralUtility::mkdir_deep(Environment::getPublicPath() . '/typo3temp/assets/images/');
352
                // Create file:
353
                $this->make();
354
                $this->output($gifFileName);
355
                $this->destroy();
356
            }
357
            return $gifFileName;
358
        }
359
        return '';
360
    }
361
362
    /**
363
     * The actual rendering of the image file.
364
     * Basically sets the dimensions, the background color, the traverses the array of GIFBUILDER objects and finally setting the transparent color if defined.
365
     * Creates a GDlib resource in $this->im and works on that
366
     * Called by gifBuild()
367
     *
368
     * @internal
369
     * @see gifBuild()
370
     */
371
    public function make()
372
    {
373
        // Get trivial data
374
        $XY = $this->XY;
375
        // Reset internal properties
376
        $this->saveAlphaLayer = false;
377
        // Gif-start
378
        $im = imagecreatetruecolor($XY[0], $XY[1]);
379
        if ($im === false) {
380
            throw new \RuntimeException('imagecreatetruecolor returned false', 1598350445);
381
        }
382
        $this->im = $im;
383
        $this->w = $XY[0];
384
        $this->h = $XY[1];
385
        // Transparent layer as background if set and requirements are met
386
        if (!empty($this->setup['backColor']) && $this->setup['backColor'] === 'transparent' && !$this->setup['reduceColors'] && (empty($this->setup['format']) || $this->setup['format'] === 'png')) {
387
            // Set transparency properties
388
            imagesavealpha($this->im, true);
389
            // Fill with a transparent background
390
            $transparentColor = imagecolorallocatealpha($this->im, 0, 0, 0, 127);
391
            imagefill($this->im, 0, 0, $transparentColor);
392
            // Set internal properties to keep the transparency over the rendering process
393
            $this->saveAlphaLayer = true;
394
            // Force PNG in case no format is set
395
            $this->setup['format'] = 'png';
396
            $BGcols = [];
397
        } else {
398
            // Fill the background with the given color
399
            $BGcols = $this->convertColor($this->setup['backColor']);
400
            $Bcolor = imagecolorallocate($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
401
            imagefilledrectangle($this->im, 0, 0, $XY[0], $XY[1], $Bcolor);
402
        }
403
        // Traverse the GIFBUILDER objects and render each one:
404
        if (is_array($this->setup)) {
405
            $sKeyArray = ArrayUtility::filterAndSortByNumericKeys($this->setup);
406
            foreach ($sKeyArray as $theKey) {
407
                $theValue = $this->setup[$theKey];
408
                if ((int)$theKey && ($conf = $this->setup[$theKey . '.'])) {
409
                    // apply stdWrap to all properties, except for TEXT objects
410
                    // all properties of the TEXT sub-object have already been stdWrap-ped
411
                    // before in ->checkTextObj()
412
                    if ($theValue !== 'TEXT') {
413
                        $isStdWrapped = [];
414
                        foreach ($conf as $key => $value) {
415
                            $parameter = rtrim($key, '.');
416
                            if (!($isStdWrapped[$parameter] ?? false) && isset($conf[$parameter . '.'])) {
417
                                $conf[$parameter] = $this->cObj->stdWrapValue($parameter, $conf);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

417
                                $conf[$parameter] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue($parameter, $conf);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
418
                                $isStdWrapped[$parameter] = 1;
419
                            }
420
                        }
421
                    }
422
423
                    switch ($theValue) {
424
                        case 'IMAGE':
425
                            if ($conf['mask'] ?? false) {
426
                                $this->maskImageOntoImage($this->im, $conf, $this->workArea);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...s::maskImageOntoImage() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

426
                                $this->maskImageOntoImage(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea);
Loading history...
427
                            } else {
428
                                $this->copyImageOntoImage($this->im, $conf, $this->workArea);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...s::copyImageOntoImage() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

428
                                $this->copyImageOntoImage(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea);
Loading history...
429
                            }
430
                            break;
431
                        case 'TEXT':
432
                            if (!($conf['hide'] ?? false)) {
433
                                if (is_array($conf['shadow.'] ?? null)) {
434
                                    $isStdWrapped = [];
435
                                    foreach ($conf['shadow.'] as $key => $value) {
436
                                        $parameter = rtrim($key, '.');
437
                                        if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
438
                                            $conf['shadow.'][$parameter] = $this->cObj->stdWrapValue($parameter, $conf);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

438
                                            $conf['shadow.'][$parameter] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue($parameter, $conf);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
439
                                            $isStdWrapped[$parameter] = 1;
440
                                        }
441
                                    }
442
                                    $this->makeShadow($this->im, $conf['shadow.'], $this->workArea, $conf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...Functions::makeShadow() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

442
                                    $this->makeShadow(/** @scrutinizer ignore-type */ $this->im, $conf['shadow.'], $this->workArea, $conf);
Loading history...
443
                                }
444
                                if (is_array($conf['emboss.'] ?? null)) {
445
                                    $isStdWrapped = [];
446
                                    foreach ($conf['emboss.'] as $key => $value) {
447
                                        $parameter = rtrim($key, '.');
448
                                        if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
449
                                            $conf['emboss.'][$parameter] = $this->cObj->stdWrapValue($parameter, $conf);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

449
                                            $conf['emboss.'][$parameter] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue($parameter, $conf);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
450
                                            $isStdWrapped[$parameter] = 1;
451
                                        }
452
                                    }
453
                                    $this->makeEmboss($this->im, $conf['emboss.'], $this->workArea, $conf);
454
                                }
455
                                if (is_array($conf['outline.'] ?? null)) {
456
                                    $isStdWrapped = [];
457
                                    foreach ($conf['outline.'] as $key => $value) {
458
                                        $parameter = rtrim($key, '.');
459
                                        if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
460
                                            $conf['outline.'][$parameter] = $this->cObj->stdWrapValue($parameter, $conf);
0 ignored issues
show
Deprecated Code introduced by
The property TYPO3\CMS\Frontend\Imaging\GifBuilder::$cObj has been deprecated: Set to protected in v12. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

460
                                            $conf['outline.'][$parameter] = /** @scrutinizer ignore-deprecated */ $this->cObj->stdWrapValue($parameter, $conf);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
461
                                            $isStdWrapped[$parameter] = 1;
462
                                        }
463
                                    }
464
                                    $this->makeOutline($this->im, $conf['outline.'], $this->workArea, $conf);
465
                                }
466
                                $conf['imgMap'] = 1;
467
                                $this->makeText($this->im, $conf, $this->workArea);
468
                            }
469
                            break;
470
                        case 'OUTLINE':
471
                            if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
472
                                $this->makeOutline($this->im, $conf, $this->workArea, $txtConf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...unctions::makeOutline() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

472
                                $this->makeOutline(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea, $txtConf);
Loading history...
473
                            }
474
                            break;
475
                        case 'EMBOSS':
476
                            if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
477
                                $this->makeEmboss($this->im, $conf, $this->workArea, $txtConf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...Functions::makeEmboss() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

477
                                $this->makeEmboss(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea, $txtConf);
Loading history...
478
                            }
479
                            break;
480
                        case 'SHADOW':
481
                            if ($this->setup[$conf['textObjNum']] === 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
482
                                $this->makeShadow($this->im, $conf, $this->workArea, $txtConf);
483
                            }
484
                            break;
485
                        case 'BOX':
486
                            $this->makeBox($this->im, $conf, $this->workArea);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...calFunctions::makeBox() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

486
                            $this->makeBox(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea);
Loading history...
487
                            break;
488
                        case 'EFFECT':
489
                            $this->makeEffect($this->im, $conf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...Functions::makeEffect() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

489
                            $this->makeEffect(/** @scrutinizer ignore-type */ $this->im, $conf);
Loading history...
490
                            break;
491
                        case 'ADJUST':
492
                            $this->adjust($this->im, $conf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...icalFunctions::adjust() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

492
                            $this->adjust(/** @scrutinizer ignore-type */ $this->im, $conf);
Loading history...
493
                            break;
494
                        case 'CROP':
495
                            $this->crop($this->im, $conf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\GraphicalFunctions::crop() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

495
                            $this->crop(/** @scrutinizer ignore-type */ $this->im, $conf);
Loading history...
496
                            break;
497
                        case 'SCALE':
498
                            $this->scale($this->im, $conf);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\GraphicalFunctions::scale() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

498
                            $this->scale(/** @scrutinizer ignore-type */ $this->im, $conf);
Loading history...
499
                            break;
500
                        case 'WORKAREA':
501
                            if ($conf['set']) {
502
                                // this sets the workArea
503
                                $this->setWorkArea($conf['set']);
504
                            }
505
                            if (isset($conf['clear'])) {
506
                                // This sets the current to the default;
507
                                $this->workArea = $this->defaultWorkArea;
508
                            }
509
                            break;
510
                        case 'ELLIPSE':
511
                            $this->makeEllipse($this->im, $conf, $this->workArea);
0 ignored issues
show
Bug introduced by
It seems like $this->im can also be of type GdImage; however, parameter $im of TYPO3\CMS\Core\Imaging\G...unctions::makeEllipse() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

511
                            $this->makeEllipse(/** @scrutinizer ignore-type */ $this->im, $conf, $this->workArea);
Loading history...
512
                            break;
513
                    }
514
                }
515
            }
516
        }
517
        // Preserve alpha transparency
518
        if (!$this->saveAlphaLayer) {
519
            if ($this->setup['transparentBackground']) {
520
                // Auto transparent background is set
521
                $Bcolor = imagecolorclosest($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
522
                imagecolortransparent($this->im, $Bcolor);
523
            } elseif (is_array($this->setup['transparentColor_array'])) {
524
                // Multiple transparent colors are set. This is done via the trick that all transparent colors get
525
                // converted to one color and then this one gets set as transparent as png/gif can just have one
526
                // transparent color.
527
                $Tcolor = $this->unifyColors($this->im, $this->setup['transparentColor_array'], (bool)($this->setup['transparentColor.']['closest'] ?? false));
528
                if ($Tcolor >= 0) {
529
                    imagecolortransparent($this->im, $Tcolor);
530
                }
531
            }
532
        }
533
    }
534
535
    /*********************************************
536
     *
537
     * Various helper functions
538
     *
539
     ********************************************/
540
    /**
541
     * Initializing/Cleaning of TypoScript properties for TEXT GIFBUILDER objects
542
     *
543
     * 'cleans' TEXT-object; Checks fontfile and other vital setup
544
     * Finds the title if its a 'variable' (instantiates a cObj and loads it with the ->data record)
545
     * Performs caseshift if any.
546
     *
547
     * @param array $conf GIFBUILDER object TypoScript properties
548
     * @return array Modified $conf array IF the "text" property is not blank
549
     * @internal
550
     */
551
    public function checkTextObj($conf)
552
    {
553
        $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
554
        $cObj->start($this->data);
555
        $isStdWrapped = [];
556
        foreach ($conf as $key => $value) {
557
            $parameter = rtrim($key, '.');
558
            if (!($isStdWrapped[$parameter] ?? false) && isset($conf[$parameter . '.'])) {
559
                $conf[$parameter] = $cObj->stdWrapValue($parameter, $conf);
560
                $isStdWrapped[$parameter] = 1;
561
            }
562
        }
563
564
        if (!is_null($conf['fontFile'] ?? null)) {
565
            $conf['fontFile'] = $this->checkFile($conf['fontFile']);
566
        }
567
        if (!($conf['fontFile'] ?? false)) {
568
            $conf['fontFile'] = $this->checkFile('EXT:core/Resources/Private/Font/nimbus.ttf');
569
        }
570
        if (!($conf['iterations'] ?? false)) {
571
            $conf['iterations'] = 1;
572
        }
573
        if (!($conf['fontSize'] ?? false)) {
574
            $conf['fontSize'] = 12;
575
        }
576
        // If any kind of spacing applies, we cannot use angles!!
577
        if (($conf['spacing'] ?? false) || ($conf['wordSpacing'] ?? false)) {
578
            $conf['angle'] = 0;
579
        }
580
        if (!isset($conf['antiAlias'])) {
581
            $conf['antiAlias'] = 1;
582
        }
583
        $conf['fontColor'] = trim($conf['fontColor'] ?? '');
584
        // Strip HTML
585
        if (!($conf['doNotStripHTML'] ?? false)) {
586
            $conf['text'] = strip_tags($conf['text'] ?? '');
587
        }
588
        $this->combinedTextStrings[] = strip_tags($conf['text'] ?? '');
589
        // Max length = 100 if automatic line breaks are not defined:
590
        if (!isset($conf['breakWidth']) || !$conf['breakWidth']) {
591
            $tlen = (int)($conf['textMaxLength'] ?? 0) ?: 100;
592
            $conf['text'] = mb_substr($conf['text'], 0, $tlen, 'utf-8');
593
        }
594
        if ((string)$conf['text'] != '') {
595
            // Char range map thingie:
596
            $fontBaseName = PathUtility::basename($conf['fontFile']);
597
            if (is_array($this->charRangeMap[$fontBaseName] ?? null)) {
598
                // Initialize splitRendering array:
599
                if (!is_array($conf['splitRendering.'])) {
600
                    $conf['splitRendering.'] = [];
601
                }
602
                $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
603
                // Do not impose settings if a splitRendering object already exists:
604
                if (!isset($conf['splitRendering.'][$cfgK])) {
605
                    // Set configuration:
606
                    $conf['splitRendering.'][$cfgK] = 'charRange';
607
                    $conf['splitRendering.'][$cfgK . '.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
608
                    // Multiplicator of fontsize:
609
                    if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
610
                        $conf['splitRendering.'][$cfgK . '.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
611
                    }
612
                    // Multiplicator of pixelSpace:
613
                    if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
614
                        $travKeys = ['xSpaceBefore', 'xSpaceAfter', 'ySpaceBefore', 'ySpaceAfter'];
615
                        foreach ($travKeys as $pxKey) {
616
                            if (isset($conf['splitRendering.'][$cfgK . '.'][$pxKey])) {
617
                                $conf['splitRendering.'][$cfgK . '.'][$pxKey] = round($conf['splitRendering.'][$cfgK . '.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
618
                            }
619
                        }
620
                    }
621
                }
622
            }
623
            if (is_array($conf['splitRendering.'] ?? null)) {
624
                foreach ($conf['splitRendering.'] as $key => $value) {
625
                    if (is_array($conf['splitRendering.'][$key])) {
626
                        if (isset($conf['splitRendering.'][$key]['fontFile'])) {
627
                            $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']);
628
                        }
629
                    }
630
                }
631
            }
632
            return $conf;
633
        }
634
        return null;
635
    }
636
637
    /**
638
     * Calculation of offset using "splitCalc" and insertion of dimensions from other GIFBUILDER objects.
639
     *
640
     * Example:
641
     * Input: 2+2, 2*3, 123, [10.w]
642
     * Output: 4,6,123,45  (provided that the width of object in position 10 was 45 pixels wide)
643
     *
644
     * @param string $string The string to resolve/calculate the result of. The string is divided by a comma first and each resulting part is calculated into an integer.
645
     * @return string The resolved string with each part (separated by comma) returned separated by comma
646
     * @internal
647
     */
648
    public function calcOffset($string)
649
    {
650
        $value = [];
651
        $numbers = GeneralUtility::trimExplode(',', $this->calculateFunctions($string));
652
        foreach ($numbers as $key => $val) {
653
            if ((string)$val == (string)(int)$val) {
654
                $value[$key] = (int)$val;
655
            } else {
656
                $value[$key] = $this->calculateValue($val);
657
            }
658
        }
659
        $string = implode(',', $value);
660
        return $string;
661
    }
662
663
    /**
664
     * Returns an "imgResource" creating an instance of the ContentObjectRenderer class and calling ContentObjectRenderer::getImgResource
665
     *
666
     * @param string $file Filename value OR the string "GIFBUILDER", see documentation in TSref for the "datatype" called "imgResource
667
     * @param array $fileArray TypoScript properties passed to the function. Either GIFBUILDER properties or imgResource properties, depending on the value of $file (whether that is "GIFBUILDER" or a file reference)
668
     * @return array|null Returns an array with file information from ContentObjectRenderer::getImgResource()
669
     * @internal
670
     * @see ContentObjectRenderer::getImgResource()
671
     */
672
    public function getResource($file, $fileArray)
673
    {
674
        $context = GeneralUtility::makeInstance(Context::class);
675
        $deferProcessing = !$context->hasAspect('fileProcessing') || $context->getPropertyFromAspect('fileProcessing', 'deferProcessing');
676
        $context->setAspect('fileProcessing', new FileProcessingAspect(false));
677
        try {
678
            if (!in_array($fileArray['ext'] ?? '', $this->imageFileExt, true)) {
679
                $fileArray['ext'] = $this->gifExtension;
680
            }
681
            /** @var ContentObjectRenderer $cObj */
682
            $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
683
            $cObj->start($this->data);
684
            return $cObj->getImgResource($file, $fileArray);
685
        } finally {
686
            $context->setAspect('fileProcessing', new FileProcessingAspect($deferProcessing));
687
        }
688
    }
689
690
    /**
691
     * Returns the reference to a "resource" in TypoScript.
692
     *
693
     * @param string $file The resource value.
694
     * @return string|null Returns the relative filepath or null if it's invalid
695
     * @internal
696
     */
697
    public function checkFile($file)
698
    {
699
        try {
700
            return GeneralUtility::makeInstance(FilePathSanitizer::class)->sanitize($file, true);
701
        } catch (Exception $e) {
702
            return null;
703
        }
704
    }
705
706
    /**
707
     * Calculates the GIFBUILDER output filename/path based on a serialized, hashed value of this->setup
708
     * and prefixes the original filename
709
     * also, the filename gets an additional prefix (max 100 characters),
710
     * something like "GB_MD5HASH_myfilename_is_very_long_and_such.jpg"
711
     *
712
     * @param string $pre Filename prefix, eg. "GB_
713
     * @return string The filepath, relative to Environment::getPublicPath()
714
     * @internal
715
     */
716
    public function fileName($pre)
717
    {
718
        $basicFileFunctions = GeneralUtility::makeInstance(BasicFileUtility::class);
719
        $filePrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
720
        $filePrefix = $basicFileFunctions->cleanFileName(ltrim($filePrefix, '.'));
721
722
        // shorten prefix to avoid overly long file names
723
        $filePrefix = substr($filePrefix, 0, 100);
724
725
        // Only take relevant parameters to ease the pain for json_encode and make the final string short
726
        // so shortMD5 is not as slow. see https://forge.typo3.org/issues/64158
727
        $hashInputForFileName = [
728
            array_keys($this->setup),
729
            $filePrefix,
730
            $this->im,
731
            $this->w,
732
            $this->h,
733
            $this->map,
734
            $this->workArea,
735
            $this->combinedTextStrings,
736
            $this->combinedFileNames,
737
            $this->data,
738
        ];
739
        return 'typo3temp/' . $pre . $filePrefix . '_' . md5((string)json_encode($hashInputForFileName)) . '.' . $this->extension();
740
    }
741
742
    /**
743
     * Returns the file extension used in the filename
744
     *
745
     * @return string Extension; "jpg" or "gif"/"png
746
     * @internal
747
     */
748
    public function extension()
749
    {
750
        switch (strtolower($this->setup['format'] ?? '')) {
751
            case 'jpg':
752
            case 'jpeg':
753
                return 'jpg';
754
            case 'png':
755
                return 'png';
756
            case 'gif':
757
                return 'gif';
758
            default:
759
                return $this->gifExtension;
760
        }
761
    }
762
763
    /**
764
     * Calculates the value concerning the dimensions of objects.
765
     *
766
     * @param string $string The string to be calculated (e.g. "[20.h]+13")
767
     * @return int The calculated value (e.g. "23")
768
     * @see calcOffset()
769
     */
770
    protected function calculateValue($string)
771
    {
772
        $calculatedValue = 0;
773
        $parts = GeneralUtility::splitCalc($string, '+-*/%');
774
        foreach ($parts as $part) {
775
            $theVal = $part[1];
776
            $sign = $part[0];
777
            if (((string)(int)$theVal) == ((string)$theVal)) {
778
                $theVal = (int)$theVal;
779
            } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
780
                $objParts = explode('.', substr($theVal, 1, -1));
781
                $theVal = 0;
782
                if (isset($this->objBB[$objParts[0]])) {
783
                    if ($objParts[1] === 'w') {
784
                        $theVal = $this->objBB[$objParts[0]][0];
785
                    } elseif ($objParts[1] === 'h') {
786
                        $theVal = $this->objBB[$objParts[0]][1];
787
                    } elseif ($objParts[1] === 'lineHeight') {
788
                        $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
789
                    }
790
                    $theVal = (int)$theVal;
791
                }
792
            } elseif ((float)$theVal) {
793
                $theVal = (float)$theVal;
794
            } else {
795
                $theVal = 0;
796
            }
797
            if ($sign === '-') {
798
                $calculatedValue -= $theVal;
799
            } elseif ($sign === '+') {
800
                $calculatedValue += $theVal;
801
            } elseif ($sign === '/' && $theVal) {
802
                $calculatedValue = $calculatedValue / $theVal;
803
            } elseif ($sign === '*') {
804
                $calculatedValue = $calculatedValue * $theVal;
805
            } elseif ($sign === '%' && $theVal) {
806
                $calculatedValue %= $theVal;
807
            }
808
        }
809
        return round($calculatedValue);
810
    }
811
812
    /**
813
     * Calculates special functions:
814
     * + max([10.h], [20.h])	-> gets the maximum of the given values
815
     *
816
     * @param string $string The raw string with functions to be calculated
817
     * @return string The calculated values
818
     */
819
    protected function calculateFunctions($string)
820
    {
821
        if (preg_match_all('#max\\(([^)]+)\\)#', $string, $matches)) {
822
            foreach ($matches[1] as $index => $maxExpression) {
823
                $string = str_replace($matches[0][$index], (string)$this->calculateMaximum($maxExpression), $string);
824
            }
825
        }
826
        return $string;
827
    }
828
829
    /**
830
     * Calculates the maximum of a set of values defined like "[10.h],[20.h],1000"
831
     *
832
     * @param string $string The string to be used to calculate the maximum (e.g. "[10.h],[20.h],1000")
833
     * @return int The maximum value of the given comma separated and calculated values
834
     */
835
    protected function calculateMaximum($string)
836
    {
837
        $parts = GeneralUtility::trimExplode(',', $this->calcOffset($string), true);
838
        $maximum = !empty($parts) ? max($parts) : 0;
839
        return $maximum;
840
    }
841
}
842