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 /* Hook preprocess gifbuilder conf 00136 * Added by Julle for 3.8.0 00137 * 00138 * Let's you pre-process the gifbuilder configuration. for 00139 * example you can split a string up into lines and render each 00140 * line as TEXT obj, see extension julle_gifbconf 00141 */ 00142 00143 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'])) { 00144 foreach($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_gifbuilder.php']['gifbuilder-ConfPreProcess'] as $_funcRef) { 00145 $_params = $this->setup; 00146 $this->setup = t3lib_div::callUserFunction($_funcRef,$_params,$this); 00147 } 00148 } 00149 00150 // Initializing global Char Range Map 00151 $this->charRangeMap = array(); 00152 if (is_array($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'])) { 00153 foreach($GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'] as $cRMcfgkey => $cRMcfg) { 00154 if (is_array($cRMcfg)) { 00155 00156 // Initializing: 00157 $cRMkey = $GLOBALS['TSFE']->tmpl->setup['_GIFBUILDER.']['charRangeMap.'][substr($cRMcfgkey,0,-1)]; 00158 $this->charRangeMap[$cRMkey] = array(); 00159 $this->charRangeMap[$cRMkey]['charMapConfig'] = $cRMcfg['charMapConfig.']; 00160 $this->charRangeMap[$cRMkey]['cfgKey'] = substr($cRMcfgkey,0,-1); 00161 $this->charRangeMap[$cRMkey]['multiplicator'] = (double)$cRMcfg['fontSizeMultiplicator']; 00162 $this->charRangeMap[$cRMkey]['pixelSpace'] = intval($cRMcfg['pixelSpaceFontSizeRef']); 00163 } 00164 } 00165 } 00166 00167 // Getting sorted list of TypoScript keys from setup. 00168 $sKeyArray=t3lib_TStemplate::sortedKeyList($this->setup); 00169 00170 // Setting the background color, passing it through stdWrap 00171 if ($conf['backColor.'] || $conf['backColor']) { 00172 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00173 $cObj->start($this->data); 00174 $this->setup['backColor'] = trim($cObj->stdWrap($this->setup['backColor'], $this->setup['backColor.'])); 00175 } 00176 if (!$this->setup['backColor']) {$this->setup['backColor']='white';} 00177 00178 // Transparent GIFs 00179 // not working with reduceColors 00180 // there's an option for IM: -transparent colors 00181 if ($conf['transparentColor.'] || $conf['transparentColor']) { 00182 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00183 $cObj->start($this->data); 00184 $this->setup['transparentColor_array'] = explode('|', trim($cObj->stdWrap($this->setup['transparentColor'], $this->setup['transparentColor.']))); 00185 } 00186 00187 // Set default dimensions 00188 if (!$this->setup['XY']) {$this->setup['XY']='120,50';} 00189 00190 00191 // Checking TEXT and IMAGE objects for files. If any errors the objects are cleared. 00192 // The Bounding Box for the objects is stored in an array 00193 foreach($sKeyArray as $theKey) { 00194 $theValue = $this->setup[$theKey]; 00195 00196 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00197 // Swipes through TEXT and IMAGE-objects 00198 switch($theValue) { 00199 case 'TEXT': 00200 if ($this->setup[$theKey.'.'] = $this->checkTextObj($conf)) { 00201 00202 // Adjust font width if max size is set: 00203 if ($this->setup[$theKey.'.']['maxWidth']) { 00204 $this->setup[$theKey.'.']['fontSize'] = $this->fontResize($this->setup[$theKey.'.']); //RTF - this has to be done before calcBBox 00205 } 00206 00207 // Calculate bounding box: 00208 $txtInfo=$this->calcBBox($this->setup[$theKey.'.']); 00209 $this->setup[$theKey.'.']['BBOX'] = $txtInfo; 00210 $this->objBB[$theKey] = $txtInfo; 00211 $this->setup[$theKey.'.']['imgMap'] = 0; 00212 } 00213 break; 00214 case 'IMAGE': 00215 $fileInfo = $this->getResource($conf['file'],$conf['file.']); 00216 if ($fileInfo) { 00217 $this->combinedFileNames[] = ereg_replace('\.[[:alnum:]]+$','',basename($fileInfo[3])); 00218 $this->setup[$theKey.'.']['file'] = $fileInfo[3]; 00219 $this->setup[$theKey.'.']['BBOX'] = $fileInfo; 00220 $this->objBB[$theKey] = $fileInfo; 00221 if ($conf['mask']) { 00222 $maskInfo = $this->getResource($conf['mask'],$conf['mask.']); 00223 if ($maskInfo) { 00224 $this->setup[$theKey.'.']['mask'] = $maskInfo[3]; 00225 } else { 00226 $this->setup[$theKey.'.']['mask'] = ''; 00227 } 00228 } 00229 } else { 00230 unset($this->setup[$theKey.'.']); 00231 } 00232 break; 00233 } 00234 // Checks if disabled is set... (this is also done in menu.php / imgmenu!!) 00235 if ($conf['if.']) { 00236 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00237 $cObj->start($this->data); 00238 00239 if (!$cObj->checkIf($conf['if.'])) { 00240 unset($this->setup[$theKey]); 00241 unset($this->setup[$theKey.'.']); 00242 } 00243 } 00244 } 00245 } 00246 00247 // Calculate offsets on elements 00248 $this->setup['XY'] = $this->calcOffset($this->setup['XY']); 00249 $this->setup['offset'] = $this->calcOffset($this->setup['offset']); 00250 $this->setup['workArea'] = $this->calcOffset($this->setup['workArea']); 00251 00252 foreach ($sKeyArray as $theKey) { 00253 $theValue=$this->setup[$theKey]; 00254 00255 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00256 switch($theValue) { 00257 case 'TEXT': 00258 case 'IMAGE': 00259 if ($this->setup[$theKey.'.']['offset']) { 00260 $this->setup[$theKey.'.']['offset'] = $this->calcOffset($this->setup[$theKey.'.']['offset']); 00261 } 00262 break; 00263 case 'BOX': 00264 if ($this->setup[$theKey.'.']['dimensions']) { 00265 $this->setup[$theKey.'.']['dimensions'] = $this->calcOffset($this->setup[$theKey.'.']['dimensions']); 00266 } 00267 break; 00268 case 'WORKAREA': 00269 if ($this->setup[$theKey.'.']['set']) { 00270 $this->setup[$theKey.'.']['set'] = $this->calcOffset($this->setup[$theKey.'.']['set']); 00271 } 00272 break; 00273 case 'CROP': 00274 if ($this->setup[$theKey.'.']['crop']) { 00275 $this->setup[$theKey.'.']['crop'] = $this->calcOffset($this->setup[$theKey.'.']['crop']); 00276 } 00277 break; 00278 case 'SCALE': 00279 if ($this->setup[$theKey.'.']['width']) { 00280 $this->setup[$theKey.'.']['width'] = $this->calcOffset($this->setup[$theKey.'.']['width']); 00281 } 00282 if ($this->setup[$theKey.'.']['height']) { 00283 $this->setup[$theKey.'.']['height'] = $this->calcOffset($this->setup[$theKey.'.']['height']); 00284 } 00285 break; 00286 } 00287 } 00288 } 00289 // Get trivial data 00290 $XY = t3lib_div::intExplode(',',$this->setup['XY']); 00291 $maxWidth = intval($this->setup['maxWidth']); 00292 $maxHeight = intval($this->setup['maxHeight']); 00293 00294 $XY[0] = t3lib_div::intInRange($XY[0],1, $maxWidth?$maxWidth:2000); 00295 $XY[1] = t3lib_div::intInRange($XY[1],1, $maxHeight?$maxHeight:2000); 00296 $this->XY = $XY; 00297 $this->w = $XY[0]; 00298 $this->h = $XY[1]; 00299 $this->OFFSET = t3lib_div::intExplode(',',$this->setup['offset']); 00300 00301 $this->setWorkArea($this->setup['workArea']); // this sets the workArea 00302 $this->defaultWorkArea = $this->workArea; // this sets the default to the current; 00303 } 00304 } 00305 00314 function gifBuild() { 00315 if ($this->setup) { 00316 $gifFileName = $this->fileName('GB/'); // Relative to PATH_site 00317 if (!@file_exists($gifFileName)) { // File exists 00318 00319 // Create temporary directory if not done: 00320 $this->createTempSubDir('GB/'); 00321 00322 // Create file: 00323 $this->make(); 00324 $this->output($gifFileName); 00325 $this->destroy(); 00326 } 00327 return $gifFileName; 00328 } 00329 } 00330 00342 function make() { 00343 // Get trivial data 00344 $XY = $this->XY; 00345 00346 // Gif-start 00347 $this->im = imagecreate($XY[0],$XY[1]); 00348 $this->w = $XY[0]; 00349 $this->h = $XY[1]; 00350 00351 // backColor is set 00352 $cols=$this->convertColor($this->setup['backColor']); 00353 ImageColorAllocate($this->im, $cols[0],$cols[1],$cols[2]); 00354 00355 // Traverse the GIFBUILDER objects an render each one: 00356 if (is_array($this->setup)) { 00357 $sKeyArray=t3lib_TStemplate::sortedKeyList($this->setup); 00358 foreach($sKeyArray as $theKey) { 00359 $theValue=$this->setup[$theKey]; 00360 00361 if (intval($theKey) && $conf=$this->setup[$theKey.'.']) { 00362 switch($theValue) { 00363 // Images 00364 case 'IMAGE': 00365 if ($conf['mask']) { 00366 $this->maskImageOntoImage($this->im,$conf,$this->workArea); 00367 } else { 00368 $this->copyImageOntoImage($this->im,$conf,$this->workArea); 00369 } 00370 break; 00371 00372 // Text 00373 case 'TEXT': 00374 if (!$conf['hide']) { 00375 if (is_array($conf['shadow.'])) { 00376 $this->makeShadow($this->im,$conf['shadow.'],$this->workArea,$conf); 00377 } 00378 if (is_array($conf['emboss.'])) { 00379 $this->makeEmboss($this->im,$conf['emboss.'],$this->workArea,$conf); 00380 } 00381 if (is_array($conf['outline.'])) { 00382 $this->makeOutline($this->im,$conf['outline.'],$this->workArea,$conf); 00383 } 00384 $conf['imgMap']=1; 00385 $this->makeText($this->im,$conf,$this->workArea); 00386 } 00387 break; 00388 00389 // Text effects: 00390 case 'OUTLINE': 00391 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00392 $this->makeOutline($this->im,$conf,$this->workArea,$txtConf); 00393 } 00394 break; 00395 case 'EMBOSS': 00396 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00397 $this->makeEmboss($this->im,$conf,$this->workArea,$txtConf); 00398 } 00399 break; 00400 case 'SHADOW': 00401 if ($this->setup[$conf['textObjNum']]=='TEXT' && $txtConf=$this->checkTextObj($this->setup[$conf['textObjNum'].'.'])) { 00402 $this->makeShadow($this->im,$conf,$this->workArea,$txtConf); 00403 } 00404 break; 00405 00406 // Other 00407 case 'BOX': 00408 $this->makeBox($this->im,$conf,$this->workArea); 00409 break; 00410 case 'EFFECT': 00411 $this->makeEffect($this->im,$conf); 00412 break; 00413 case 'ADJUST': 00414 $this->adjust($this->im,$conf); 00415 break; 00416 case 'CROP': 00417 $this->crop($this->im,$conf); 00418 break; 00419 case 'SCALE': 00420 $this->scale($this->im,$conf); 00421 break; 00422 case 'WORKAREA': 00423 if ($conf['set']) { 00424 $this->setWorkArea($conf['set']); // this sets the workArea 00425 } 00426 if (isset($conf['clear'])) { 00427 $this->workArea = $this->defaultWorkArea; // this sets the current to the default; 00428 } 00429 break; 00430 } 00431 } 00432 } 00433 } 00434 // Auto transparent background is set 00435 if ($this->setup['transparentBackground']) { 00436 imagecolortransparent($this->im, imagecolorat($this->im, 0, 0)); 00437 } 00438 // TransparentColors are set 00439 if (is_array($this->setup['transparentColor_array'])) { 00440 reset($this->setup['transparentColor_array']); 00441 while(list(,$transparentColor)=each($this->setup['transparentColor_array'])) { 00442 $cols=$this->convertColor($transparentColor); 00443 if ($this->setup['transparentColor.']['closest']) { 00444 $colIndex = ImageColorClosest ($this->im, $cols[0],$cols[1],$cols[2]); 00445 } else { 00446 $colIndex = ImageColorExact ($this->im, $cols[0],$cols[1],$cols[2]); 00447 } 00448 if ($colIndex > -1) { 00449 ImageColorTransparent($this->im, $colIndex); 00450 } else { 00451 ImageColorTransparent($this->im, ImageColorAllocate($this->im, $cols[0],$cols[1],$cols[2])); 00452 } 00453 break; // Originally we thought of letting many colors be defined as transparent, but GDlib seems to accept only one definition. Therefore we break here. Maybe in the future this 'break' will be cancelled if a method of truly defining many transparent colors could be found. 00454 } 00455 } 00456 } 00457 00458 00459 00460 00461 00462 00463 00464 00465 00466 00467 00468 00469 00470 00471 00472 00473 00474 00475 /********************************************* 00476 * 00477 * Various helper functions 00478 * 00479 ********************************************/ 00480 00481 00493 function checkTextObj($conf) { 00494 $conf['fontFile']=$this->checkFile($conf['fontFile']); 00495 if (!$conf['fontFile']){$conf['fontFile']='t3lib/fonts/nimbus.ttf';} 00496 if (!$conf['iterations']){$conf['iterations'] = 1;} 00497 if (!$conf['fontSize']){$conf['fontSize']=12;} 00498 if ($conf['spacing'] || $conf['wordSpacing']) { // If any kind of spacing applys, we cannot use angles!! 00499 $conf['angle']=0; 00500 } 00501 if (!isset($conf['antiAlias'])){$conf['antiAlias']=1;} 00502 $cObj =t3lib_div::makeInstance('tslib_cObj'); 00503 $cObj->start($this->data); 00504 00505 $conf['text']=$cObj->stdWrap($conf['text'],$conf['text.']); 00506 // Strip HTML 00507 if (!$conf['doNotStripHTML']) { 00508 $conf['text'] = strip_tags($conf['text']); 00509 } 00510 $this->combinedTextStrings[] = strip_tags($conf['text']); 00511 00512 // Max length = 100 00513 $tlen = intval($conf['textMaxLength']) ? intval($conf['textMaxLength']) : 100; 00514 $conf['text'] = substr($conf['text'],0,$tlen); 00515 if ((string)$conf['text']!='') { 00516 00517 // Char range map thingie: 00518 $fontBaseName = basename($conf['fontFile']); 00519 if (is_array($this->charRangeMap[$fontBaseName])) { 00520 00521 // Initialize splitRendering array: 00522 if (!is_array($conf['splitRendering.'])) { 00523 $conf['splitRendering.'] = array(); 00524 } 00525 00526 $cfgK = $this->charRangeMap[$fontBaseName]['cfgKey']; 00527 if (!isset($conf['splitRendering.'][$cfgK])) { // Do not impose settings if a splitRendering object already exists: 00528 // Set configuration: 00529 $conf['splitRendering.'][$cfgK] = 'charRange'; 00530 $conf['splitRendering.'][$cfgK.'.'] = $this->charRangeMap[$fontBaseName]['charMapConfig']; 00531 00532 // multiplicator of fontsize: 00533 if ($this->charRangeMap[$fontBaseName]['multiplicator']) { 00534 $conf['splitRendering.'][$cfgK.'.']['fontSize'] = round($conf['fontSize'] * $this->charRangeMap[$fontBaseName]['multiplicator']); 00535 } 00536 // multiplicator of pixelSpace: 00537 if ($this->charRangeMap[$fontBaseName]['pixelSpace']) { 00538 $travKeys = array('xSpaceBefore','xSpaceAfter','ySpaceBefore','ySpaceAfter'); 00539 foreach($travKeys as $pxKey) { 00540 if (isset($conf['splitRendering.'][$cfgK.'.'][$pxKey])) { 00541 $conf['splitRendering.'][$cfgK.'.'][$pxKey] = round($conf['splitRendering.'][$cfgK.'.'][$pxKey] * ($conf['fontSize'] / $this->charRangeMap[$fontBaseName]['pixelSpace'])); 00542 } 00543 } 00544 } 00545 } 00546 } 00547 if (is_array($conf['splitRendering.'])) { 00548 foreach($conf['splitRendering.'] as $key => $value) { 00549 if (is_array($conf['splitRendering.'][$key])) { 00550 if (isset($conf['splitRendering.'][$key]['fontFile'])) { 00551 $conf['splitRendering.'][$key]['fontFile'] = $this->checkFile($conf['splitRendering.'][$key]['fontFile']); 00552 } 00553 } 00554 } 00555 } 00556 00557 return $conf; 00558 } 00559 } 00560 00572 function calcOffset($string) { 00573 $numbers=explode(',',$string); 00574 while(list($key,$val)=each($numbers)) { 00575 $val = trim($val); 00576 if ((string)$val==(string)intval($val)) { 00577 $value[$key]=intval($val); 00578 } else { 00579 $parts= t3lib_div::splitCalc($val,'+-*/%'); 00580 $value[$key]=0; 00581 reset($parts); 00582 while(list(,$part)=each($parts)) { 00583 $theVal = $part[1]; 00584 $sign = $part[0]; 00585 if ((string)intval($theVal)==(string)$theVal) { 00586 $theVal = intval($theVal); 00587 } elseif ('['.substr($theVal,1,-1).']'==$theVal) { 00588 $objParts=explode('.',substr($theVal,1,-1)); 00589 $theVal=0; 00590 if (isset($this->objBB[$objParts[0]])) { 00591 if ($objParts[1]=='w') {$theVal=intval($this->objBB[$objParts[0]][0]);} 00592 if ($objParts[1]=='h') {$theVal=intval($this->objBB[$objParts[0]][1]);} 00593 } 00594 } else { 00595 $theVal =0; 00596 } 00597 if ($sign=='-') {$value[$key]-=$theVal;} 00598 if ($sign=='+') {$value[$key]+=$theVal;} 00599 if ($sign=='/') {if (intval($theVal)) $value[$key]/=intval($theVal);} 00600 if ($sign=='*') {$value[$key]*=$theVal;} 00601 if ($sign=='%') {if (intval($theVal)) $value[$key]%=intval($theVal);} 00602 } 00603 $value[$key]=intval($value[$key]); 00604 } 00605 } 00606 $string = implode(',',$value); 00607 return $string; 00608 } 00609 00621 function getResource($file,$fileArray) { 00622 $fileArray['ext']= $this->gifExtension; 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 ?>