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