Cleanup: Updated copyright comments
[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 * @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 if ($this->nativeCharset) {
600 $conf['text'] = $this->csConvObj->substr($this->nativeCharset, $conf['text'], 0, $tlen);
601 } else {
602 $conf['text'] = substr($conf['text'], 0 , $tlen);
603 }
604 }
605 if ((string)$conf['text']!='') {
606
607 // Char range map thingie:
608 $fontBaseName = basename($conf['fontFile']);
609 if (is_array($this->charRangeMap[$fontBaseName])) {
610
611 // Initialize splitRendering array:
612 if (!is_array($conf['splitRendering.'])) {
613 $conf['splitRendering.'] = array();
614 }
615
616 $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey'];
617 if (!isset($conf['splitRendering.'][$cfgK])) { // Do not impose settings if a splitRendering object already exists:
618 // Set configuration:
619 $conf['splitRendering.'][$cfgK] = 'charRange';
620 $conf['splitRendering.'][$cfgK.'.'] = $this->charRangeMap[$fontBaseName]['charMapConfig'];
621
622 // multiplicator of fontsize:
623 if ($this->charRangeMap[$fontBaseName]['multiplicator']) {
624 $conf['splitRendering.'][$cfgK.'.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']);
625 }
626 // multiplicator of pixelSpace:
627 if ($this->charRangeMap[$fontBaseName]['pixelSpace']) {
628 $travKeys = array('xSpaceBefore','xSpaceAfter','ySpaceBefore','ySpaceAfter');
629 foreach($travKeys as $pxKey) {
630 if (isset($conf['splitRendering.'][$cfgK.'.'][$pxKey])) {
631 $conf['splitRendering.'][$cfgK.'.'][$pxKey] = round($conf['splitRendering.'][$cfgK.'.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace']));
632 }
633 }
634 }
635 }
636 }
637 if (is_array($conf['splitRendering.'])) {
638 foreach($conf['splitRendering.'] as $key => $value) {
639 if (is_array($conf['splitRendering.'][$key])) {
640 if (isset($conf['splitRendering.'][$key]['fontFile'])) {
641 $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']);
642 }
643 }
644 }
645 }
646
647 return $conf;
648 }
649 }
650
651 /**
652 * Calculation of offset using "splitCalc" and insertion of dimensions from other GIFBUILDER objects.
653 *
654 * Example:
655 * Input: 2+2, 2*3, 123, [10.w]
656 * Output: 4,6,123,45 (provided that the width of object in position 10 was 45 pixels wide)
657 *
658 * @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.
659 * @return string The resolved string with each part (separated by comma) returned separated by comma
660 * @access private
661 */
662 function calcOffset($string) {
663 $value = array();
664 $numbers = t3lib_div::trimExplode(',', $this->calculateFunctions($string));
665
666 foreach ($numbers as $key => $val) {
667 if ((string)$val == (string)intval($val)) {
668 $value[$key] = intval($val);
669 } else {
670 $value[$key] = $this->calculateValue($val);
671 }
672 }
673
674 $string = implode(',', $value);
675 return $string;
676 }
677
678 /**
679 * Returns an "imgResource" creating an instance of the tslib_cObj class and calling tslib_cObj::getImgResource
680 *
681 * @param string Filename value OR the string "GIFBUILDER", see documentation in TSref for the "datatype" called "imgResource"
682 * @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)
683 * @return array Returns an array with file information if an image was returned. Otherwise false.
684 * @access private
685 * @see tslib_cObj::getImgResource()
686 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=315&cHash=63b593a934
687 * @link http://typo3.org/doc.0.html?&tx_extrepmgm_pi1[extUid]=270&tx_extrepmgm_pi1[tocEl]=282&cHash=831a95115d
688 */
689 function getResource($file,$fileArray) {
690 if (!t3lib_div::inList($this->imageFileExt, $fileArray['ext'])) {
691 $fileArray['ext'] = $this->gifExtension;
692 }
693 $cObj =t3lib_div::makeInstance('tslib_cObj');
694 $cObj->start($this->data);
695 return $cObj->getImgResource($file,$fileArray);
696 }
697
698 /**
699 * Returns the reference to a "resource" in TypoScript.
700 *
701 * @param string The resource value.
702 * @return string Returns the relative filepath
703 * @access private
704 * @see t3lib_TStemplate::getFileName()
705 */
706 function checkFile($file) {
707 return $GLOBALS['TSFE']->tmpl->getFileName($file);
708 }
709
710 /**
711 * Calculates the GIFBUILDER output filename/path based on a serialized, hashed value of this->setup
712 *
713 * @param string Filename prefix, eg. "GB_"
714 * @return string The relative filepath (relative to PATH_site)
715 * @access private
716 */
717 function fileName($pre) {
718
719 $meaningfulPrefix = '';
720
721 if ($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']) {
722 $meaningfulPrefix = implode('_', array_merge($this->combinedTextStrings, $this->combinedFileNames));
723 // Convert raw string to a nice ASCII-only string without spaces
724 $meaningfulPrefix = $GLOBALS['TSFE']->csConvObj->specCharsToASCII($GLOBALS['TSFE']->renderCharset, $meaningfulPrefix);
725 $meaningfulPrefix = str_replace(' ', '_', $meaningfulPrefix);
726 $meaningfulPrefix = substr($meaningfulPrefix, 0, intval($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix'])) . '_';
727 }
728
729 // 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.
730 return $this->tempPath .
731 $pre .
732 $meaningfulPrefix .
733 t3lib_div::shortMD5(serialize($this->setup)) .
734 '.' . $this->extension();
735 }
736
737 /**
738 * Returns the file extension used in the filename
739 *
740 * @return string Extension; "jpg" or "gif"/"png"
741 * @access private
742 */
743 function extension() {
744 switch(strtolower($this->setup['format'])) {
745 case 'jpg':
746 case 'jpeg':
747 return 'jpg';
748 break;
749 case 'png':
750 return 'png';
751 break;
752 case 'gif':
753 return 'gif';
754 break;
755 default:
756 return $this->gifExtension;
757 break;
758 }
759 }
760
761 /**
762 * Calculates the value concerning the dimensions of objects.
763 *
764 * @param string $string: The string to be calculated (e.g. "[20.h]+13")
765 * @return integer The calculated value (e.g. "23")
766 * @see calcOffset()
767 */
768 protected function calculateValue($string) {
769 $calculatedValue = 0;
770 $parts = t3lib_div::splitCalc($string, '+-*/%');
771
772 foreach ($parts as $part) {
773 $theVal = $part[1];
774 $sign = $part[0];
775
776 if ((string)intval($theVal) == (string)$theVal) {
777 $theVal = intval($theVal);
778 } elseif ('[' . substr($theVal, 1, -1) . ']' == $theVal) {
779 $objParts = explode('.', substr($theVal, 1, -1));
780 $theVal = 0;
781 if (isset($this->objBB[$objParts[0]])) {
782 if ($objParts[1] == 'w') {
783 $theVal = $this->objBB[$objParts[0]][0];
784 } elseif ($objParts[1] == 'h') {
785 $theVal = $this->objBB[$objParts[0]][1];
786 } elseif ($objParts[1] == 'lineHeight') {
787 $theVal = $this->objBB[$objParts[0]][2]['lineHeight'];
788 }
789 $theVal = intval($theVal);
790 }
791 } elseif (floatval($theVal)) {
792 $theVal = floatval($theVal);
793 } else {
794 $theVal = 0;
795 }
796
797 if ($sign == '-') {
798 $calculatedValue-= $theVal;
799 } elseif ($sign == '+') {
800 $calculatedValue+= $theVal;
801 } elseif ($sign == '/' && $theVal) {
802 $calculatedValue = $calculatedValue / $theVal;
803 } elseif ($sign == '*') {
804 $calculatedValue = $calculatedValue * $theVal;
805 } elseif ($sign == '%' && $theVal) {
806 $calculatedValue%= $theVal;
807 }
808 }
809
810 return round($calculatedValue);
811 }
812
813 /**
814 * Calculates special functions:
815 * + max([10.h], [20.h]) -> gets the maximum of the given values
816 *
817 * @param string $string: The raw string with functions to be calculated
818 * @return string The calculated values
819 */
820 protected function calculateFunctions($string) {
821 if (preg_match_all('#max\(([^)]+)\)#', $string, $matches)) {
822 foreach ($matches[1] as $index => $maxExpression) {
823 $string = str_replace(
824 $matches[0][$index],
825 $this->calculateMaximum(
826 $maxExpression
827 ),
828 $string
829 );
830 }
831 }
832
833 return $string;
834 }
835
836 /**
837 * Calculates the maximum of a set of values defined like "[10.h],[20.h],1000"
838 *
839 * @param string $string: The string to be used to calculate the maximum (e.g. "[10.h],[20.h],1000")
840 * @return integer The maxium value of the given comma separated and calculated values
841 */
842 protected function calculateMaximum($string) {
843 $parts = t3lib_div::trimExplode(',', $this->calcOffset($string), true);
844 $maximum = (count($parts) ? max($parts) : 0);
845 return $maximum;
846 }
847 }
848
849
850 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_gifbuilder.php'])) {
851 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['tslib/class.tslib_gifbuilder.php']);
852 }
853
854 ?>