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