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