[BUGFIX] Replace calls of tslib_gifbuilder with namespaced class
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Imaging / GifBuilder.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Imaging;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Generating gif/png-files from TypoScript
31 * Used by the menu-objects and imgResource in TypoScript.
32 *
33 * Revised for TYPO3 3.6 June/2003 by Kasper Skårhøj
34 *
35 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
36 */
37 /**
38 * GIFBUILDER extension class.
39 * This class allows for advanced rendering of images with various layers of images, text and graphical primitives.
40 * 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.
41 * 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])
42 * Not all instances of this class is truely 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, t3lib_stdGraphic.
43 *
44 * Here is an example of how to use this class (from tslib_content.php, function getImgResource):
45 *
46 * $gifCreator = t3lib_div::makeInstance('TYPO3\\CMS\\Frontend\\Imaging\\GifBuilder');
47 * $gifCreator->init();
48 * $theImage='';
49 * if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
50 * $gifCreator->start($fileArray, $this->data);
51 * $theImage = $gifCreator->gifBuild();
52 * }
53 * return $gifCreator->getImageDimensions($theImage);
54 *
55 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
56 */
57 class GifBuilder extends \TYPO3\CMS\Core\Imaging\GraphicalFunctions {
58
59 // Internal
60 // the main image
61 /**
62 * @todo Define visibility
63 */
64 public $im = '';
65
66 // the image-width
67 /**
68 * @todo Define visibility
69 */
70 public $w = 0;
71
72 // the image-height
73 /**
74 * @todo Define visibility
75 */
76 public $h = 0;
77
78 // map-data
79 /**
80 * @todo Define visibility
81 */
82 public $map;
83
84 /**
85 * @todo Define visibility
86 */
87 public $workArea;
88
89 // This holds the operational setup for gifbuilder. Basically this is a TypoScript array with properties.
90 /**
91 * @todo Define visibility
92 */
93 public $setup = array();
94
95 // Contains all text strings used on this image
96 /**
97 * @todo Define visibility
98 */
99 public $combinedTextStrings = array();
100
101 // Contains all filenames (basename without extension) used on this image
102 /**
103 * @todo Define visibility
104 */
105 public $combinedFileNames = array();
106
107 // This is the array from which data->field: [key] is fetched. So this is the current record!
108 /**
109 * @todo Define visibility
110 */
111 public $data = array();
112
113 /**
114 * @todo Define visibility
115 */
116 public $objBB = array();
117
118 /**
119 * @todo Define visibility
120 */
121 public $myClassName = 'gifbuilder';
122
123 /**
124 * @todo Define visibility
125 */
126 public $charRangeMap = array();
127
128 /**
129 * 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.
130 * Modifies the ->setup, ->objBB internal arrays
131 * Should be called after the ->init() function which initializes the parent class functions/variables in general.
132 * The class tslib_gmenu also uses gifbuilder and here there is an interesting use since the function findLargestDims() from that class calls the init() and start() functions to find the total dimensions before starting the rendering of the images.
133 *
134 * @param array $conf TypoScript properties for the GIFBUILDER session. Stored internally in the variable ->setup
135 * @param array $data The current data record from tslib_cObj. Stored internally in the variable ->data
136 * @return void
137 * @see tslib_cObj::getImgResource(), tslib_gmenu::makeGifs(), tslib_gmenu::findLargestDims()
138 * @todo Define visibility
139 */
140 public function start($conf, $data) {
141 if (is_array($conf)) {
142 $this->setup = $conf;
143 $this->data = $data;
144 $this->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
145 $this->cObj->start($this->data);
146 // Hook preprocess gifbuilder conf
147 // Added by Julle for 3.8.0
148 //
149 // Let's you pre-process the gifbuilder configuration. for
150 // example you can split a string up into lines and render each
151 // line as TEXT obj, see extension julle_gifbconf
152 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'])) {
153 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] as $_funcRef) {
154 $_params = $this->setup;
155 $this->setup = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $_params, $this);
156 }
157 }
158 // Initializing global Char Range Map
159 $this->charRangeMap = array();
160 if (is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) {
161 foreach ($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) {
162 if (is_array($cRMcfg)) {
163 // Initializing:
164 $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey, 0, -1)];
165 $this->charRangeMap[$cRMkey] = array();
166 $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.'];
167 $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey, 0, -1);
168 $this->charRangeMap[$cRMkey]['multiplicator'] = (double) $cRMcfg['fontSizeMultiplicator'];
169 $this->charRangeMap[$cRMkey]['pixelSpace'] = intval($cRMcfg['pixelSpaceFontSizeRef']);
170 }
171 }
172 }
173 // Getting sorted list of TypoScript keys from setup.
174 $sKeyArray = \TYPO3\CMS\Core\TypoScript\TemplateService::sortedKeyList($this->setup);
175 // Setting the background color, passing it through stdWrap
176 if ($conf['backColor.'] || $conf['backColor']) {
177 $this->setup['backColor'] = isset($this->setup['backColor.']) ? trim($this->cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])) : $this->setup['backColor'];
178 }
179 if (!$this->setup['backColor']) {
180 $this->setup['backColor'] = 'white';
181 }
182 if ($conf['transparentColor.'] || $conf['transparentColor']) {
183 $this->setup['transparentColor_array'] = isset($this->setup['transparentColor.']) ? explode('|', trim($this->cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))) : explode('|', trim($this->setup['transparentColor']));
184 }
185 if (isset($this->setup['transparentBackground.'])) {
186 $this->setup['transparentBackground'] = $this->cObj->stdWrap($this->setup['transparentBackground'], $this->setup['transparentBackground.']);
187 }
188 if (isset($this->setup['reduceColors.'])) {
189 $this->setup['reduceColors'] = $this->cObj->stdWrap($this->setup['reduceColors'], $this->setup['reduceColors.']);
190 }
191 // Set default dimensions
192 if (isset($this->setup['XY.'])) {
193 $this->setup['XY'] = $this->cObj->stdWrap($this->setup['XY'], $this->setup['XY.']);
194 }
195 if (!$this->setup['XY']) {
196 $this->setup['XY'] = '120,50';
197 }
198 // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared.
199 // The Bounding Box for the objects is stored in an array
200 foreach ($sKeyArray as $theKey) {
201 $theValue = $this->setup[$theKey];
202 if (intval($theKey) && ($conf = $this->setup[$theKey . '.'])) {
203 // Swipes through TEXT and IMAGE-objects
204 switch ($theValue) {
205 case 'TEXT':
206 if ($this->setup[$theKey . '.'] = $this->checkTextObj($conf)) {
207 // Adjust font width if max size is set:
208 $maxWidth = isset($this->setup[$theKey . '.']['maxWidth.']) ? $this->cObj->stdWrap($this->setup[$theKey . '.']['maxWidth'], $this->setup[$theKey . '.']['maxWidth.']) : $this->setup[$theKey . '.']['maxWidth'];
209 if ($maxWidth) {
210 $this->setup[$theKey . '.']['fontSize'] = $this->fontResize($this->setup[$theKey . '.']);
211 }
212 // Calculate bounding box:
213 $txtInfo = $this->calcBBox($this->setup[$theKey . '.']);
214 $this->setup[$theKey . '.']['BBOX'] = $txtInfo;
215 $this->objBB[$theKey] = $txtInfo;
216 $this->setup[$theKey . '.']['imgMap'] = 0;
217 }
218 break;
219 case 'IMAGE':
220 $fileInfo = $this->getResource($conf['file'], $conf['file.']);
221 if ($fileInfo) {
222 $this->combinedFileNames[] = preg_replace('/\\.[[:alnum:]]+$/', '', basename($fileInfo[3]));
223 $this->setup[$theKey . '.']['file'] = $fileInfo[3];
224 $this->setup[$theKey . '.']['BBOX'] = $fileInfo;
225 $this->objBB[$theKey] = $fileInfo;
226 if ($conf['mask']) {
227 $maskInfo = $this->getResource($conf['mask'], $conf['mask.']);
228 if ($maskInfo) {
229 $this->setup[$theKey . '.']['mask'] = $maskInfo[3];
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 = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
242 $cObj->start($this->data);
243 if (!$cObj->checkIf($conf['if.'])) {
244 unset($this->setup[$theKey]);
245 unset($this->setup[$theKey . '.']);
246 }
247 }
248 }
249 }
250 // Calculate offsets on elements
251 $this->setup['XY'] = $this->calcOffset($this->setup['XY']);
252 if (isset($this->setup['offset.'])) {
253 $this->setup['offset'] = $this->cObj->stdWrap($this->setup['offset'], $this->setup['offset.']);
254 }
255 $this->setup['offset'] = $this->calcOffset($this->setup['offset']);
256 if (isset($this->setup['workArea.'])) {
257 $this->setup['workArea'] = $this->cObj->stdWrap($this->setup['workArea'], $this->setup['workArea.']);
258 }
259 $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']);
260 foreach ($sKeyArray as $theKey) {
261 $theValue = $this->setup[$theKey];
262 if (intval($theKey) && ($conf = $this->setup[$theKey . '.'])) {
263 switch ($theValue) {
264 case 'TEXT':
265
266 case 'IMAGE':
267 if (isset($this->setup[$theKey . '.']['offset.'])) {
268 $this->setup[$theKey . '.']['offset'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['offset'], $this->setup[$theKey . '.']['offset.']);
269 }
270 if ($this->setup[$theKey . '.']['offset']) {
271 $this->setup[$theKey . '.']['offset'] = $this->calcOffset($this->setup[$theKey . '.']['offset']);
272 }
273 break;
274 case 'BOX':
275
276 case 'ELLIPSE':
277 if (isset($this->setup[$theKey . '.']['dimensions.'])) {
278 $this->setup[$theKey . '.']['dimensions'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['dimensions'], $this->setup[$theKey . '.']['dimensions.']);
279 }
280 if ($this->setup[$theKey . '.']['dimensions']) {
281 $this->setup[$theKey . '.']['dimensions'] = $this->calcOffset($this->setup[$theKey . '.']['dimensions']);
282 }
283 break;
284 case 'WORKAREA':
285 if (isset($this->setup[$theKey . '.']['set.'])) {
286 $this->setup[$theKey . '.']['set'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['set'], $this->setup[$theKey . '.']['set.']);
287 }
288 if ($this->setup[$theKey . '.']['set']) {
289 $this->setup[$theKey . '.']['set'] = $this->calcOffset($this->setup[$theKey . '.']['set']);
290 }
291 break;
292 case 'CROP':
293 if (isset($this->setup[$theKey . '.']['crop.'])) {
294 $this->setup[$theKey . '.']['crop'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['crop'], $this->setup[$theKey . '.']['crop.']);
295 }
296 if ($this->setup[$theKey . '.']['crop']) {
297 $this->setup[$theKey . '.']['crop'] = $this->calcOffset($this->setup[$theKey . '.']['crop']);
298 }
299 break;
300 case 'SCALE':
301 if (isset($this->setup[$theKey . '.']['width.'])) {
302 $this->setup[$theKey . '.']['width'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['width'], $this->setup[$theKey . '.']['width.']);
303 }
304 if ($this->setup[$theKey . '.']['width']) {
305 $this->setup[$theKey . '.']['width'] = $this->calcOffset($this->setup[$theKey . '.']['width']);
306 }
307 if (isset($this->setup[$theKey . '.']['height.'])) {
308 $this->setup[$theKey . '.']['height'] = $this->cObj->stdWrap($this->setup[$theKey . '.']['height'], $this->setup[$theKey . '.']['height.']);
309 }
310 if ($this->setup[$theKey . '.']['height']) {
311 $this->setup[$theKey . '.']['height'] = $this->calcOffset($this->setup[$theKey . '.']['height']);
312 }
313 break;
314 }
315 }
316 }
317 // Get trivial data
318 $XY = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $this->setup['XY']);
319 $maxWidth = isset($this->setup['maxWidth.']) ? intval($this->cObj->stdWrap($this->setup['maxWidth'], $this->setup['maxWidth.'])) : intval($this->setup['maxWidth']);
320 $maxHeight = isset($this->setup['maxHeight.']) ? intval($this->cObj->stdWrap($this->setup['maxHeight'], $this->setup['maxHeight.'])) : intval($this->setup['maxHeight']);
321 $XY[0] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($XY[0], 1, $maxWidth ? $maxWidth : 2000);
322 $XY[1] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($XY[1], 1, $maxHeight ? $maxHeight : 2000);
323 $this->XY = $XY;
324 $this->w = $XY[0];
325 $this->h = $XY[1];
326 $this->OFFSET = \TYPO3\CMS\Core\Utility\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/ 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(), fileName()
341 * @todo Define visibility
342 */
343 public function gifBuild() {
344 if ($this->setup) {
345 // Relative to PATH_site
346 $gifFileName = $this->fileName('GB/');
347 // File exists
348 if (!file_exists($gifFileName)) {
349 // Create temporary directory if not done:
350 $this->createTempSubDir('GB/');
351 // Create file:
352 $this->make();
353 $this->output($gifFileName);
354 $this->destroy();
355 }
356 return $gifFileName;
357 }
358 }
359
360 /**
361 * The actual rendering of the image file.
362 * Basically sets the dimensions, the background color, the traverses the array of GIFBUILDER objects and finally setting the transparent color if defined.
363 * Creates a GDlib resource in $this->im and works on that
364 * Called by gifBuild()
365 *
366 * @return void
367 * @access private
368 * @see gifBuild()
369 * @todo Define visibility
370 */
371 public function make() {
372 // Get trivial data
373 $XY = $this->XY;
374 // Reset internal properties
375 $this->saveAlphaLayer = FALSE;
376 // Gif-start
377 $this->im = imagecreatetruecolor($XY[0], $XY[1]);
378 $this->w = $XY[0];
379 $this->h = $XY[1];
380 // Transparent layer as background if set and requirements are met
381 if (!empty($this->setup['backColor']) && $this->setup['backColor'] === 'transparent' && $this->png_truecolor && !$this->setup['reduceColors'] && (empty($this->setup['format']) || $this->setup['format'] === 'png')) {
382 // Set transparency properties
383 imagesavealpha($this->im, TRUE);
384 // Fill with a transparent background
385 $transparentColor = imagecolorallocatealpha($this->im, 0, 0, 0, 127);
386 imagefill($this->im, 0, 0, $transparentColor);
387 // Set internal properties to keep the transparency over the rendering process
388 $this->saveAlphaLayer = TRUE;
389 // Force PNG in case no format is set
390 $this->setup['format'] = 'png';
391 } else {
392 // Fill the background with the given color
393 $BGcols = $this->convertColor($this->setup['backColor']);
394 $Bcolor = ImageColorAllocate($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
395 ImageFilledRectangle($this->im, 0, 0, $XY[0], $XY[1], $Bcolor);
396 }
397 // Traverse the GIFBUILDER objects an render each one:
398 if (is_array($this->setup)) {
399 $sKeyArray = \TYPO3\CMS\Core\TypoScript\TemplateService::sortedKeyList($this->setup);
400 foreach ($sKeyArray as $theKey) {
401 $theValue = $this->setup[$theKey];
402 if (intval($theKey) && ($conf = $this->setup[$theKey . '.'])) {
403 $isStdWrapped = array();
404 foreach ($conf as $key => $value) {
405 $parameter = rtrim($key, '.');
406 if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
407 $conf[$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
408 $isStdWrapped[$parameter] = 1;
409 }
410 }
411 switch ($theValue) {
412 case 'IMAGE':
413 if ($conf['mask']) {
414 $this->maskImageOntoImage($this->im, $conf, $this->workArea);
415 } else {
416 $this->copyImageOntoImage($this->im, $conf, $this->workArea);
417 }
418 break;
419 case 'TEXT':
420 if (!$conf['hide']) {
421 if (is_array($conf['shadow.'])) {
422 $isStdWrapped = array();
423 foreach ($conf['shadow.'] as $key => $value) {
424 $parameter = rtrim($key, '.');
425 if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
426 $conf['shadow.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
427 $isStdWrapped[$parameter] = 1;
428 }
429 }
430 $this->makeShadow($this->im, $conf['shadow.'], $this->workArea, $conf);
431 }
432 if (is_array($conf['emboss.'])) {
433 $isStdWrapped = array();
434 foreach ($conf['emboss.'] as $key => $value) {
435 $parameter = rtrim($key, '.');
436 if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
437 $conf['emboss.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
438 $isStdWrapped[$parameter] = 1;
439 }
440 }
441 $this->makeEmboss($this->im, $conf['emboss.'], $this->workArea, $conf);
442 }
443 if (is_array($conf['outline.'])) {
444 $isStdWrapped = array();
445 foreach ($conf['outline.'] as $key => $value) {
446 $parameter = rtrim($key, '.');
447 if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
448 $conf['outline.'][$parameter] = $this->cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
449 $isStdWrapped[$parameter] = 1;
450 }
451 }
452 $this->makeOutline($this->im, $conf['outline.'], $this->workArea, $conf);
453 }
454 $conf['imgMap'] = 1;
455 $this->makeText($this->im, $conf, $this->workArea);
456 }
457 break;
458 case 'OUTLINE':
459 if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
460 $this->makeOutline($this->im, $conf, $this->workArea, $txtConf);
461 }
462 break;
463 case 'EMBOSS':
464 if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
465 $this->makeEmboss($this->im, $conf, $this->workArea, $txtConf);
466 }
467 break;
468 case 'SHADOW':
469 if ($this->setup[$conf['textObjNum']] == 'TEXT' && ($txtConf = $this->checkTextObj($this->setup[$conf['textObjNum'] . '.']))) {
470 $this->makeShadow($this->im, $conf, $this->workArea, $txtConf);
471 }
472 break;
473 case 'BOX':
474 $this->makeBox($this->im, $conf, $this->workArea);
475 break;
476 case 'EFFECT':
477 $this->makeEffect($this->im, $conf);
478 break;
479 case 'ADJUST':
480 $this->adjust($this->im, $conf);
481 break;
482 case 'CROP':
483 $this->crop($this->im, $conf);
484 break;
485 case 'SCALE':
486 $this->scale($this->im, $conf);
487 break;
488 case 'WORKAREA':
489 if ($conf['set']) {
490 // this sets the workArea
491 $this->setWorkArea($conf['set']);
492 }
493 if (isset($conf['clear'])) {
494 // This sets the current to the default;
495 $this->workArea = $this->defaultWorkArea;
496 }
497 break;
498 case 'ELLIPSE':
499 $this->makeEllipse($this->im, $conf, $this->workArea);
500 break;
501 }
502 }
503 }
504 }
505 // Preserve alpha transparency
506 if (!$this->saveAlphaLayer) {
507 if ($this->setup['transparentBackground']) {
508 // Auto transparent background is set
509 $Bcolor = ImageColorClosest($this->im, $BGcols[0], $BGcols[1], $BGcols[2]);
510 imagecolortransparent($this->im, $Bcolor);
511 } elseif (is_array($this->setup['transparentColor_array'])) {
512 // Multiple transparent colors are set. This is done via the trick that all transparent colors get
513 // converted to one color and then this one gets set as transparent as png/gif can just have one
514 // transparent color.
515 $Tcolor = $this->unifyColors($this->im, $this->setup['transparentColor_array'], intval($this->setup['transparentColor.']['closest']));
516 if ($Tcolor >= 0) {
517 imagecolortransparent($this->im, $Tcolor);
518 }
519 }
520 }
521 }
522
523 /*********************************************
524 *
525 * Various helper functions
526 *
527 ********************************************/
528 /**
529 * Initializing/Cleaning of TypoScript properties for TEXT GIFBUILDER objects
530 *
531 * 'cleans' TEXT-object; Checks fontfile and other vital setup
532 * Finds the title if its a 'variable' (instantiates a cObj and loads it with the ->data record)
533 * Performs caseshift if any.
534 *
535 * @param array $conf GIFBUILDER object TypoScript properties
536 * @return array Modified $conf array IF the "text" property is not blank
537 * @access private
538 * @todo Define visibility
539 */
540 public function checkTextObj($conf) {
541 $cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
542 $cObj->start($this->data);
543 $isStdWrapped = array();
544 foreach ($conf as $key => $value) {
545 $parameter = rtrim($key, '.');
546 if (!$isStdWrapped[$parameter] && isset($conf[$parameter . '.'])) {
547 $conf[$parameter] = $cObj->stdWrap($conf[$parameter], $conf[$parameter . '.']);
548 $isStdWrapped[$parameter] = 1;
549 }
550 }
551 $conf['fontFile'] = $this->checkFile($conf['fontFile']);
552 if (!$conf['fontFile']) {
553 $conf['fontFile'] = 't3lib/fonts/nimbus.ttf';
554 }
555 if (!$conf['iterations']) {
556 $conf['iterations'] = 1;
557 }
558 if (!$conf['fontSize']) {
559 $conf['fontSize'] = 12;
560 }
561 // If any kind of spacing applys, we cannot use angles!!
562 if ($conf['spacing'] || $conf['wordSpacing']) {
563 $conf['angle'] = 0;
564 }
565 if (!isset($conf['antiAlias'])) {
566 $conf['antiAlias'] = 1;
567 }
568 $conf['fontColor'] = trim($conf['fontColor']);
569 // Strip HTML
570 if (!$conf['doNotStripHTML']) {
571 $conf['text'] = strip_tags($conf['text']);
572 }
573 $this->combinedTextStrings[] = strip_tags($conf['text']);
574 // Max length = 100 if automatic line braks are not defined:
575 if (!isset($conf['breakWidth']) || !$conf['breakWidth']) {
576 $tlen = intval($conf['textMaxLength']) ? intval($conf['textMaxLength']) : 100;
577 if ($this->nativeCharset) {
578 $conf['text'] = $this->csConvObj->substr($this->nativeCharset, $conf['text'], 0, $tlen);
579 } else {
580 $conf['text'] = substr($conf['text'], 0, $tlen);
581 }
582 }
583 if ((string) $conf['text'] != '') {
584 // Char range map thingie:
585 $fontBaseName = basename($conf['fontFile']);
586 if (is_array($this->charRangeMap[$fontBaseName])) {
587 // Initialize splitRendering array:
588 if (!is_array($conf['splitRendering.'])) {
589 $conf['splitRendering.'] = array();
590 }
591 $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
592 // Do not impose settings if a splitRendering object already exists:
593 if (!isset($conf['splitRendering.'][$cfgK])) {
594 // Set configuration:
595 $conf['splitRendering.'][$cfgK] = 'charRange';
596 $conf['splitRendering.'][$cfgK . '.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
597 // Multiplicator of fontsize:
598 if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
599 $conf['splitRendering.'][$cfgK . '.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
600 }
601 // Multiplicator of pixelSpace:
602 if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
603 $travKeys = array('xSpaceBefore', 'xSpaceAfter', 'ySpaceBefore', 'ySpaceAfter');
604 foreach ($travKeys as $pxKey) {
605 if (isset($conf['splitRendering.'][$cfgK . '.'][$pxKey])) {
606 $conf['splitRendering.'][$cfgK . '.'][$pxKey] = round($conf['splitRendering.'][($cfgK . '.')][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
607 }
608 }
609 }
610 }
611 }
612 if (is_array($conf['splitRendering.'])) {
613 foreach ($conf['splitRendering.'] as $key => $value) {
614 if (is_array($conf['splitRendering.'][$key])) {
615 if (isset($conf['splitRendering.'][$key]['fontFile'])) {
616 $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']);
617 }
618 }
619 }
620 }
621 return $conf;
622 }
623 }
624
625 /**
626 * Calculation of offset using "splitCalc" and insertion of dimensions from other GIFBUILDER objects.
627 *
628 * Example:
629 * Input: 2+2, 2*3, 123, [10.w]
630 * Output: 4,6,123,45 (provided that the width of object in position 10 was 45 pixels wide)
631 *
632 * @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.
633 * @return string The resolved string with each part (separated by comma) returned separated by comma
634 * @access private
635 * @todo Define visibility
636 */
637 public function calcOffset($string) {
638 $value = array();
639 $numbers = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->calculateFunctions($string));
640 foreach ($numbers as $key => $val) {
641 if ((string) $val == (string) intval($val)) {
642 $value[$key] = intval($val);
643 } else {
644 $value[$key] = $this->calculateValue($val);
645 }
646 }
647 $string = implode(',', $value);
648 return $string;
649 }
650
651 /**
652 * Returns an "imgResource" creating an instance of the tslib_cObj class and calling tslib_cObj::getImgResource
653 *
654 * @param string $file Filename value OR the string "GIFBUILDER", see documentation in TSref for the "datatype" called "imgResource
655 * @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)
656 * @return array Returns an array with file information if an image was returned. Otherwise FALSE.
657 * @access private
658 * @see tslib_cObj::getImgResource()
659 * @todo Define visibility
660 */
661 public function getResource($file, $fileArray) {
662 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->imageFileExt, $fileArray['ext'])) {
663 $fileArray['ext'] = $this->gifExtension;
664 }
665 $cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
666 $cObj->start($this->data);
667 return $cObj->getImgResource($file, $fileArray);
668 }
669
670 /**
671 * Returns the reference to a "resource" in TypoScript.
672 *
673 * @param string $file The resource value.
674 * @return string Returns the relative filepath
675 * @access private
676 * @see t3lib_TStemplate::getFileName()
677 * @todo Define visibility
678 */
679 public function checkFile($file) {
680 return $GLOBALS['TSFE']->tmpl->getFileName($file);
681 }
682
683 /**
684 * Calculates the GIFBUILDER output filename/path based on a serialized, hashed value of this->setup
685 *
686 * @param string $pre Filename prefix, eg. "GB_
687 * @return string The relative filepath (relative to PATH_site)
688 * @access private
689 * @todo Define visibility
690 */
691 public function fileName($pre) {
692 $meaningfulPrefix = '';
693 if ($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']) {
694 /** @var $basicFileFunctions \TYPO3\CMS\Core\Utility\File\BasicFileUtility */
695 $basicFileFunctions = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Utility\\File\\BasicFileUtility');
696 $meaningfulPrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
697 $meaningfulPrefix = $basicFileFunctions->cleanFileName($meaningfulPrefix);
698 $meaningfulPrefixLength = intval($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']);
699 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) {
700 /** @var $t3libCsInstance \TYPO3\CMS\Core\Charset\CharsetConverter */
701 $t3libCsInstance = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
702 $meaningfulPrefix = $t3libCsInstance->substr('utf-8', $meaningfulPrefix, 0, $meaningfulPrefixLength);
703 } else {
704 $meaningfulPrefix = substr($meaningfulPrefix, 0, $meaningfulPrefixLength);
705 }
706 $meaningfulPrefix .= '_';
707 }
708 // WARNING: In PHP5 I discovered that rendering with freetype of Japanese letters was totally corrupt.
709 // Not only the wrong glyphs are printed but also some memory stack overflow resulted in strange additional
710 // chars - and finally the reason for this investigation: The Bounding box data was changing all the time
711 // resulting in new images being generated all the time. With PHP4 it works fine.
712 return $this->tempPath . $pre . $meaningfulPrefix . \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5(serialize($this->setup)) . '.' . $this->extension();
713 }
714
715 /**
716 * Returns the file extension used in the filename
717 *
718 * @return string Extension; "jpg" or "gif"/"png
719 * @access private
720 * @todo Define visibility
721 */
722 public function extension() {
723 switch (strtolower($this->setup['format'])) {
724 case 'jpg':
725
726 case 'jpeg':
727 return 'jpg';
728 break;
729 case 'png':
730 return 'png';
731 break;
732 case 'gif':
733 return 'gif';
734 break;
735 default:
736 return $this->gifExtension;
737 break;
738 }
739 }
740
741 /**
742 * Calculates the value concerning the dimensions of objects.
743 *
744 * @param string $string The string to be calculated (e.g. "[20.h]+13")
745 * @return integer The calculated value (e.g. "23")
746 * @see calcOffset()
747 */
748 protected function calculateValue($string) {
749 $calculatedValue = 0;
750 $parts = \TYPO3\CMS\Core\Utility\GeneralUtility::splitCalc($string, '+-*/%');
751 foreach ($parts as $part) {
752 $theVal = $part[1];
753 $sign = $part[0];
754 if ((string) intval($theVal) == (string) $theVal) {
755 $theVal = intval($theVal);
756 } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
757 $objParts = explode('.', substr($theVal, 1, -1));
758 $theVal = 0;
759 if (isset($this->objBB[$objParts[0]])) {
760 if ($objParts[1] == 'w') {
761 $theVal = $this->objBB[$objParts[0]][0];
762 } elseif ($objParts[1] == 'h') {
763 $theVal = $this->objBB[$objParts[0]][1];
764 } elseif ($objParts[1] == 'lineHeight') {
765 $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
766 }
767 $theVal = intval($theVal);
768 }
769 } elseif (floatval($theVal)) {
770 $theVal = floatval($theVal);
771 } else {
772 $theVal = 0;
773 }
774 if ($sign == '-') {
775 $calculatedValue -= $theVal;
776 } elseif ($sign == '+') {
777 $calculatedValue += $theVal;
778 } elseif ($sign == '/' && $theVal) {
779 $calculatedValue = $calculatedValue / $theVal;
780 } elseif ($sign == '*') {
781 $calculatedValue = $calculatedValue * $theVal;
782 } elseif ($sign == '%' && $theVal) {
783 $calculatedValue %= $theVal;
784 }
785 }
786 return round($calculatedValue);
787 }
788
789 /**
790 * Calculates special functions:
791 * + max([10.h], [20.h]) -> gets the maximum of the given values
792 *
793 * @param string $string The raw string with functions to be calculated
794 * @return string The calculated values
795 */
796 protected function calculateFunctions($string) {
797 if (preg_match_all('#max\\(([^)]+)\\)#', $string, $matches)) {
798 foreach ($matches[1] as $index => $maxExpression) {
799 $string = str_replace($matches[0][$index], $this->calculateMaximum($maxExpression), $string);
800 }
801 }
802 return $string;
803 }
804
805 /**
806 * Calculates the maximum of a set of values defined like "[10.h],[20.h],1000"
807 *
808 * @param string $string The string to be used to calculate the maximum (e.g. "[10.h],[20.h],1000")
809 * @return integer The maxium value of the given comma separated and calculated values
810 */
811 protected function calculateMaximum($string) {
812 $parts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->calcOffset($string), TRUE);
813 $maximum = count($parts) ? max($parts) : 0;
814 return $maximum;
815 }
816
817 }
818
819
820 ?>