Documentation TYPO3 par Ameos |
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00102 class tslib_gifBuilder extends t3lib_stdGraphic { 00103 00104 // Internal 00105 var $im = ''; // the main image 00106 var $w = 0; // the image-width 00107 var $h = 0; // the image-height 00108 var $map; // map-data 00109 var $workArea; 00110 var $setup = Array (); // This holds the operational setup for gifbuilder. Basically this is a TypoScript array with properties. 00111 var $combinedTextStrings = array(); // Contains all text strings used on this image 00112 var $combinedFileNames = array(); // Contains all filenames (basename without extension) used on this image 00113 var $data = Array(); // This is the array from which data->field: [key] is fetched. So this is the current record! 00114 var $objBB = Array(); 00115 var $myClassName = 'gifbuilder'; 00116 var $charRangeMap=array(); 00117 00129 function start($conf,$data) { 00130 00131 if (is_array($conf)) { 00132 $this->setup = $conf; 00133 $this->data = $data; 00134 00135 00136 /* Hook preprocess gifbuilder conf 00137 * Added by Julle for 3.8.0 00138 * 00139 * Let's you pre-process the gifbuilder configuration. for 00140 * example you can split a string up into lines and render each 00141 * line as TEXT obj, see extension julle_gifbconf 00142 */ 00143 00144 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'])) { 00145 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] as $_funcRef) { 00146 $_params = $this->setup; 00147 $this->setup = t3lib_div::callUserFunction($_funcRef,$_params,$this); 00148 } 00149 } 00150 00151 // Initializing global Char Range Map 00152 $this->charRangeMap = array(); 00153 if (is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) { 00154 foreach($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) { 00155 if (is_array($cRMcfg)) { 00156 00157 // Initializing: 00158 $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey,0,-1)]; 00159 $this->charRangeMap[$cRMkey] = array(); 00160 $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.']; 00161 $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey,0,-1); 00162 $this->charRangeMap[$cRMkey]['multiplicator'] = (double)$cRMcfg['fontSizeMultiplicator']; 00163 $this->charRangeMap[$cRMkey]['pixelSpace'] = intval($cRMcfg['pixelSpaceFontSizeRef']); 00164 } 00165 } 00166 } 00167 00168 // Getting sorted list of TypoScript keys from setup. 00169 $sKeyArray=t3lib_TStemplate::sortedKeyList($this->setup); 00170 00171 // Setting the background color, passing it through stdWrap 00172 if ($conf['backColor.'] || $conf['backColor']) { 00173 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00174 $cObj->start($this->data); 00175 $this->setup['backColor'] = trim($cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])); 00176 } 00177 if (!$this->setup['backColor']) { $this->setup['backColor']='white'; } 00178 00179 if ($conf['transparentColor.'] || $conf['transparentColor']) { 00180 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00181 $cObj->start($this->data); 00182 $this->setup['transparentColor_array'] = explode('|', trim($cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))); 00183 } 00184 00185 // 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. 00186 // not working with reduceColors and truecolor images 00187 if (($this->setup['transparentBackground'] || is_array($this->setup['transparentColor_array'])) && ($this->gifExtension=='gif' || !$this->png_truecolor || isset($this->setup['reduceColors']))) { 00188 $this->truecolor = false; 00189 } 00190 00191 // Set default dimensions 00192 if (!$this->setup['XY']) {$this->setup['XY']='120,50';} 00193 00194 00195 // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared. 00196 // The Bounding Box for the objects is stored in an array 00197 foreach($sKeyArray as $theKey) { 00198 $theValue = $this->setup[$theKey]; 00199 00200 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00201 // Swipes through TEXT and IMAGE-objects 00202 switch($theValue) { 00203 case 'TEXT': 00204 if ($this->setup[$theKey.'.'] = $this->checkTextObj($conf)) { 00205 00206 // Adjust font width if max size is set: 00207 if ($this->setup[$theKey.'.']['maxWidth']) { 00208 $this->setup[$theKey.'.']['fontSize'] = $this->fontResize($this->setup[$theKey.'.']); //RTF - this has to be done before calcBBox 00209 } 00210 00211 // Calculate bounding box: 00212 $txtInfo=$this->calcBBox($this->setup[$theKey.'.']); 00213 $this->setup[$theKey.'.']['BBOX'] = $txtInfo; 00214 $this->objBB[$theKey] = $txtInfo; 00215 $this->setup[$theKey.'.']['imgMap'] = 0; 00216 } 00217 break; 00218 case 'IMAGE': 00219 $fileInfo = $this->getResource($conf['file'],$conf['file.']); 00220 if ($fileInfo) { 00221 $this->combinedFileNames[] = ereg_replace('\.[[:alnum:]]+$','',basename($fileInfo[3])); 00222 $this->setup[$theKey.'.']['file'] = $fileInfo[3]; 00223 $this->setup[$theKey.'.']['BBOX'] = $fileInfo; 00224 $this->objBB[$theKey] = $fileInfo; 00225 if ($conf['mask']) { 00226 $maskInfo = $this->getResource($conf['mask'],$conf['mask.']); 00227 if ($maskInfo) { 00228 $this->setup[$theKey.'.']['mask'] = $maskInfo[3]; 00229 } else { 00230 $this->setup[$theKey.'.']['mask'] = ''; 00231 } 00232 } 00233 } else { 00234 unset($this->setup[$theKey.'.']); 00235 } 00236 break; 00237 } 00238 // Checks if disabled is set... (this is also done in menu.php / imgmenu!!) 00239 if ($conf['if.']) { 00240 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00241 $cObj->start($this->data); 00242 00243 if (!$cObj->checkIf($conf['if.'])) { 00244 unset($this->setup[$theKey]); 00245 unset($this->setup[$theKey.'.']); 00246 } 00247 } 00248 } 00249 } 00250 00251 // Calculate offsets on elements 00252 $this->setup['XY'] = $this->calcOffset($this->setup['XY']); 00253 $this->setup['offset'] = $this->calcOffset($this->setup['offset']); 00254 $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']); 00255 00256 foreach ($sKeyArray as $theKey) { 00257 $theValue=$this->setup[$theKey]; 00258 00259 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00260 switch($theValue) { 00261 case 'TEXT': 00262 case 'IMAGE': 00263 if ($this->setup[$theKey.'.']['offset']) { 00264 $this->setup[$theKey.'.']['offset'] = $this->calcOffset($this->setup[$theKey.'.']['offset']); 00265 } 00266 break; 00267 case 'BOX': 00268 if ($this->setup[$theKey.'.']['dimensions']) { 00269 $this->setup[$theKey.'.']['dimensions'] = $this->calcOffset($this->setup[$theKey.'.']['dimensions']); 00270 } 00271 break; 00272 case 'WORKAREA': 00273 if ($this->setup[$theKey.'.']['set']) { 00274 $this->setup[$theKey.'.']['set'] = $this->calcOffset($this->setup[$theKey.'.']['set']); 00275 } 00276 break; 00277 case 'CROP': 00278 if ($this->setup[$theKey.'.']['crop']) { 00279 $this->setup[$theKey.'.']['crop'] = $this->calcOffset($this->setup[$theKey.'.']['crop']); 00280 } 00281 break; 00282 case 'SCALE': 00283 if ($this->setup[$theKey.'.']['width']) { 00284 $this->setup[$theKey.'.']['width'] = $this->calcOffset($this->setup[$theKey.'.']['width']); 00285 } 00286 if ($this->setup[$theKey.'.']['height']) { 00287 $this->setup[$theKey.'.']['height'] = $this->calcOffset($this->setup[$theKey.'.']['height']); 00288 } 00289 break; 00290 } 00291 } 00292 } 00293 // Get trivial data 00294 $XY = t3lib_div::intExplode(',',$this->setup['XY']); 00295 $maxWidth = intval($this->setup['maxWidth']); 00296 $maxHeight = intval($this->setup['maxHeight']); 00297 00298 $XY[0] = t3lib_div::intInRange($XY[0],1, $maxWidth?$maxWidth:2000); 00299 $XY[1] = t3lib_div::intInRange($XY[1],1, $maxHeight?$maxHeight:2000); 00300 $this->XY = $XY; 00301 $this->w = $XY[0]; 00302 $this->h = $XY[1]; 00303 $this->OFFSET = t3lib_div::intExplode(',',$this->setup['offset']); 00304 00305 $this->setWorkArea($this->setup['workArea']); // this sets the workArea 00306 $this->defaultWorkArea = $this->workArea; // this sets the default to the current; 00307 } 00308 } 00309 00318 function gifBuild() { 00319 if ($this->setup) { 00320 $gifFileName = $this->fileName('GB/'); // Relative to PATH_site 00321 if (!@file_exists($gifFileName)) { // File exists 00322 00323 // Create temporary directory if not done: 00324 $this->createTempSubDir('GB/'); 00325 00326 // Create file: 00327 $this->make(); 00328 $this->output($gifFileName); 00329 $this->destroy(); 00330 } 00331 return $gifFileName; 00332 } 00333 } 00334 00346 function make() { 00347 // Get trivial data 00348 $XY = $this->XY; 00349 00350 // Gif-start 00351 $this->im = $this->imagecreate($XY[0],$XY[1]); 00352 $this->w = $XY[0]; 00353 $this->h = $XY[1]; 00354 00355 // backColor is set 00356 $BGcols = $this->convertColor($this->setup['backColor']); 00357 $Bcolor = ImageColorAllocate($this->im, $BGcols[0],$BGcols[1],$BGcols[2]); 00358 ImageFilledRectangle($this->im, 0, 0, $XY[0], $XY[1], $Bcolor); 00359 00360 // Traverse the GIFBUILDER objects an render each one: 00361 if (is_array($this->setup)) { 00362 $sKeyArray=t3lib_TStemplate::sortedKeyList($this->setup); 00363 foreach($sKeyArray as $theKey) { 00364 $theValue=$this->setup[$theKey]; 00365 00366 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00367 switch($theValue) { 00368 // Images 00369 case 'IMAGE': 00370 if ($conf['mask']) { 00371 $this->maskImageOntoImage($this->im,$conf,$this->workArea); 00372 } else { 00373 $this->copyImageOntoImage($this->im,$conf,$this->workArea); 00374 } 00375 break; 00376 00377 // Text 00378 case 'TEXT': 00379 if (!$conf['hide']) { 00380 if (is_array($conf['shadow.'])) { 00381 $this->makeShadow($this->im,$conf['shadow.'],$this->workArea,$conf); 00382 } 00383 if (is_array($conf['emboss.'])) { 00384 $this->makeEmboss($this->im,$conf['emboss.'],$this->workArea,$conf); 00385 } 00386 if (is_array($conf['outline.'])) { 00387 $this->makeOutline($this->im,$conf['outline.'],$this->workArea,$conf); 00388 } 00389 $conf['imgMap']=1; 00390 $this->makeText($this->im,$conf,$this->workArea); 00391 } 00392 break; 00393 00394 // Text effects: 00395 case 'OUTLINE': 00396 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00397 $this->makeOutline($this->im,$conf,$this->workArea,$txtConf); 00398 } 00399 break; 00400 case 'EMBOSS': 00401 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00402 $this->makeEmboss($this->im,$conf,$this->workArea,$txtConf); 00403 } 00404 break; 00405 case 'SHADOW': 00406 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00407 $this->makeShadow($this->im,$conf,$this->workArea,$txtConf); 00408 } 00409 break; 00410 00411 // Other 00412 case 'BOX': 00413 $this->makeBox($this->im,$conf,$this->workArea); 00414 break; 00415 case 'EFFECT': 00416 $this->makeEffect($this->im,$conf); 00417 break; 00418 case 'ADJUST': 00419 $this->adjust($this->im,$conf); 00420 break; 00421 case 'CROP': 00422 $this->crop($this->im,$conf); 00423 break; 00424 case 'SCALE': 00425 $this->scale($this->im,$conf); 00426 break; 00427 case 'WORKAREA': 00428 if ($conf['set']) { 00429 $this->setWorkArea($conf['set']); // this sets the workArea 00430 } 00431 if (isset($conf['clear'])) { 00432 $this->workArea = $this->defaultWorkArea; // this sets the current to the default; 00433 } 00434 break; 00435 } 00436 } 00437 } 00438 } 00439 00440 00441 if ($this->setup['transparentBackground']) { 00442 // Auto transparent background is set 00443 $Bcolor = ImageColorExact($this->im, $BGcols[0],$BGcols[1],$BGcols[2]); 00444 imagecolortransparent($this->im, $Bcolor); 00445 } elseif (is_array($this->setup['transparentColor_array'])) { 00446 // 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. 00447 $Tcolor = $this->unifyColors($this->im, $this->setup['transparentColor_array'], intval($this->setup['transparentColor.']['closest'])); 00448 if ($Tcolor>=0) { 00449 imagecolortransparent($this->im, $Tcolor); 00450 } 00451 } 00452 00453 } 00454 00455 00456 00457 00458 00459 00460 00461 00462 00463 00464 00465 00466 00467 00468 00469 00470 00471 00472 /********************************************* 00473 * 00474 * Various helper functions 00475 * 00476 ********************************************/ 00477 00478 00490 function checkTextObj($conf) { 00491 $conf['fontFile']=$this->checkFile($conf['fontFile']); 00492 if (!$conf['fontFile']){$conf['fontFile']='t3lib/fonts/nimbus.ttf';} 00493 if (!$conf['iterations']){$conf['iterations'] = 1;} 00494 if (!$conf['fontSize']){$conf['fontSize']=12;} 00495 if ($conf['spacing'] || $conf['wordSpacing']) { // If any kind of spacing applys, we cannot use angles!! 00496 $conf['angle']=0; 00497 } 00498 if (!isset($conf['antiAlias'])){$conf['antiAlias']=1;} 00499 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00500 $cObj->start($this->data); 00501 00502 $conf['fontColor'] = trim($cObj->stdWrap($conf['fontColor'], $conf['fontColor.'])); 00503 $conf['text']=$cObj->stdWrap($conf['text'],$conf['text.']); 00504 // Strip HTML 00505 if (!$conf['doNotStripHTML']) { 00506 $conf['text'] = strip_tags($conf['text']); 00507 } 00508 $this->combinedTextStrings[] = strip_tags($conf['text']); 00509 00510 // Max length = 100 00511 $tlen = intval($conf['textMaxLength']) ? intval($conf['textMaxLength']) : 100; 00512 $conf['text'] = substr($conf['text'],0,$tlen); 00513 if ((string)$conf['text']!='') { 00514 00515 // Char range map thingie: 00516 $fontBaseName = basename($conf['fontFile']); 00517 if (is_array($this->charRangeMap[$fontBaseName])) { 00518 00519 // Initialize splitRendering array: 00520 if (!is_array($conf['splitRendering.'])) { 00521 $conf['splitRendering.'] = array(); 00522 } 00523 00524 $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey']; 00525 if (!isset($conf['splitRendering.'][$cfgK])) { // Do not impose settings if a splitRendering object already exists: 00526 // Set configuration: 00527 $conf['splitRendering.'][$cfgK] = 'charRange'; 00528 $conf['splitRendering.'][$cfgK.'.'] = $this->charRangeMap[$fontBaseName]['charMapConfig']; 00529 00530 // multiplicator of fontsize: 00531 if ($this->charRangeMap[$fontBaseName]['multiplicator']) { 00532 $conf['splitRendering.'][$cfgK.'.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']); 00533 } 00534 // multiplicator of pixelSpace: 00535 if ($this->charRangeMap[$fontBaseName]['pixelSpace']) { 00536 $travKeys = array('xSpaceBefore','xSpaceAfter','ySpaceBefore','ySpaceAfter'); 00537 foreach($travKeys as $pxKey) { 00538 if (isset($conf['splitRendering.'][$cfgK.'.'][$pxKey])) { 00539 $conf['splitRendering.'][$cfgK.'.'][$pxKey] = round($conf['splitRendering.'][$cfgK.'.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace'])); 00540 } 00541 } 00542 } 00543 } 00544 } 00545 if (is_array($conf['splitRendering.'])) { 00546 foreach($conf['splitRendering.'] as $key => $value) { 00547 if (is_array($conf['splitRendering.'][$key])) { 00548 if (isset($conf['splitRendering.'][$key]['fontFile'])) { 00549 $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']); 00550 } 00551 } 00552 } 00553 } 00554 00555 return $conf; 00556 } 00557 } 00558 00570 function calcOffset($string) { 00571 $numbers=explode(',',$string); 00572 while(list($key,$val)=each($numbers)) { 00573 $val = trim($val); 00574 if ((string)$val==(string)intval($val)) { 00575 $value[$key]=intval($val); 00576 } else { 00577 $parts= t3lib_div::splitCalc($val,'+-*/%'); 00578 $value[$key]=0; 00579 reset($parts); 00580 while(list(,$part)=each($parts)) { 00581 $theVal = $part[1]; 00582 $sign = $part[0]; 00583 if ((string)intval($theVal)==(string)$theVal) { 00584 $theVal = intval($theVal); 00585 } elseif ('['.substr($theVal,1,-1).']'==$theVal) { 00586 $objParts=explode('.',substr($theVal,1,-1)); 00587 $theVal=0; 00588 if (isset($this->objBB[$objParts[0]])) { 00589 if ($objParts[1]=='w') {$theVal=intval($this->objBB[$objParts[0]][0]);} 00590 if ($objParts[1]=='h') {$theVal=intval($this->objBB[$objParts[0]][1]);} 00591 } 00592 } else { 00593 $theVal =0; 00594 } 00595 if ($sign=='-') {$value[$key]-=$theVal;} 00596 if ($sign=='+') {$value[$key]+=$theVal;} 00597 if ($sign=='/') {if (intval($theVal)) $value[$key]/=intval($theVal);} 00598 if ($sign=='*') {$value[$key]*=$theVal;} 00599 if ($sign=='%') {if (intval($theVal)) $value[$key]%=intval($theVal);} 00600 } 00601 $value[$key]=intval($value[$key]); 00602 } 00603 } 00604 $string = implode(',',$value); 00605 return $string; 00606 } 00607 00619 function getResource($file,$fileArray) { 00620 if (!t3lib_div::inList($this->imageFileExt, $fileArray['ext'])) { 00621 $fileArray['ext'] = $this->gifExtension; 00622 } 00623 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00624 $cObj->start($this->data); 00625 return $cObj->getImgResource($file,$fileArray); 00626 } 00627 00636 function checkFile($file) { 00637 return $GLOBALS['TSFE']->tmpl->getFileName($file); 00638 } 00639 00647 function fileName($pre) { 00648 00649 // 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. 00650 return $this->tempPath. 00651 $pre. 00652 ($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix'] ? $GLOBALS['TSFE']->fileNameASCIIPrefix(implode('_',array_merge($this->combinedTextStrings,$this->combinedFileNames)),intval($GLOBALS['TSFE']->config['config']['meaningfulTempFilePrefix']),'_') : ''). 00653 t3lib_div::shortMD5(serialize($this->setup)). 00654 '.'.$this->extension(); 00655 } 00656 00663 function extension() { 00664 switch(strtolower($this->setup['format'])) { 00665 case 'jpg': 00666 case 'jpeg': 00667 return 'jpg'; 00668 break; 00669 default: 00670 return $this->gifExtension; 00671 break; 00672 } 00673 } 00674 } 00675 00676 00677 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_gifbuilder.php']) { 00678 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_gifbuilder.php']); 00679 } 00680 00681 ?>