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