| [ Index ] |
|
Code source de Typo3 4.1.3 |
1 <?php 2 /*************************************************************** 3 * Copyright notice 4 * 5 * (c) 1999-2007 Kasper Skaarhoj (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 * Standard graphical functions 29 * 30 * $Id: class.t3lib_stdgraphic.php 2572 2007-10-16 16:07:41Z mundaun $ 31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj 32 * 33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 34 */ 35 /** 36 * [CLASS/FUNCTION INDEX of SCRIPT] 37 * 38 * 39 * 40 * 155: class t3lib_stdGraphic 41 * 236: function init() 42 * 43 * SECTION: Layering images / "IMAGE" GIFBUILDER object 44 * 366: function maskImageOntoImage(&$im,$conf,$workArea) 45 * 436: function copyImageOntoImage(&$im,$conf,$workArea) 46 * 458: function copyGifOntoGif(&$im,$cpImg,$conf,$workArea) 47 * 537: function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) 48 * 49 * SECTION: Text / "TEXT" GIFBUILDER object 50 * 587: function makeText(&$im,$conf,$workArea) 51 * 707: function txtPosition($conf,$workArea,$BB) 52 * 761: function calcBBox($conf) 53 * 820: function addToMap($cords,$conf) 54 * 843: function calcTextCordsForMap($cords,$offset, $conf) 55 * 878: function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1) 56 * 915: function fontResize($conf) 57 * 958: function ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1) 58 * 1005: function ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering,$sF=1) 59 * 1058: function splitString($string,$splitRendering,$fontSize,$fontFile) 60 * 1208: function calcWordSpacing($conf, $scaleFactor=1) 61 * 1227: function getTextScalFactor($conf) 62 * 63 * SECTION: Other GIFBUILDER objects related to TEXT 64 * 1262: function makeOutline(&$im,$conf,$workArea,$txtConf) 65 * 1291: function circleOffset($distance, $iterations) 66 * 1315: function makeEmboss(&$im,$conf,$workArea,$txtConf) 67 * 1337: function makeShadow(&$im,$conf,$workArea,$txtConf) 68 * 69 * SECTION: Other GIFBUILDER objects 70 * 1469: function makeBox(&$im,$conf,$workArea) 71 * 1491: function makeEffect(&$im, $conf) 72 * 1506: function IMparams($setup) 73 * 1589: function adjust(&$im, $conf) 74 * 1621: function crop(&$im,$conf) 75 * 1652: function scale(&$im,$conf) 76 * 1684: function setWorkArea($workArea) 77 * 78 * SECTION: Adjustment functions 79 * 1725: function autolevels(&$im) 80 * 1756: function outputLevels(&$im,$low,$high,$swap='') 81 * 1788: function inputLevels(&$im,$low,$high,$swap='') 82 * 1819: function reduceColors(&$im,$limit, $cols) 83 * 1832: function IMreduceColors($file, $cols) 84 * 85 * SECTION: GIFBUILDER Helper functions 86 * 1875: function prependAbsolutePath($fontFile) 87 * 1889: function v5_sharpen($factor) 88 * 1908: function v5_blur($factor) 89 * 1925: function randomName() 90 * 1938: function applyOffset($cords,$OFFSET) 91 * 1951: function convertColor($string) 92 * 2001: function recodeString($string) 93 * 2023: function singleChars($theText,$returnUnicodeNumber=FALSE) 94 * 2046: function objPosition($conf,$workArea,$BB) 95 * 96 * SECTION: Scaling, Dimensions of images 97 * 2125: function imageMagickConvert($imagefile,$newExt='',$w='',$h='',$params='',$frame='',$options='',$mustCreate=0) 98 * 2238: function getImageDimensions($imageFile) 99 * 2266: function cacheImageDimensions($identifyResult) 100 * 2298: function getCachedImageDimensions($imageFile) 101 * 2332: function getImageScale($info,$w,$h,$options) 102 * 2438: function file_exists_typo3temp_file($output,$orig='') 103 * 104 * SECTION: ImageMagick API functions 105 * 2499: function imageMagickIdentify($imagefile) 106 * 2534: function imageMagickExec($input,$output,$params) 107 * 2557: function combineExec($input,$overlay,$mask,$output, $handleNegation = false) 108 * 2588: function wrapFileName($inputName) 109 * 110 * SECTION: Various IO functions 111 * 2629: function checkFile($file) 112 * 2643: function createTempSubDir($dirName) 113 * 2665: function applyImageMagickToPHPGif(&$im, $command) 114 * 2691: function gif_or_jpg($type,$w,$h) 115 * 2708: function output($file) 116 * 2748: function destroy() 117 * 2758: function imgTag ($imgInfo) 118 * 2770: function ImageWrite($destImg, $theImage) 119 * 2808: function imageGif($destImg, $theImage) 120 * 2820: function imageCreateFromGif($sourceImg) 121 * 2831: function imageCreateFromFile($sourceImg) 122 * 2870: function imagecreate($w, $h) 123 * 2885: function hexColor($col) 124 * 2903: function unifyColors(&$img, $colArr, $closest = false) 125 * 126 * TOTAL FUNCTIONS: 66 127 * (This index is automatically created/updated by the extension "extdeveval") 128 * 129 */ 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 /** 147 * Class contains a bunch of cool functions for manipulating graphics with GDlib/Freetype and ImageMagick 148 * VERY OFTEN used with gifbuilder that extends this class and provides a TypoScript API to using these functions 149 * 150 * @author Kasper Skaarhoj <kasperYYYY@typo3.com> 151 * @package TYPO3 152 * @subpackage t3lib 153 * @see tslib_gifBuilder 154 */ 155 class t3lib_stdGraphic { 156 157 // Internal configuration, set in init() 158 var $combineScript = 'combine'; // The ImageMagick filename used for combining two images. This name changed during the versions. 159 var $noFramePrepended=0; // If set, there is no frame pointer prepended to the filenames. 160 var $GD2=0; // Set, if the GDlib used is version 2. 161 var $imagecopyresized_fix=0; // If set, imagecopyresized will not be called directly. For GD2 (some PHP installs?) 162 var $gifExtension = 'gif'; // This should be changed to 'png' if you want this class to read/make PNG-files instead! 163 var $gdlibExtensions = ''; // File formats supported by gdlib. This variable get's filled in "init" method 164 var $truecolor = true; // Internal variable which get's used to determine wheter GDlib should use function truecolor pendants 165 var $png_truecolor = false; // Set to true if generated png's should be truecolor by default 166 var $truecolorColors = 0xffffff; // 16777216 Colors is the maximum value for PNG, JPEG truecolor images (24-bit, 8-bit / Channel) 167 var $TTFLocaleConv = ''; // Used to recode input to TTF-functions for other charsets. 168 var $enable_typo3temp_db_tracking = 0; // If set, then all files in typo3temp will be logged in a database table. In addition to being a log of the files with original filenames, it also serves to secure that the same image is not rendered simultaneously by two different processes. 169 var $imageFileExt = 'gif,jpg,jpeg,png,tif,bmp,tga,pcx,ai,pdf'; // Commalist of file extensions perceived as images by TYPO3. List should be set to 'gif,png,jpeg,jpg' if IM is not available. Lowercase and no spaces between! 170 var $webImageExt = 'gif,jpg,jpeg,png'; // Commalist of web image extensions (can be shown by a webbrowser) 171 var $maskNegate = ''; // Will be ' -negate' if ImageMagick ver 5.2+. See init(); 172 var $NO_IM_EFFECTS = ''; 173 var $cmds = Array ( 174 'jpg' => '', 175 'jpeg' => '', 176 'gif' => '-colors 64', 177 'png' => '-colors 64' 178 ); 179 var $NO_IMAGE_MAGICK = ''; 180 var $V5_EFFECTS = 0; 181 var $im_version_4 = 0; 182 var $mayScaleUp = 1; 183 184 // Variables for testing, alternative usage etc. 185 var $filenamePrefix=''; // Filename prefix for images scaled in imageMagickConvert() 186 var $imageMagickConvert_forceFileNameBody=''; // Forcing the output filename of imageMagickConvert() to this value. However after calling imageMagickConvert() it will be set blank again. 187 var $dontCheckForExistingTempFile = 0; // This flag should always be false. If set true, imageMagickConvert will always write a new file to the tempdir! Used for debugging. 188 var $dontCompress=0; // Prevents imageMagickConvert() from compressing the gif-files with t3lib_div::gif_compress() 189 var $dontUnlinkTempFiles=0; // For debugging ONLY! 190 var $alternativeOutputKey=''; // For debugging only. Filenames will not be based on mtime and only filename (not path) will be used. This key is also included in the hash of the filename... 191 192 // Internal: 193 var $IM_commands = Array(); // All ImageMagick commands executed is stored in this array for tracking. Used by the Install Tools Image section 194 var $workArea = Array(); 195 196 // Constants: 197 var $tempPath = 'typo3temp/'; // The temp-directory where to store the files. Normally relative to PATH_site but is allowed to be the absolute path AS LONG AS it is a subdir to PATH_site. 198 var $absPrefix = ''; // Prefix for relative paths. Used in "show_item.php" script. Is prefixed the output file name IN imageMagickConvert() 199 var $scalecmd = '-geometry'; // ImageMagick scaling command; "-geometry" eller "-sample". Used in makeText() and imageMagickConvert() 200 var $im5fx_blurSteps='1x2,2x2,3x2,4x3,5x3,5x4,6x4,7x5,8x5,9x5'; // Used by v5_blur() to simulate 10 continuous steps of blurring 201 var $im5fx_sharpenSteps='1x2,2x2,3x2,2x3,3x3,4x3,3x4,4x4,4x5,5x5'; // Used by v5_sharpen() to simulate 10 continuous steps of sharpening. 202 var $pixelLimitGif = 10000; // This is the limit for the number of pixels in an image before it will be rendered as JPG instead of GIF/PNG 203 var $colMap = Array ( // Array mapping HTML color names to RGB values. 204 'aqua' => Array(0,255,255), 205 'black' => Array(0,0,0), 206 'blue' => Array(0,0,255), 207 'fuchsia' => Array(255,0,255), 208 'gray' => Array(128,128,128), 209 'green' => Array(0,128,0), 210 'lime' => Array(0,255,0), 211 'maroon' => Array(128,0,0), 212 'navy' => Array(0,0,128), 213 'olive' => Array(128,128,0), 214 'purple' => Array(128,0,128), 215 'red' => Array(255,0,0), 216 'silver' => Array(192,192,192), 217 'teal' => Array(0,128,128), 218 'yellow' => Array(255,255,0), 219 'white' => Array(255,255,255) 220 ); 221 222 // Charset conversion object: 223 var $csConvObj; 224 var $nativeCharset=''; // Is set to the native character set of the input strings. 225 226 227 228 229 230 /** 231 * Init function. Must always call this when using the class. 232 * This function will read the configuration information from $GLOBALS['TYPO3_CONF_VARS']['GFX'] can set some values in internal variables. 233 * 234 * @return void 235 */ 236 function init() { 237 $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX']; 238 239 if (function_exists('imagecreatefromjpeg')&&function_exists('imagejpeg')) { 240 $this->gdlibExtensions .= ',jpg,jpeg'; 241 } 242 if (function_exists('imagecreatefrompng')&&function_exists('imagepng')) { 243 $this->gdlibExtensions .= ',png'; 244 } 245 if (function_exists('imagecreatefromgif')&&function_exists('imagegif')) { 246 $this->gdlibExtensions .= ',gif'; 247 } 248 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['png_truecolor']) { 249 $this->png_truecolor = true; 250 } 251 if (!$gfxConf['gdlib_2'] || !function_exists('imagecreatetruecolor')) { 252 $this->truecolor = false; 253 } 254 if (!$gfxConf['im_version_5']) { 255 $this->im_version_4 = true; 256 } 257 258 // When GIFBUILDER gets used in truecolor mode (GD2 required) 259 if ($this->truecolor) { 260 if ($this->png_truecolor) { 261 $this->cmds['png'] = ''; // No colors parameter if we generate truecolor images. 262 } 263 $this->cmds['gif'] = ''; // No colors parameter if we generate truecolor images. 264 } 265 266 // Setting default JPG parameters: 267 $this->jpegQuality = t3lib_div::intInRange($gfxConf['jpg_quality'], 10, 100, 75); 268 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -sharpen 50 -quality '.$this->jpegQuality; 269 270 if ($gfxConf['im_combine_filename']) $this->combineScript=$gfxConf['im_combine_filename']; 271 if ($gfxConf['im_noFramePrepended']) $this->noFramePrepended=1; 272 273 if ($gfxConf['gdlib_2']) { 274 $this->GD2 = 1; 275 $this->imagecopyresized_fix = $gfxConf['gdlib_2']==='no_imagecopyresized_fix' ? 0 : 1; 276 } 277 if ($gfxConf['gdlib_png']) { 278 $this->gifExtension='png'; 279 } 280 if ($gfxConf['TTFLocaleConv']) { 281 $this->TTFLocaleConv = $gfxConf['TTFLocaleConv']; 282 } 283 if ($gfxConf['enable_typo3temp_db_tracking']) { 284 $this->enable_typo3temp_db_tracking = $gfxConf['enable_typo3temp_db_tracking']; 285 } 286 287 $this->imageFileExt = $gfxConf['imagefile_ext']; 288 289 // This should be set if ImageMagick ver. 5+ is used. 290 if ($gfxConf['im_negate_mask']) { 291 // Boolean. Indicates if the mask images should be inverted first. 292 // This depends of the ImageMagick version. Below ver. 5.1 this should be false. 293 // Above ImageMagick version 5.2+ it should be true. 294 // Just set the flag if the masks works opposite the intension! 295 $this->maskNegate = ' -negate'; 296 } 297 if ($gfxConf['im_no_effects']) { 298 // Boolean. This is necessary if using ImageMagick 5+. 299 // Approved version for using effects is version 4.2.9. 300 // Effects in Imagemagick 5+ tends to render very slowly!! 301 // - therefore must be disabled in order not to perform sharpen, blurring and such. 302 $this->NO_IM_EFFECTS = 1; 303 304 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -quality '.$this->jpegQuality; 305 } 306 // ... but if 'im_v5effects' is set, don't care about 'im_no_effects' 307 if ($gfxConf['im_v5effects']) { 308 $this->NO_IM_EFFECTS = 0; 309 $this->V5_EFFECTS = 1; 310 311 if ($gfxConf['im_v5effects']>0) { 312 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -quality '.intval($gfxConf['jpg_quality']).$this->v5_sharpen(10); 313 } 314 } 315 316 if (!$gfxConf['im']) { 317 $this->NO_IMAGE_MAGICK = 1; 318 } 319 // Secures that images are not scaled up. 320 if ($gfxConf['im_noScaleUp']) { 321 $this->mayScaleUp=0; 322 } 323 324 if (TYPO3_MODE=='FE') { 325 $this->csConvObj = &$GLOBALS['TSFE']->csConvObj; 326 } elseif(is_object($GLOBALS['LANG'])) { // BE assumed: 327 $this->csConvObj = &$GLOBALS['LANG']->csConvObj; 328 } else { // The object may not exist yet, so we need to create it now. Happens in the Install Tool for example. 329 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs'); 330 } 331 $this->nativeCharset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']; 332 } 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 /************************************************* 350 * 351 * Layering images / "IMAGE" GIFBUILDER object 352 * 353 *************************************************/ 354 355 /** 356 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is true. 357 * It reads the two images defined by $conf['file'] and $conf['mask'] and copies the $conf['file'] onto the input image pointer image using the $conf['mask'] as a grayscale mask 358 * The operation involves ImageMagick for combining. 359 * 360 * @param pointer GDlib image pointer 361 * @param array TypoScript array with configuration for the GIFBUILDER object. 362 * @param array The current working area coordinates. 363 * @return void 364 * @see tslib_gifBuilder::make() 365 */ 366 function maskImageOntoImage(&$im,$conf,$workArea) { 367 if ($conf['file'] && $conf['mask']) { 368 $imgInf = pathinfo($conf['file']); 369 $imgExt = strtolower($imgInf['extension']); 370 if (!t3lib_div::inList($this->gdlibExtensions, $imgExt)) { 371 $BBimage = $this->imageMagickConvert($conf['file'],$this->gifExtension,'','','','',''); 372 } else { 373 $BBimage = $this->getImageDimensions($conf['file']); 374 } 375 $maskInf = pathinfo($conf['mask']); 376 $maskExt = strtolower($maskInf['extension']); 377 if (!t3lib_div::inList($this->gdlibExtensions, $maskExt)) { 378 $BBmask = $this->imageMagickConvert($conf['mask'],$this->gifExtension,'','','','',''); 379 } else { 380 $BBmask = $this->getImageDimensions($conf['mask']); 381 } 382 if ($BBimage && $BBmask) { 383 $w = imagesx($im); 384 $h = imagesy($im); 385 $tmpStr = $this->randomName(); 386 $theImage = $tmpStr.'_img.'.$this->gifExtension; 387 $theDest = $tmpStr.'_dest.'.$this->gifExtension; 388 $theMask = $tmpStr.'_mask.'.$this->gifExtension; 389 // prepare overlay image 390 $cpImg = $this->imageCreateFromFile($BBimage[3]); 391 $destImg = $this->imagecreate($w,$h); 392 $Bcolor = ImageColorAllocate($destImg, 0,0,0); 393 ImageFilledRectangle($destImg, 0, 0, $w, $h, $Bcolor); 394 $this->copyGifOntoGif($destImg,$cpImg,$conf,$workArea); 395 $this->ImageWrite($destImg, $theImage); 396 imageDestroy($cpImg); 397 imageDestroy($destImg); 398 // prepare mask image 399 $cpImg = $this->imageCreateFromFile($BBmask[3]); 400 $destImg = $this->imagecreate($w,$h); 401 $Bcolor = ImageColorAllocate($destImg, 0, 0, 0); 402 ImageFilledRectangle($destImg, 0, 0, $w, $h, $Bcolor); 403 $this->copyGifOntoGif($destImg,$cpImg,$conf,$workArea); 404 $this->ImageWrite($destImg, $theMask); 405 imageDestroy($cpImg); 406 imageDestroy($destImg); 407 // mask the images 408 $this->ImageWrite($im, $theDest); 409 410 $this->combineExec($theDest,$theImage,$theMask,$theDest, true); // Let combineExec handle maskNegation 411 412 $backIm = $this->imageCreateFromFile($theDest); // The main image is loaded again... 413 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 414 ImageColorTransparent($backIm,-1); 415 $im = $backIm; 416 } 417 // unlink files from process 418 if (!$this->dontUnlinkTempFiles) { 419 unlink($theDest); 420 unlink($theImage); 421 unlink($theMask); 422 } 423 } 424 } 425 } 426 427 /** 428 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is false (using only $conf['file']) 429 * 430 * @param pointer GDlib image pointer 431 * @param array TypoScript array with configuration for the GIFBUILDER object. 432 * @param array The current working area coordinates. 433 * @return void 434 * @see tslib_gifBuilder::make(), maskImageOntoImage() 435 */ 436 function copyImageOntoImage(&$im,$conf,$workArea) { 437 if ($conf['file']) { 438 if (!t3lib_div::inList($this->gdlibExtensions, $conf['BBOX'][2])) { 439 $conf['BBOX']=$this->imageMagickConvert($conf['BBOX'][3],$this->gifExtension,'','','','',''); 440 $conf['file']=$conf['BBOX'][3]; 441 } 442 $cpImg = $this->imageCreateFromFile($conf['file']); 443 $this->copyGifOntoGif($im,$cpImg,$conf,$workArea); 444 imageDestroy($cpImg); 445 } 446 } 447 448 /** 449 * Copies two GDlib image pointers onto each other, using TypoScript configuration from $conf and the input $workArea definition. 450 * 451 * @param pointer GDlib image pointer, destination (bottom image) 452 * @param pointer GDlib image pointer, source (top image) 453 * @param array TypoScript array with the properties for the IMAGE GIFBUILDER object. Only used for the "tile" property value. 454 * @param array Work area 455 * @return void Works on the $im image pointer 456 * @access private 457 */ 458 function copyGifOntoGif(&$im,$cpImg,$conf,$workArea) { 459 $cpW = imagesx($cpImg); 460 $cpH = imagesy($cpImg); 461 $tile = t3lib_div::intExplode(',',$conf['tile']); 462 $tile[0] = t3lib_div::intInRange($tile[0],1,20); 463 $tile[1] = t3lib_div::intInRange($tile[1],1,20); 464 $cpOff = $this->objPosition($conf,$workArea,Array($cpW*$tile[0],$cpH*$tile[1])); 465 466 for ($xt=0;$xt<$tile[0];$xt++) { 467 $Xstart=$cpOff[0]+$cpW*$xt; 468 if ($Xstart+$cpW > $workArea[0]) { // if this image is inside of the workArea, then go on 469 // X: 470 if ($Xstart < $workArea[0]) { 471 $cpImgCutX = $workArea[0]-$Xstart; 472 $Xstart = $workArea[0]; 473 } else { 474 $cpImgCutX = 0; 475 } 476 $w = $cpW-$cpImgCutX; 477 if ($Xstart > $workArea[0]+$workArea[2]-$w) { 478 $w = $workArea[0]+$workArea[2]-$Xstart; 479 } 480 if ($Xstart < $workArea[0]+$workArea[2]) { // if this image is inside of the workArea, then go on 481 // Y: 482 for ($yt=0;$yt<$tile[1];$yt++) { 483 $Ystart=$cpOff[1]+$cpH*$yt; 484 if ($Ystart+$cpH > $workArea[1]) { // if this image is inside of the workArea, then go on 485 if ($Ystart < $workArea[1]) { 486 $cpImgCutY = $workArea[1]-$Ystart; 487 $Ystart = $workArea[1]; 488 } else { 489 $cpImgCutY = 0; 490 } 491 $h = $cpH-$cpImgCutY; 492 if ($Ystart > $workArea[1]+$workArea[3]-$h) { 493 $h = $workArea[1]+$workArea[3]-$Ystart; 494 } 495 if ($Ystart < $workArea[1]+$workArea[3]) { // if this image is inside of the workArea, then go on 496 $this->imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); 497 } 498 } 499 } // Y: 500 } 501 } 502 } 503 } 504 505 /** 506 * Alternative function for using the similar PHP function imagecopyresized(). Used for GD2 only. 507 * 508 * OK, the reason for this stupid fix is the following story: 509 * GD1.x was capable of copying two images together and combining their palettes! GD2 is apparently not. 510 * With GD2 only the palette of the dest-image is used which mostly results in totally black images when trying to 511 * copy a color-ful image onto the destination. 512 * The GD2-fix is to 513 * 1) Create a blank TRUE-COLOR image 514 * 2) Copy the destination image onto that one 515 * 3) Then do the actual operation; Copying the source (top image) onto that 516 * 4) ... and return the result pointer. 517 * 5) Reduce colors (if we do not, the result may become strange!) 518 * It works, but the resulting images is now a true-color PNG which may be very large. 519 * So, why not use 'imagetruecolortopalette ($im, TRUE, 256)' - well because it does NOT WORK! So simple is that. 520 * 521 * For parameters, see PHP function "imagecopyresized()" 522 * 523 * @param pointer see PHP function "imagecopyresized()" 524 * @param pointer see PHP function "imagecopyresized()" 525 * @param integer see PHP function "imagecopyresized()" 526 * @param integer see PHP function "imagecopyresized()" 527 * @param integer see PHP function "imagecopyresized()" 528 * @param integer see PHP function "imagecopyresized()" 529 * @param integer see PHP function "imagecopyresized()" 530 * @param integer see PHP function "imagecopyresized()" 531 * @param integer see PHP function "imagecopyresized()" 532 * @param integer see PHP function "imagecopyresized()" 533 * @return void 534 * @access private 535 * @see t3lib_iconWorks::imagecopyresized() 536 */ 537 function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) { 538 if ($this->imagecopyresized_fix) { 539 $im_base = $this->imagecreate(imagesx($im), imagesy($im)); // Make true color image 540 imagecopyresized($im_base, $im, 0,0,0,0, imagesx($im),imagesy($im),imagesx($im),imagesy($im)); // Copy the source image onto that 541 imagecopyresized($im_base, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); // Then copy the $cpImg onto that (the actual operation!) 542 $im = $im_base; // Set pointer 543 if (!$this->truecolor) { 544 $this->makeEffect($im, Array('value'=>'colors='.t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256))); // Reduce to "reduceColors" colors - make SURE that IM is working then! 545 } 546 } else { 547 imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); 548 } 549 } 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 /******************************** 573 * 574 * Text / "TEXT" GIFBUILDER object 575 * 576 ********************************/ 577 578 /** 579 * Implements the "TEXT" GIFBUILDER object 580 * 581 * @param pointer GDlib image pointer 582 * @param array TypoScript array with configuration for the GIFBUILDER object. 583 * @param array The current working area coordinates. 584 * @return void 585 * @see tslib_gifBuilder::make() 586 */ 587 function makeText(&$im,$conf,$workArea) { 588 // Spacing 589 list($spacing,$wordSpacing) = $this->calcWordSpacing($conf); 590 // Position 591 $txtPos = $this->txtPosition($conf,$workArea,$conf['BBOX']); 592 $theText = $this->recodeString($conf['text']); 593 594 if ($conf['imgMap'] && is_array($conf['imgMap.'])) { 595 $this->addToMap($this->calcTextCordsForMap($conf['BBOX'][2],$txtPos, $conf['imgMap.']), $conf['imgMap.']); 596 } 597 if (!$conf['hideButCreateMap']) { 598 // Font Color: 599 $cols=$this->convertColor($conf['fontColor']); 600 // NiceText is calculated 601 if (!$conf['niceText']) { 602 // Font Color is reserved: 603 if (!$this->truecolor) { 604 $reduce = t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256); 605 $this->reduceColors($im, $reduce-49, $reduce-50); // If "reduce-49" colors (or more) are used reduce them to "reduce-50" 606 } 607 $Fcolor = ImageColorAllocate($im, $cols[0],$cols[1],$cols[2]); 608 // antiAliasing is setup: 609 $Fcolor = ($conf['antiAlias']) ? $Fcolor : -$Fcolor; 610 611 for ($a=0; $a<$conf['iterations']; $a++) { 612 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 613 $this->SpacedImageTTFText($im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.']); 614 } else { 615 $this->ImageTTFTextWrapper($im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.']); 616 } 617 } 618 } else { // NICETEXT:: 619 // options anti_aliased and iterations is NOT available when doing this!! 620 $w = imagesx($im); 621 $h = imagesy($im); 622 $tmpStr = $this->randomName(); 623 624 $fileMenu = $tmpStr.'_menuNT.'.$this->gifExtension; 625 $fileColor = $tmpStr.'_colorNT.'.$this->gifExtension; 626 $fileMask = $tmpStr.'_maskNT.'.$this->gifExtension; 627 // Scalefactor 628 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'],2,5); 629 $newW = ceil($sF*imagesx($im)); 630 $newH = ceil($sF*imagesy($im)); 631 632 // Make mask 633 $maskImg = $this->imagecreate($newW, $newH); 634 $Bcolor = ImageColorAllocate($maskImg, 255,255,255); 635 ImageFilledRectangle($maskImg, 0, 0, $newW, $newH, $Bcolor); 636 $Fcolor = ImageColorAllocate($maskImg, 0,0,0); 637 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 638 $this->SpacedImageTTFText($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.'],$sF); 639 } else { 640 $this->ImageTTFTextWrapper($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'],$sF); 641 } 642 $this->ImageWrite($maskImg, $fileMask); 643 ImageDestroy($maskImg); 644 645 // Downscales the mask 646 if ($this->NO_IM_EFFECTS) { 647 if ($this->maskNegate) { 648 $command = trim($this->scalecmd.' '.$w.'x'.$h.'!'); // Negate 2 times makes no negate... 649 } else { 650 $command = trim($this->scalecmd.' '.$w.'x'.$h.'! -negate'); 651 } 652 } else { 653 if ($this->maskNegate) { 654 $command = trim($conf['niceText.']['before'].' '.$this->scalecmd.' '.$w.'x'.$h.'! '.$conf['niceText.']['after']); 655 } else { 656 $command = trim($conf['niceText.']['before'].' '.$this->scalecmd.' '.$w.'x'.$h.'! '.$conf['niceText.']['after'].' -negate'); 657 } 658 if ($conf['niceText.']['sharpen']) { 659 if ($this->V5_EFFECTS) { 660 $command.=$this->v5_sharpen($conf['niceText.']['sharpen']); 661 } else { 662 $command.=' -sharpen '.t3lib_div::intInRange($conf['niceText.']['sharpen'],1,99); 663 } 664 } 665 } 666 667 $this->imageMagickExec($fileMask,$fileMask,$command); 668 669 // Make the color-file 670 $colorImg = $this->imagecreate($w,$h); 671 $Ccolor = ImageColorAllocate($colorImg, $cols[0],$cols[1],$cols[2]); 672 ImageFilledRectangle($colorImg, 0, 0, $w, $h, $Ccolor); 673 $this->ImageWrite($colorImg, $fileColor); 674 ImageDestroy($colorImg); 675 676 // The mask is applied 677 $this->ImageWrite($im, $fileMenu); // The main pictures is saved temporarily 678 679 $this->combineExec($fileMenu,$fileColor,$fileMask, $fileMenu); 680 681 $backIm = $this->imageCreateFromFile($fileMenu); // The main image is loaded again... 682 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 683 ImageColorTransparent($backIm,-1); 684 $im = $backIm; 685 } 686 687 // Deleting temporary files; 688 if (!$this->dontUnlinkTempFiles) { 689 unlink($fileMenu); 690 unlink($fileColor); 691 unlink($fileMask); 692 } 693 } 694 } 695 } 696 697 /** 698 * Calculates text position for printing the text onto the image based on configuration like alignment and workarea. 699 * 700 * @param array TypoScript array for the TEXT GIFBUILDER object 701 * @param array Workarea definition 702 * @param array Bounding box information, was set in tslib_gifBuilder::start() 703 * @return array [0]=x, [1]=y, [2]=w, [3]=h 704 * @access private 705 * @see makeText() 706 */ 707 function txtPosition($conf,$workArea,$BB) { 708 $bbox = $BB[2]; 709 $angle=intval($conf['angle'])/180*pi(); 710 $conf['angle']=0; 711 $straightBB = $this->calcBBox($conf); 712 713 // offset, align, valign, workarea 714 $result=Array(); // [0]=x, [1]=y, [2]=w, [3]=h 715 $result[2] = $BB[0]; 716 $result[3] = $BB[1]; 717 $w=$workArea[2]; 718 $h=$workArea[3]; 719 720 switch($conf['align']) { 721 case 'right': 722 case 'center': 723 $factor=abs(cos($angle)); 724 $sign=(cos($angle)<0)?-1:1; 725 $len1 = $sign*$factor*$straightBB[0]; 726 $len2= $sign*$BB[0]; 727 $result[0] = $w-ceil($len2*$factor+(1-$factor)*$len1); 728 729 $factor=abs(sin($angle)); 730 $sign=(sin($angle)<0)?-1:1; 731 $len1= $sign*$factor*$straightBB[0]; 732 $len2= $sign*$BB[1]; 733 $result[1]=ceil($len2*$factor+(1-$factor)*$len1); 734 break; 735 } 736 switch($conf['align']) { 737 case 'right': 738 break; 739 case 'center': 740 $result[0] = round(($result[0])/2); 741 $result[1] = round(($result[1])/2); 742 break; 743 default: 744 $result[0]=0; 745 $result[1]=0; 746 break; 747 } 748 $result = $this->applyOffset($result,t3lib_div::intExplode(',',$conf['offset'])); 749 $result = $this->applyOffset($result,$workArea); 750 return $result; 751 } 752 753 /** 754 * Calculates bounding box information for the TEXT GIFBUILDER object. 755 * 756 * @param array TypoScript array for the TEXT GIFBUILDER object 757 * @return array Array with three keys [0]/[1] being x/y and [2] being the bounding box array 758 * @access private 759 * @see txtPosition(), tslib_gifBuilder::start() 760 */ 761 function calcBBox($conf) { 762 $sF = $this->getTextScalFactor($conf); 763 list($spacing,$wordSpacing) = $this->calcWordSpacing($conf, $sF); 764 $theText = $this->recodeString($conf['text']); 765 766 $charInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $theText, $conf['splitRendering.'],$sF); 767 $theBBoxInfo = $charInf; 768 if ($conf['angle']) { 769 $xArr = Array($charInf[0],$charInf[2],$charInf[4],$charInf[6]); 770 $yArr = Array($charInf[1],$charInf[3],$charInf[5],$charInf[7]); 771 $x=max($xArr)-min($xArr); 772 $y=max($yArr)-min($yArr); 773 } else { 774 $x = ($charInf[2]-$charInf[0]); 775 $y = ($charInf[1]-$charInf[7]); 776 } 777 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 778 $x=0; 779 if (!$spacing && $wordSpacing) { 780 $bits = explode(' ',$theText); 781 while(list(,$word)=each($bits)) { 782 $word.=' '; 783 $wordInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $word, $conf['splitRendering.'],$sF); 784 $wordW = ($wordInf[2]-$wordInf[0]); 785 $x+=$wordW+$wordSpacing; 786 } 787 } else { 788 $utf8Chars = $this->singleChars($theText); 789 // For each UTF-8 char, do: 790 foreach($utf8Chars as $char) { 791 $charInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $char, $conf['splitRendering.'],$sF); 792 $charW = ($charInf[2]-$charInf[0]); 793 $x+=$charW+(($char==' ')?$wordSpacing:$spacing); 794 } 795 } 796 } 797 798 if ($sF>1) { 799 $x = ceil($x/$sF); 800 $y = ceil($y/$sF); 801 if (is_array($theBBoxInfo)) { 802 reset($theBBoxInfo); 803 while(list($key,$val)=each($theBBoxInfo)) { 804 $theBBoxInfo[$key]=ceil($theBBoxInfo[$key]/$sF); 805 } 806 } 807 } 808 return array($x,$y,$theBBoxInfo); 809 } 810 811 /** 812 * Adds an <area> tag to the internal variable $this->map which is used to accumulate the content for an ImageMap 813 * 814 * @param array Coordinates for a polygon image map as created by ->calcTextCordsForMap() 815 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object. 816 * @return void 817 * @access private 818 * @see makeText(), calcTextCordsForMap() 819 */ 820 function addToMap($cords,$conf) { 821 $JS = $conf['noBlur'] ? '' : ' onfocus="blurLink(this);"'; 822 823 $this->map.='<area'. 824 ' shape="poly"'. 825 ' coords="'.implode(',',$cords).'"'. 826 ' href="'.htmlspecialchars($conf['url']).'"'. 827 ($conf['target'] ? ' target="'.htmlspecialchars($conf['target']).'"' : ''). 828 $JS. 829 (strlen($conf['titleText']) ? ' title="'.htmlspecialchars($conf['titleText']).'"' : ''). 830 ' alt="'.htmlspecialchars($conf['altText']).'" />'; 831 } 832 833 /** 834 * Calculating the coordinates for a TEXT string on an image map. Used in an <area> tag 835 * 836 * @param array Coordinates (from BBOX array) 837 * @param array Offset array 838 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object. 839 * @return array 840 * @access private 841 * @see makeText(), calcTextCordsForMap() 842 */ 843 function calcTextCordsForMap($cords,$offset, $conf) { 844 $pars = t3lib_div::intExplode(',',$conf['explode'].','); 845 846 $newCords[0] = $cords[0]+$offset[0]-$pars[0]; 847 $newCords[1] = $cords[1]+$offset[1]+$pars[1]; 848 $newCords[2] = $cords[2]+$offset[0]+$pars[0]; 849 $newCords[3] = $cords[3]+$offset[1]+$pars[1]; 850 $newCords[4] = $cords[4]+$offset[0]+$pars[0]; 851 $newCords[5] = $cords[5]+$offset[1]-$pars[1]; 852 $newCords[6] = $cords[6]+$offset[0]-$pars[0]; 853 $newCords[7] = $cords[7]+$offset[1]-$pars[1]; 854 855 return $newCords; 856 } 857 858 /** 859 * Printing text onto an image like the PHP function imageTTFText does but in addition it offers options for spacing of letters and words. 860 * Spacing is done by printing one char at a time and this means that the spacing is rather uneven and probably not very nice. 861 * See 862 * 863 * @param pointer (See argument for PHP function imageTTFtext()) 864 * @param integer (See argument for PHP function imageTTFtext()) 865 * @param integer (See argument for PHP function imageTTFtext()) 866 * @param integer (See argument for PHP function imageTTFtext()) 867 * @param integer (See argument for PHP function imageTTFtext()) 868 * @param integer (See argument for PHP function imageTTFtext()) 869 * @param string (See argument for PHP function imageTTFtext()) 870 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in. 871 * @param integer The spacing of letters in pixels 872 * @param integer The spacing of words in pixels 873 * @param array $splitRenderingConf array 874 * @param integer Scale factor 875 * @return void 876 * @access private 877 */ 878 function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1) { 879 880 $spacing*=$sF; 881 $wordSpacing*=$sF; 882 883 if (!$spacing && $wordSpacing) { 884 $bits = explode(' ',$text); 885 reset($bits); 886 while(list(,$word)=each($bits)) { 887 $word.=' '; 888 $word = $word; 889 $wordInf = $this->ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $word, $splitRenderingConf ,$sF); 890 $wordW = ($wordInf[2]-$wordInf[0]); 891 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $word, $splitRenderingConf, $sF); 892 $x+=$wordW+$wordSpacing; 893 } 894 } else { 895 $utf8Chars = $this->singleChars($text); 896 // For each UTF-8 char, do: 897 foreach($utf8Chars as $char) { 898 $charInf = $this->ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $char, $splitRenderingConf, $sF); 899 $charW = ($charInf[2]-$charInf[0]); 900 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $char, $splitRenderingConf, $sF); 901 $x+=$charW+(($char==' ')?$wordSpacing:$spacing); 902 } 903 } 904 } 905 906 /** 907 * Function that finds the right fontsize that will render the textstring within a certain width 908 * 909 * @param array The TypoScript properties of the TEXT GIFBUILDER object 910 * @return integer The new fontSize 911 * @access private 912 * @author Rene Fritz <r.fritz@colorcube.de> 913 * @see tslib_gifBuilder::start() 914 */ 915 function fontResize($conf) { 916 // you have to use +calc options like [10.h] in 'offset' to get the right position of your text-image, if you use +calc in XY height!!!! 917 $maxWidth = intval($conf['maxWidth']); 918 list($spacing,$wordSpacing) = $this->calcWordSpacing($conf); 919 if ($maxWidth) { 920 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 921 return $conf['fontSize']; 922 // ################ no calc for spacing yet !!!!!! 923 } else { 924 do { 925 // determine bounding box. 926 $bounds = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $this->recodeString($conf['text']), $conf['splitRendering.']); 927 if ($conf['angle']< 0) { 928 $pixelWidth = abs($bounds[4]-$bounds[0]); 929 } elseif ($conf['angle'] > 0) { 930 $pixelWidth = abs($bounds[2]-$bounds[6]); 931 } else { 932 $pixelWidth = abs($bounds[4]-$bounds[6]); 933 } 934 935 // Size is fine, exit: 936 if ($pixelWidth <= $maxWidth) { 937 break; 938 } else { 939 $conf['fontSize']--; 940 } 941 } while ($conf['fontSize']>1); 942 }//if spacing 943 } 944 return $conf['fontSize']; 945 } 946 947 /** 948 * Wrapper for ImageTTFBBox 949 * 950 * @param integer (See argument for PHP function ImageTTFBBox()) 951 * @param integer (See argument for PHP function ImageTTFBBox()) 952 * @param string (See argument for PHP function ImageTTFBBox()) 953 * @param string (See argument for PHP function ImageTTFBBox()) 954 * @param array Split-rendering configuration 955 * @param integer Scale factor 956 * @return array Information array. 957 */ 958 function ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1) { 959 960 // Initialize: 961 $offsetInfo = array(); 962 $stringParts = $this->splitString($string,$splitRendering,$fontSize,$fontFile); 963 964 // Traverse string parts: 965 foreach($stringParts as $strCfg) { 966 $fontFile = t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']); 967 if (is_readable($fontFile)) { 968 969 // Calculate Bounding Box for part: 970 $calc = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF*$strCfg['fontSize']), $angle, $fontFile, $strCfg['str']); 971 972 // Calculate offsets: 973 if (!count($offsetInfo)) { 974 $offsetInfo = $calc; // First run, just copy over. 975 } else { 976 $offsetInfo[2]+=$calc[2]-$calc[0]+intval($splitRendering['compX'])+intval($strCfg['xSpaceBefore'])+intval($strCfg['xSpaceAfter']); 977 $offsetInfo[3]+=$calc[3]-$calc[1]-intval($splitRendering['compY'])-intval($strCfg['ySpaceBefore'])-intval($strCfg['ySpaceAfter']); 978 $offsetInfo[4]+=$calc[4]-$calc[6]+intval($splitRendering['compX'])+intval($strCfg['xSpaceBefore'])+intval($strCfg['xSpaceAfter']); 979 $offsetInfo[5]+=$calc[5]-$calc[7]-intval($splitRendering['compY'])-intval($strCfg['ySpaceBefore'])-intval($strCfg['ySpaceAfter']); 980 } 981 982 } else { 983 debug('cannot read file: '.$fontFile, 't3lib_stdGraphic::ImageTTFBBoxWrapper()'); 984 } 985 } 986 987 return $offsetInfo; 988 } 989 990 /** 991 * Wrapper for ImageTTFText 992 * 993 * @param pointer (See argument for PHP function imageTTFtext()) 994 * @param integer (See argument for PHP function imageTTFtext()) 995 * @param integer (See argument for PHP function imageTTFtext()) 996 * @param integer (See argument for PHP function imageTTFtext()) 997 * @param integer (See argument for PHP function imageTTFtext()) 998 * @param integer (See argument for PHP function imageTTFtext()) 999 * @param string (See argument for PHP function imageTTFtext()) 1000 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in. 1001 * @param array Split-rendering configuration 1002 * @param integer Scale factor 1003 * @return void 1004 */ 1005 function ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering,$sF=1) { 1006 1007 // Initialize: 1008 $stringParts = $this->splitString($string,$splitRendering,$fontSize,$fontFile); 1009 $x = ceil($sF*$x); 1010 $y = ceil($sF*$y); 1011 1012 // Traverse string parts: 1013 foreach($stringParts as $i => $strCfg) { 1014 1015 // Initialize: 1016 $colorIndex = $color; 1017 1018 // Set custom color if any (only when niceText is off): 1019 if ($strCfg['color'] && $sF==1) { 1020 $cols = $this->convertColor($strCfg['color']); 1021 $colorIndex = ImageColorAllocate($im, $cols[0],$cols[1],$cols[2]); 1022 $colorIndex = $color >= 0 ? $colorIndex : -$colorIndex; 1023 } 1024 1025 // Setting xSpaceBefore 1026 if ($i) { 1027 $x+= intval($strCfg['xSpaceBefore']); 1028 $y-= intval($strCfg['ySpaceBefore']); 1029 } 1030 1031 $fontFile = t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']); 1032 if (is_readable($fontFile)) { 1033 1034 // Render part: 1035 ImageTTFText($im, t3lib_div::freetypeDpiComp($sF*$strCfg['fontSize']), $angle, $x, $y, $colorIndex, $fontFile, $strCfg['str']); 1036 1037 // Calculate offset to apply: 1038 $wordInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF*$strCfg['fontSize']), $angle, t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']), $strCfg['str']); 1039 $x+= $wordInf[2]-$wordInf[0]+intval($splitRendering['compX'])+intval($strCfg['xSpaceAfter']); 1040 $y+= $wordInf[5]-$wordInf[7]-intval($splitRendering['compY'])-intval($strCfg['ySpaceAfter']); 1041 1042 } else { 1043 debug('cannot read file: '.$fontFile, 't3lib_stdGraphic::ImageTTFTextWrapper()'); 1044 } 1045 1046 } 1047 } 1048 1049 /** 1050 * Splitting a string for ImageTTFBBox up into an array where each part has its own configuration options. 1051 * 1052 * @param string UTF-8 string 1053 * @param array Split-rendering configuration from GIFBUILDER TEXT object. 1054 * @param integer Current fontsize 1055 * @param string Current font file 1056 * @return array Array with input string splitted according to configuration 1057 */ 1058 function splitString($string,$splitRendering,$fontSize,$fontFile) { 1059 1060 // Initialize by setting the whole string and default configuration as the first entry. 1061 $result = array(); 1062 $result[] = array( 1063 'str' => $string, 1064 'fontSize' => $fontSize, 1065 'fontFile' => $fontFile 1066 ); 1067 1068 // Traverse the split-rendering configuration: 1069 // Splitting will create more entries in $result with individual configurations. 1070 if (is_array($splitRendering)) { 1071 $sKeyArray = t3lib_TStemplate::sortedKeyList($splitRendering); 1072 1073 // Traverse configured options: 1074 foreach($sKeyArray as $key) { 1075 $cfg = $splitRendering[$key.'.']; 1076 1077 // Process each type of split rendering keyword: 1078 switch((string)$splitRendering[$key]) { 1079 case 'highlightWord': 1080 if (strlen($cfg['value'])) { 1081 $newResult = array(); 1082 1083 // Traverse the current parts of the result array: 1084 foreach($result as $part) { 1085 // Explode the string value by the word value to highlight: 1086 $explodedParts = explode($cfg['value'],$part['str']); 1087 foreach($explodedParts as $c => $expValue) { 1088 if (strlen($expValue)) { 1089 $newResult[] = array_merge($part,array('str' => $expValue)); 1090 } 1091 if ($c+1 < count($explodedParts)) { 1092 $newResult[] = array( 1093 'str' => $cfg['value'], 1094 'fontSize' => $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 1095 'fontFile' => $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 1096 'color' => $cfg['color'], 1097 'xSpaceBefore' => $cfg['xSpaceBefore'], 1098 'xSpaceAfter' => $cfg['xSpaceAfter'], 1099 'ySpaceBefore' => $cfg['ySpaceBefore'], 1100 'ySpaceAfter' => $cfg['ySpaceAfter'], 1101 ); 1102 } 1103 } 1104 } 1105 1106 // Set the new result as result array: 1107 if (count($newResult)) { 1108 $result = $newResult; 1109 } 1110 } 1111 break; 1112 case 'charRange': 1113 if (strlen($cfg['value'])) { 1114 1115 // Initialize range: 1116 $ranges = t3lib_div::trimExplode(',',$cfg['value'],1); 1117 foreach($ranges as $i => $rangeDef) { 1118 $ranges[$i] = t3lib_div::intExplode('-',$ranges[$i]); 1119 if (!isset($ranges[$i][1])) $ranges[$i][1] = $ranges[$i][0]; 1120 } 1121 $newResult = array(); 1122 1123 // Traverse the current parts of the result array: 1124 foreach($result as $part) { 1125 1126 // Initialize: 1127 $currentState = -1; 1128 $bankAccum = ''; 1129 1130 // Explode the string value by the word value to highlight: 1131 $utf8Chars = $this->singleChars($part['str']); 1132 foreach($utf8Chars as $utfChar) { 1133 1134 // Find number and evaluate position: 1135 $uNumber = $this->csConvObj->utf8CharToUnumber($utfChar); 1136 $inRange = 0; 1137 foreach($ranges as $rangeDef) { 1138 if ($uNumber >= $rangeDef[0] && (!$rangeDef[1] || $uNumber <= $rangeDef[1])) { 1139 $inRange = 1; 1140 break; 1141 } 1142 } 1143 if ($currentState==-1) $currentState = $inRange; // Initialize first char 1144 1145 // Switch bank: 1146 if ($inRange != $currentState && !t3lib_div::inList('32,10,13,9',$uNumber)) { 1147 1148 // Set result: 1149 if (strlen($bankAccum)) { 1150 $newResult[] = array( 1151 'str' => $bankAccum, 1152 'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 1153 'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 1154 'color' => $currentState ? $cfg['color'] : '', 1155 'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '', 1156 'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '', 1157 'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '', 1158 'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '', 1159 ); 1160 } 1161 1162 // Initialize new settings: 1163 $currentState = $inRange; 1164 $bankAccum = ''; 1165 } 1166 1167 // Add char to bank: 1168 $bankAccum.=$utfChar; 1169 } 1170 1171 // Set result for FINAL part: 1172 if (strlen($bankAccum)) { 1173 $newResult[] = array( 1174 'str' => $bankAccum, 1175 'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 1176 'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 1177 'color' => $currentState ? $cfg['color'] : '', 1178 'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '', 1179 'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '', 1180 'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '', 1181 'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '', 1182 ); 1183 } 1184 } 1185 1186 // Set the new result as result array: 1187 if (count($newResult)) { 1188 $result = $newResult; 1189 } 1190 } 1191 break; 1192 } 1193 } 1194 } 1195 1196 return $result; 1197 } 1198 1199 /** 1200 * Calculates the spacing and wordSpacing values 1201 * 1202 * @param array TypoScript array for the TEXT GIFBUILDER object 1203 * @param integer TypoScript value from eg $conf['niceText.']['scaleFactor'] 1204 * @return array Array with two keys [0]/[1] being array($spacing,$wordSpacing) 1205 * @access private 1206 * @see calcBBox() 1207 */ 1208 function calcWordSpacing($conf, $scaleFactor=1) { 1209 1210 $spacing = intval($conf['spacing']); 1211 $wordSpacing = intval($conf['wordSpacing']); 1212 $wordSpacing = $wordSpacing?$wordSpacing:$spacing*2; 1213 1214 $spacing*=$scaleFactor; 1215 $wordSpacing*=$scaleFactor; 1216 1217 return array($spacing,$wordSpacing); 1218 } 1219 1220 /** 1221 * Calculates and returns the niceText.scaleFactor 1222 * 1223 * @param array TypoScript array for the TEXT GIFBUILDER object 1224 * @return integer TypoScript value from eg $conf['niceText.']['scaleFactor'] 1225 * @access private 1226 */ 1227 function getTextScalFactor($conf) { 1228 if (!$conf['niceText']) { 1229 $sF = 1; 1230 } else { // NICETEXT:: 1231 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'],2,5); 1232 } 1233 return $sF; 1234 } 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 /********************************************* 1247 * 1248 * Other GIFBUILDER objects related to TEXT 1249 * 1250 *********************************************/ 1251 1252 /** 1253 * Implements the "OUTLINE" GIFBUILDER object / property for the TEXT object 1254 * 1255 * @param pointer GDlib image pointer 1256 * @param array TypoScript array with configuration for the GIFBUILDER object. 1257 * @param array The current working area coordinates. 1258 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 1259 * @return void 1260 * @see tslib_gifBuilder::make(), makeText() 1261 */ 1262 function makeOutline(&$im,$conf,$workArea,$txtConf) { 1263 $thickness = intval($conf['thickness']); 1264 if ($thickness) { 1265 $txtConf['fontColor'] = $conf['color']; 1266 $outLineDist = t3lib_div::intInRange($thickness,1,2); 1267 for ($b=1;$b<=$outLineDist;$b++) { 1268 if ($b==1) { 1269 $it = 8; 1270 } else { 1271 $it = 16; 1272 } 1273 $outL = $this->circleOffset($b, $it); 1274 for ($a=0;$a<$it;$a++) { 1275 $this->makeText($im,$txtConf,$this->applyOffset($workArea,$outL[$a])); 1276 } 1277 } 1278 } 1279 } 1280 1281 /** 1282 * Creates some offset values in an array used to simulate a circularly applied outline around TEXT 1283 * 1284 * access private 1285 * 1286 * @param integer Distance 1287 * @param integer Iterations. 1288 * @return array 1289 * @see makeOutline() 1290 */ 1291 function circleOffset($distance, $iterations) { 1292 $res = Array(); 1293 if ($distance && $iterations) { 1294 for ($a=0;$a<$iterations;$a++) { 1295 $yOff = round(sin(2*pi()/$iterations*($a+1))*100*$distance); 1296 if ($yOff) {$yOff = intval(ceil(abs($yOff/100))*($yOff/abs($yOff)));} 1297 $xOff = round(cos(2*pi()/$iterations*($a+1))*100*$distance); 1298 if ($xOff) {$xOff = intval(ceil(abs($xOff/100))*($xOff/abs($xOff)));} 1299 $res[$a] = Array($xOff,$yOff); 1300 } 1301 } 1302 return $res; 1303 } 1304 1305 /** 1306 * Implements the "EMBOSS" GIFBUILDER object / property for the TEXT object 1307 * 1308 * @param pointer GDlib image pointer 1309 * @param array TypoScript array with configuration for the GIFBUILDER object. 1310 * @param array The current working area coordinates. 1311 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 1312 * @return void 1313 * @see tslib_gifBuilder::make(), makeShadow() 1314 */ 1315 function makeEmboss(&$im,$conf,$workArea,$txtConf) { 1316 $conf['color']=$conf['highColor']; 1317 $this->makeShadow($im,$conf,$workArea,$txtConf); 1318 $newOffset = t3lib_div::intExplode(',',$conf['offset']); 1319 $newOffset[0]*=-1; 1320 $newOffset[1]*=-1; 1321 $conf['offset']=implode(',',$newOffset); 1322 $conf['color']=$conf['lowColor']; 1323 $this->makeShadow($im,$conf,$workArea,$txtConf); 1324 } 1325 1326 /** 1327 * Implements the "SHADOW" GIFBUILDER object / property for the TEXT object 1328 * The operation involves ImageMagick for combining. 1329 * 1330 * @param pointer GDlib image pointer 1331 * @param array TypoScript array with configuration for the GIFBUILDER object. 1332 * @param array The current working area coordinates. 1333 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 1334 * @return void 1335 * @see tslib_gifBuilder::make(), makeText(), makeEmboss() 1336 */ 1337 function makeShadow(&$im,$conf,$workArea,$txtConf) { 1338 $workArea = $this->applyOffset($workArea,t3lib_div::intExplode(',',$conf['offset'])); 1339 $blurRate = t3lib_div::intInRange(intval($conf['blur']),0,99); 1340 1341 if (!$blurRate || $this->NO_IM_EFFECTS) { // No effects if ImageMagick ver. 5+ 1342 $txtConf['fontColor'] = $conf['color']; 1343 $this->makeText($im,$txtConf,$workArea); 1344 } else { 1345 $w = imagesx($im); 1346 $h = imagesy($im); 1347 $blurBorder= 3; // area around the blur used for cropping something 1348 $tmpStr = $this->randomName(); 1349 $fileMenu = $tmpStr.'_menu.'.$this->gifExtension; 1350 $fileColor = $tmpStr.'_color.'.$this->gifExtension; 1351 $fileMask = $tmpStr.'_mask.'.$this->gifExtension; 1352 1353 // BlurColor Image laves 1354 $blurColImg = $this->imagecreate($w,$h); 1355 $bcols=$this->convertColor($conf['color']); 1356 $Bcolor = ImageColorAllocate($blurColImg, $bcols[0],$bcols[1],$bcols[2]); 1357 ImageFilledRectangle($blurColImg, 0, 0, $w, $h, $Bcolor); 1358 $this->ImageWrite($blurColImg, $fileColor); 1359 ImageDestroy($blurColImg); 1360 1361 // The mask is made: BlurTextImage 1362 $blurTextImg = $this->imagecreate($w+$blurBorder*2,$h+$blurBorder*2); 1363 $Bcolor = ImageColorAllocate($blurTextImg, 0,0,0); // black background 1364 ImageFilledRectangle($blurTextImg, 0, 0, $w+$blurBorder*2, $h+$blurBorder*2, $Bcolor); 1365 $txtConf['fontColor'] = 'white'; 1366 $blurBordArr = Array($blurBorder,$blurBorder); 1367 $this->makeText($blurTextImg,$txtConf, $this->applyOffset($workArea,$blurBordArr)); 1368 $this->ImageWrite($blurTextImg, $fileMask); // dump to temporary file 1369 ImageDestroy($blurTextImg); // destroy 1370 1371 1372 $command=''; 1373 $command.=$this->maskNegate; 1374 1375 if ($this->V5_EFFECTS) { 1376 $command.=$this->v5_blur($blurRate+1); 1377 } else { 1378 // Blurring of the mask 1379 $times = ceil($blurRate/10); // How many blur-commands that is executed. Min = 1; 1380 $newBlurRate = $blurRate*4; // Here I boost the blur-rate so that it is 100 already at 25. The rest is done by up to 99 iterations of the blur-command. 1381 $newBlurRate = t3lib_div::intInRange($newBlurRate,1,99); 1382 for ($a=0;$a<$times;$a++) { // Building blur-command 1383 $command.=' -blur '.$blurRate; 1384 } 1385 } 1386 1387 $this->imageMagickExec($fileMask,$fileMask,$command.' +matte'); 1388 1389 $blurTextImg_tmp = $this->imageCreateFromFile($fileMask); // the mask is loaded again 1390 if ($blurTextImg_tmp) { // if nothing went wrong we continue with the blurred mask 1391 1392 // cropping the border from the mask 1393 $blurTextImg = $this->imagecreate($w,$h); 1394 $this->imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, $w, $h, $w, $h); 1395 ImageDestroy($blurTextImg_tmp); // Destroy the temporary mask 1396 1397 // adjust the mask 1398 $intensity = 40; 1399 if ($conf['intensity']) { 1400 $intensity = t3lib_div::intInRange($conf['intensity'],0,100); 1401 } 1402 $intensity = ceil(255-($intensity/100*255)); 1403 $this->inputLevels($blurTextImg,0,$intensity,$this->maskNegate); 1404 1405 $opacity = t3lib_div::intInRange(intval($conf['opacity']),0,100); 1406 if ($opacity && $opacity<100) { 1407 $high = ceil(255*$opacity/100); 1408 $this->outputLevels($blurTextImg,0,$high,$this->maskNegate); // reducing levels as the opacity demands 1409 } 1410 1411 $this->ImageWrite($blurTextImg, $fileMask); // Dump the mask again 1412 ImageDestroy($blurTextImg); // Destroy the mask 1413 1414 // The pictures are combined 1415 $this->ImageWrite($im, $fileMenu); // The main pictures is saved temporarily 1416 1417 $this->combineExec($fileMenu,$fileColor,$fileMask,$fileMenu); 1418 1419 $backIm = $this->imageCreateFromFile($fileMenu); // The main image is loaded again... 1420 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 1421 ImageColorTransparent($backIm,-1); 1422 $im = $backIm; 1423 } 1424 } 1425 // Deleting temporary files; 1426 if (!$this->dontUnlinkTempFiles) { 1427 unlink($fileMenu); 1428 unlink($fileColor); 1429 unlink($fileMask); 1430 } 1431 } 1432 } 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 /**************************** 1455 * 1456 * Other GIFBUILDER objects 1457 * 1458 ****************************/ 1459 1460 /** 1461 * Implements the "BOX" GIFBUILDER object 1462 * 1463 * @param pointer GDlib image pointer 1464 * @param array TypoScript array with configuration for the GIFBUILDER object. 1465 * @param array The current working area coordinates. 1466 * @return void 1467 * @see tslib_gifBuilder::make() 1468 */ 1469 function makeBox(&$im,$conf,$workArea) { 1470 $cords = t3lib_div::intExplode(',',$conf['dimensions'].',,,'); 1471 $conf['offset']=$cords[0].','.$cords[1]; 1472 $cords = $this->objPosition($conf,$workArea,Array($cords[2],$cords[3])); 1473 $cols=$this->convertColor($conf['color']); 1474 if (!$this->truecolor) { 1475 $reduce = t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256); 1476 $this->reduceColors($im, $reduce-1, $reduce-2); // If "reduce-1" colors (or more) are used reduce them to "reduce-2" 1477 } 1478 $tmpColor = ImageColorAllocate($im, $cols[0],$cols[1],$cols[2]); 1479 imagefilledrectangle($im, $cords[0], $cords[1], $cords[0]+$cords[2]-1, $cords[1]+$cords[3]-1, $tmpColor); 1480 } 1481 1482 /** 1483 * Implements the "EFFECT" GIFBUILDER object 1484 * The operation involves ImageMagick for applying effects 1485 * 1486 * @param pointer GDlib image pointer 1487 * @param array TypoScript array with configuration for the GIFBUILDER object. 1488 * @return void 1489 * @see tslib_gifBuilder::make(), applyImageMagickToPHPGif() 1490 */ 1491 function makeEffect(&$im, $conf) { 1492 $commands = $this->IMparams($conf['value']); 1493 if ($commands) { 1494 $this->applyImageMagickToPHPGif($im, $commands); 1495 } 1496 } 1497 1498 /** 1499 * Creating ImageMagick paramters from TypoScript property 1500 * 1501 * @param string A string with effect keywords=value pairs separated by "|" 1502 * @return string ImageMagick prepared parameters. 1503 * @access private 1504 * @see makeEffect() 1505 */ 1506 function IMparams($setup) { 1507 if (!trim($setup)){return '';} 1508 $effects = explode('|', $setup); 1509 $commands = ''; 1510 while(list(,$val)=each($effects)) { 1511 $pairs=explode('=',$val,2); 1512 $value = trim($pairs[1]); 1513 $effect = strtolower(trim($pairs[0])); 1514 switch($effect) { 1515 case 'gamma': 1516 $commands.=' -gamma '.doubleval($value); 1517 break; 1518 case 'blur': 1519 if (!$this->NO_IM_EFFECTS) { 1520 if ($this->V5_EFFECTS) { 1521 $commands.=$this->v5_blur($value); 1522 } else { 1523 $commands.=' -blur '.t3lib_div::intInRange($value,1,99); 1524 } 1525 } 1526 break; 1527 case 'sharpen': 1528 if (!$this->NO_IM_EFFECTS) { 1529 if ($this->V5_EFFECTS) { 1530 $commands.=$this->v5_sharpen($value); 1531 } else { 1532 $commands.=' -sharpen '.t3lib_div::intInRange($value,1,99); 1533 } 1534 } 1535 break; 1536 case 'rotate': 1537 $commands.=' -rotate '.t3lib_div::intInRange($value,0,360); 1538 break; 1539 case 'solarize': 1540 $commands.=' -solarize '.t3lib_div::intInRange($value,0,99); 1541 break; 1542 case 'swirl': 1543 $commands.=' -swirl '.t3lib_div::intInRange($value,0,1000); 1544 break; 1545 case 'wave': 1546 $params = t3lib_div::intExplode(',',$value); 1547 $commands.=' -wave '.t3lib_div::intInRange($params[0],0,99).'x'.t3lib_div::intInRange($params[1],0,99); 1548 break; 1549 case 'charcoal': 1550 $commands.=' -charcoal '.t3lib_div::intInRange($value,0,100); 1551 break; 1552 case 'gray': 1553 $commands.=' -colorspace GRAY'; 1554 break; 1555 case 'edge': 1556 $commands.=' -edge '.t3lib_div::intInRange($value,0,99); 1557 break; 1558 case 'emboss': 1559 $commands.=' -emboss'; 1560 break; 1561 case 'flip': 1562 $commands.=' -flip'; 1563 break; 1564 case 'flop': 1565 $commands.=' -flop'; 1566 break; 1567 case 'colors': 1568 $commands.=' -colors '.t3lib_div::intInRange($value,2,255); 1569 break; 1570 case 'shear': 1571 $commands.=' -shear '.t3lib_div::intInRange($value,-90,90); 1572 break; 1573 case 'invert': 1574 $commands.=' -negate'; 1575 break; 1576 } 1577 } 1578 return $commands; 1579 } 1580 1581 /** 1582 * Implements the "ADJUST" GIFBUILDER object 1583 * 1584 * @param pointer GDlib image pointer 1585 * @param array TypoScript array with configuration for the GIFBUILDER object. 1586 * @return void 1587 * @see tslib_gifBuilder::make(), autoLevels(), outputLevels(), inputLevels() 1588 */ 1589 function adjust(&$im, $conf) { 1590 $setup = $conf['value']; 1591 if (!trim($setup)){return '';} 1592 $effects = explode('|', $setup); 1593 while(list(,$val)=each($effects)) { 1594 $pairs=explode('=',$val,2); 1595 $value = trim($pairs[1]); 1596 $effect = strtolower(trim($pairs[0])); 1597 switch($effect) { 1598 case 'inputlevels': // low,high 1599 $params = t3lib_div::intExplode(',',$value); 1600 $this->inputLevels($im,$params[0],$params[1]); 1601 break; 1602 case 'outputlevels': 1603 $params = t3lib_div::intExplode(',',$value); 1604 $this->outputLevels($im,$params[0],$params[1]); 1605 break; 1606 case 'autolevels': 1607 $this->autoLevels($im); 1608 break; 1609 } 1610 } 1611 } 1612 1613 /** 1614 * Implements the "CROP" GIFBUILDER object 1615 * 1616 * @param pointer GDlib image pointer 1617 * @param array TypoScript array with configuration for the GIFBUILDER object. 1618 * @return void 1619 * @see tslib_gifBuilder::make() 1620 */ 1621 function crop(&$im,$conf) { 1622 $this->setWorkArea(''); // clears workArea to total image 1623 $cords = t3lib_div::intExplode(',',$conf['crop'].',,,'); 1624 $conf['offset']=$cords[0].','.$cords[1]; 1625 $cords = $this->objPosition($conf,$this->workArea,Array($cords[2],$cords[3])); 1626 1627 $newIm = $this->imagecreate($cords[2],$cords[3]); 1628 $cols=$this->convertColor($conf['backColor']?$conf['backColor']:$this->setup['backColor']); 1629 $Bcolor = ImageColorAllocate($newIm, $cols[0],$cols[1],$cols[2]); 1630 ImageFilledRectangle($newIm, 0, 0, $cords[2], $cords[3], $Bcolor); 1631 1632 $newConf = Array(); 1633 $workArea = Array(0,0,$cords[2],$cords[3]); 1634 if ($cords[0]<0) {$workArea[0]=abs($cords[0]);} else {$newConf['offset']=-$cords[0];} 1635 if ($cords[1]<0) {$workArea[1]=abs($cords[1]);} else {$newConf['offset'].=','.-$cords[1];} 1636 1637 $this->copyGifOntoGif($newIm,$im,$newConf,$workArea); 1638 $im = $newIm; 1639 $this->w = imagesx($im); 1640 $this->h = imagesy($im); 1641 $this->setWorkArea(''); // clears workArea to total image 1642 } 1643 1644 /** 1645 * Implements the "SCALE" GIFBUILDER object 1646 * 1647 * @param pointer GDlib image pointer 1648 * @param array TypoScript array with configuration for the GIFBUILDER object. 1649 * @return void 1650 * @see tslib_gifBuilder::make() 1651 */ 1652 function scale(&$im,$conf) { 1653 if ($conf['width'] || $conf['height'] || $conf['params']) { 1654 $tmpStr = $this->randomName(); 1655 $theFile = $tmpStr.'.'.$this->gifExtension; 1656 $this->ImageWrite($im, $theFile); 1657 $theNewFile = $this->imageMagickConvert($theFile,$this->gifExtension,$conf['width'],$conf['height'],$conf['params'],'',''); 1658 $tmpImg = $this->imageCreateFromFile($theNewFile[3]); 1659 if ($tmpImg) { 1660 ImageDestroy($im); 1661 $im = $tmpImg; 1662 $this->w = imagesx($im); 1663 $this->h = imagesy($im); 1664 $this->setWorkArea(''); // clears workArea to total image 1665 } 1666 if (!$this->dontUnlinkTempFiles) { 1667 unlink($theFile); 1668 if ($theNewFile[3] && $theNewFile[3]!=$theFile) { 1669 unlink($theNewFile[3]); 1670 } 1671 } 1672 } 1673 } 1674 1675 /** 1676 * Implements the "WORKAREA" GIFBUILDER object when setting it 1677 * Setting internal working area boundaries (->workArea) 1678 * 1679 * @param string Working area dimensions, comma separated 1680 * @return void 1681 * @access private 1682 * @see tslib_gifBuilder::make() 1683 */ 1684 function setWorkArea($workArea) { 1685 $this->workArea = t3lib_div::intExplode(',',$workArea); 1686 $this->workArea = $this->applyOffset($this->workArea,$this->OFFSET); 1687 if (!$this->workArea[2]) {$this->workArea[2]=$this->w;} 1688 if (!$this->workArea[3]) {$this->workArea[3]=$this->h;} 1689 } 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 /************************* 1714 * 1715 * Adjustment functions 1716 * 1717 ************************/ 1718 1719 /** 1720 * Apply auto-levels to input image pointer 1721 * 1722 * @param integer GDlib Image Pointer 1723 * @return void 1724 */ 1725 function autolevels(&$im) { 1726 $totalCols = ImageColorsTotal($im); 1727 $min=255; 1728 $max=0; 1729 for ($c=0; $c<$totalCols; $c++) { 1730 $cols = ImageColorsForIndex($im,$c); 1731 $grayArr[] = round(($cols['red']+$cols['green']+$cols['blue'])/3); 1732 } 1733 $min=min($grayArr); 1734 $max=max($grayArr); 1735 $delta = $max-$min; 1736 if ($delta) { 1737 for ($c=0; $c<$totalCols; $c++) { 1738 $cols = ImageColorsForIndex($im,$c); 1739 $cols['red'] = floor(($cols['red']-$min)/$delta*255); 1740 $cols['green'] = floor(($cols['green']-$min)/$delta*255); 1741 $cols['blue'] = floor(($cols['blue']-$min)/$delta*255); 1742 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']); 1743 } 1744 } 1745 } 1746 1747 /** 1748 * Apply output levels to input image pointer (decreasing contrast) 1749 * 1750 * @param integer GDlib Image Pointer 1751 * @param integer The "low" value (close to 0) 1752 * @param integer The "high" value (close to 255) 1753 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...) 1754 * @return void 1755 */ 1756 function outputLevels(&$im,$low,$high,$swap='') { 1757 if ($low<$high){ 1758 $low = t3lib_div::intInRange($low,0,255); 1759 $high = t3lib_div::intInRange($high,0,255); 1760 1761 if ($swap) { 1762 $temp = $low; 1763 $low = 255-$high; 1764 $high = 255-$temp; 1765 } 1766 1767 $delta = $high-$low; 1768 $totalCols = ImageColorsTotal($im); 1769 for ($c=0; $c<$totalCols; $c++) { 1770 $cols = ImageColorsForIndex($im,$c); 1771 $cols['red'] = $low+floor($cols['red']/255*$delta); 1772 $cols['green'] = $low+floor($cols['green']/255*$delta); 1773 $cols['blue'] = $low+floor($cols['blue']/255*$delta); 1774 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']); 1775 } 1776 } 1777 } 1778 1779 /** 1780 * Apply input levels to input image pointer (increasing contrast) 1781 * 1782 * @param integer GDlib Image Pointer 1783 * @param integer The "low" value (close to 0) 1784 * @param integer The "high" value (close to 255) 1785 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...) 1786 * @return void 1787 */ 1788 function inputLevels(&$im,$low,$high,$swap='') { 1789 if ($low<$high){ 1790 $low = t3lib_div::intInRange($low,0,255); 1791 $high = t3lib_div::intInRange($high,0,255); 1792 1793 if ($swap) { 1794 $temp = $low; 1795 $low = 255-$high; 1796 $high = 255-$temp; 1797 } 1798 1799 $delta = $high-$low; 1800 $totalCols = ImageColorsTotal($im); 1801 for ($c=0; $c<$totalCols; $c++) { 1802 $cols = ImageColorsForIndex($im,$c); 1803 $cols['red'] = t3lib_div::intInRange(($cols['red']-$low)/$delta*255, 0,255); 1804 $cols['green'] = t3lib_div::intInRange(($cols['green']-$low)/$delta*255, 0,255); 1805 $cols['blue'] = t3lib_div::intInRange(($cols['blue']-$low)/$delta*255, 0,255); 1806 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']); 1807 } 1808 } 1809 } 1810 1811 /** 1812 * Reduce colors in image dependend on the actual amount of colors (Only works if we are not in truecolor mode) 1813 * 1814 * @param integer GDlib Image Pointer 1815 * @param integer The max number of colors in the image before a reduction will happen; basically this means that IF the GD image current has the same amount or more colors than $limit define, THEN a reduction is performed. 1816 * @param integer Number of colors to reduce the image to. 1817 * @return void 1818 */ 1819 function reduceColors(&$im,$limit, $cols) { 1820 if (!$this->truecolor && ImageColorsTotal($im)>=$limit) { 1821 $this->makeEffect($im, Array('value'=>'colors='.$cols) ); 1822 } 1823 } 1824 1825 /** 1826 * Reduce colors in image using IM and create a palette based image if possible (<=256 colors) 1827 * 1828 * @param string Image file to reduce 1829 * @param integer Number of colors to reduce the image to. 1830 * @return string Reduced file 1831 */ 1832 function IMreduceColors($file, $cols) { 1833 $fI = t3lib_div::split_fileref($file); 1834 $ext = strtolower($fI['fileext']); 1835 $result = $this->randomName().'.'.$ext; 1836 if (($reduce = t3lib_div::intInRange($cols, 0, ($ext=='gif'?256:$this->truecolorColors), 0))>0) { 1837 $params = ' -colors '.$reduce; 1838 if (!$this->im_version_4) { 1839 // IM4 doesn't have this options but forces them automatically if applicaple (<256 colors in image) 1840 if ($reduce<=256) { $params .= ' -type Palette'; } 1841 if ($ext=='png' && $reduce<=256) { $prefix = 'png8:'; } 1842 } 1843 $this->imageMagickExec($file, $prefix.$result, $params); 1844 if ($result) { 1845 return $result; 1846 } 1847 } 1848 return ''; 1849 } 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 /********************************* 1862 * 1863 * GIFBUILDER Helper functions 1864 * 1865 *********************************/ 1866 1867 /** 1868 * Checks if the $fontFile is already at an absolute path and if not, prepends the correct path. 1869 * Use PATH_site unless we are in the backend. 1870 * Call it by t3lib_stdGraphic::prependAbsolutePath() 1871 * 1872 * @param string The font file 1873 * @return string The font file with absolute path. 1874 */ 1875 function prependAbsolutePath($fontFile) { 1876 $absPath = defined('PATH_typo3') ? dirname(PATH_thisScript).'/' :PATH_site; 1877 $fontFile = t3lib_div::isAbsPath($fontFile) ? $fontFile : t3lib_div::resolveBackPath($absPath.$fontFile); 1878 return $fontFile; 1879 } 1880 1881 /** 1882 * Returns the IM command for sharpening with ImageMagick 5 (when $this->V5_EFFECTS is set). 1883 * Uses $this->im5fx_sharpenSteps for translation of the factor to an actual command. 1884 * 1885 * @param integer The sharpening factor, 0-100 (effectively in 10 steps) 1886 * @return string The sharpening command, eg. " -sharpen 3x4" 1887 * @see makeText(), IMparams(), v5_blur() 1888 */ 1889 function v5_sharpen($factor) { 1890 $factor = t3lib_div::intInRange(ceil($factor/10),0,10); 1891 1892 $sharpenArr=explode(',',','.$this->im5fx_sharpenSteps); 1893 $sharpenF= trim($sharpenArr[$factor]); 1894 if ($sharpenF) { 1895 $cmd = ' -sharpen '.$sharpenF; 1896 return $cmd; 1897 } 1898 } 1899 1900 /** 1901 * Returns the IM command for blurring with ImageMagick 5 (when $this->V5_EFFECTS is set). 1902 * Uses $this->im5fx_blurSteps for translation of the factor to an actual command. 1903 * 1904 * @param integer The blurring factor, 0-100 (effectively in 10 steps) 1905 * @return string The blurring command, eg. " -blur 3x4" 1906 * @see makeText(), IMparams(), v5_sharpen() 1907 */ 1908 function v5_blur($factor) { 1909 $factor = t3lib_div::intInRange(ceil($factor/10),0,10); 1910 1911 $blurArr=explode(',',','.$this->im5fx_blurSteps); 1912 $blurF= trim($blurArr[$factor]); 1913 if ($blurF) { 1914 $cmd=' -blur '.$blurF; 1915 return $cmd; 1916 } 1917 } 1918 1919 /** 1920 * Returns a random filename prefixed with "temp_" and then 32 char md5 hash (without extension) from $this->tempPath. 1921 * Used by functions in this class to create truely temporary files for the on-the-fly processing. These files will most likely be deleted right away. 1922 * 1923 * @return string 1924 */ 1925 function randomName() { 1926 $this->createTempSubDir('temp/'); 1927 return $this->tempPath.'temp/'.md5(uniqid('')); 1928 } 1929 1930 /** 1931 * Applies offset value to coordinated in $cords. 1932 * Basically the value of key 0/1 of $OFFSET is added to keys 0/1 of $cords 1933 * 1934 * @param array Integer coordinates in key 0/1 1935 * @param array Offset values in key 0/1 1936 * @return array Modified $cords array 1937 */ 1938 function applyOffset($cords,$OFFSET) { 1939 $cords[0] = intval($cords[0])+intval($OFFSET[0]); 1940 $cords[1] = intval($cords[1])+intval($OFFSET[1]); 1941 return $cords; 1942 } 1943 1944 /** 1945 * Converts a "HTML-color" TypoScript datatype to RGB-values. 1946 * Default is 0,0,0 1947 * 1948 * @param string "HTML-color" data type string, eg. 'red', '#ffeedd' or '255,0,255'. You can also add a modifying operator afterwards. There are two options: "255,0,255 : 20" - will add 20 to values, result is "255,20,255". Or "255,0,255 : *1.23" which will multiply all RGB values with 1.23 1949 * @return array RGB values in key 0/1/2 of the array 1950 */ 1951 function convertColor($string) { 1952 $col=array(); 1953 $cParts = explode(':',$string,2); 1954 1955 // Finding the RGB definitions of the color: 1956 $string=$cParts[0]; 1957 if (strstr($string,'#')) { 1958 $string = ereg_replace('[^A-Fa-f0-9]*','',$string); 1959 $col[]=HexDec(substr($string,0,2)); 1960 $col[]=HexDec(substr($string,2,2)); 1961 $col[]=HexDec(substr($string,4,2)); 1962 } elseif (strstr($string,',')) { 1963 $string = ereg_replace('[^,0-9]*','',$string); 1964 $strArr = explode(',',$string); 1965 $col[]=intval($strArr[0]); 1966 $col[]=intval($strArr[1]); 1967 $col[]=intval($strArr[2]); 1968 } else { 1969 $string = strtolower(trim($string)); 1970 if ($this->colMap[$string]) { 1971 $col = $this->colMap[$string]; 1972 } else { 1973 $col = Array(0,0,0); 1974 } 1975 } 1976 // ... and possibly recalculating the value 1977 if (trim($cParts[1])) { 1978 $cParts[1]=trim($cParts[1]); 1979 if (substr($cParts[1],0,1)=='*') { 1980 $val=doubleval(substr($cParts[1],1)); 1981 $col[0]=t3lib_div::intInRange($col[0]*$val,0,255); 1982 $col[1]=t3lib_div::intInRange($col[1]*$val,0,255); 1983 $col[2]=t3lib_div::intInRange($col[2]*$val,0,255); 1984 } else { 1985 $val=intval($cParts[1]); 1986 $col[0]=t3lib_div::intInRange($col[0]+$val,0,255); 1987 $col[1]=t3lib_div::intInRange($col[1]+$val,0,255); 1988 $col[2]=t3lib_div::intInRange($col[2]+$val,0,255); 1989 } 1990 } 1991 return $col; 1992 } 1993 1994 /** 1995 * Recode string 1996 * Used with text strings for fonts when languages has other character sets. 1997 * 1998 * @param string The text to recode 1999 * @return string The recoded string. Should be UTF-8 output. MAY contain entities (eg. { or &#quot; which should render as real chars). 2000 */ 2001 function recodeString($string) { 2002 // Recode string to UTF-8 from $this->nativeCharset: 2003 if ($this->nativeCharset && $this->nativeCharset!='utf-8') { 2004 $string = $this->csConvObj->utf8_encode($string,$this->nativeCharset); // Convert to UTF-8 2005 } 2006 2007 // Recode string accoding to TTFLocaleConv. Deprecated. 2008 if ($this->TTFLocaleConv) { 2009 $string = recode_string($this->TTFLocaleConv,$string); 2010 } 2011 2012 return $string; 2013 } 2014 2015 /** 2016 * Split a string into an array of individual characters 2017 * The function will look at $this->nativeCharset and if that is set, the input string is expected to be UTF-8 encoded, possibly with entities in it. Otherwise the string is supposed to be a single-byte charset which is just splitted by a for-loop. 2018 * 2019 * @param string The text string to split 2020 * @param boolean Return Unicode numbers instead of chars. 2021 * @return array Numerical array with a char as each value. 2022 */ 2023 function singleChars($theText,$returnUnicodeNumber=FALSE) { 2024 if ($this->nativeCharset) { 2025 return $this->csConvObj->utf8_to_numberarray($theText,1,$returnUnicodeNumber ? 0 : 1); // Get an array of separated UTF-8 chars 2026 } else { 2027 $output=array(); 2028 $c=strlen($theText); 2029 for($a=0;$a<$c;$a++) { 2030 $output[]=substr($theText,$a,1); 2031 } 2032 return $output; 2033 } 2034 } 2035 2036 /** 2037 * Create an array with object position/boundaries based on input TypoScript configuration (such as the "align" property is used), the work area definition and $BB array 2038 * 2039 * @param array TypoScript configuration for a GIFBUILDER object 2040 * @param array Workarea definition 2041 * @param array BB (Bounding box) array. Not just used for TEXT objects but also for others 2042 * @return array [0]=x, [1]=y, [2]=w, [3]=h 2043 * @access private 2044 * @see copyGifOntoGif(), makeBox(), crop() 2045 */ 2046 function objPosition($conf,$workArea,$BB) { 2047 // offset, align, valign, workarea 2048 $result=Array(); 2049 $result[2] = $BB[0]; 2050 $result[3] = $BB[1]; 2051 $w=$workArea[2]; 2052 $h=$workArea[3]; 2053 2054 $align = explode(',',$conf['align']); 2055 $align[0] = strtolower(substr(trim($align[0]),0,1)); 2056 $align[1] = strtolower(substr(trim($align[1]),0,1)); 2057 2058 switch($align[0]) { 2059 case 'r': 2060 $result[0]=$w-$result[2]; 2061 break; 2062 case 'c': 2063 $result[0] = round(($w-$result[2])/2); 2064 break; 2065 default: 2066 $result[0] = 0; 2067 break; 2068 } 2069 switch($align[1]) { 2070 case 'b': 2071 $result[1] = $h-$result[3]; // y pos 2072 break; 2073 case 'c': 2074 $result[1] = round(($h-$result[3])/2); 2075 break; 2076 default: 2077 $result[1]=0; 2078 break; 2079 } 2080 $result = $this->applyOffset($result,t3lib_div::intExplode(',',$conf['offset'])); 2081 $result = $this->applyOffset($result,$workArea); 2082 return $result; 2083 } 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 /*********************************** 2106 * 2107 * Scaling, Dimensions of images 2108 * 2109 ***********************************/ 2110 2111 /** 2112 * Converts $imagefile to another file in temp-dir of type $newExt (extension). 2113 * 2114 * @param string The image filepath 2115 * @param string New extension, eg. "gif", "png", "jpg", "tif". If $newExt is NOT set, the new imagefile will be of the original format. If newExt = 'WEB' then one of the web-formats is applied. 2116 * @param string Width. $w / $h is optional. If only one is given the image is scaled proportionally. If an 'm' exists in the $w or $h and if both are present the $w and $h is regarded as the Maximum w/h and the proportions will be kept 2117 * @param string Height. See $w 2118 * @param string Additional ImageMagick parameters. 2119 * @param string Refers to which frame-number to select in the image. '' or 0 will select the first frame, 1 will select the next and so on... 2120 * @param array An array with options passed to getImageScale (see this function). 2121 * @param boolean If set, then another image than the input imagefile MUST be returned. Otherwise you can risk that the input image is good enough regarding messures etc and is of course not rendered to a new, temporary file in typo3temp/. But this option will force it to. 2122 * @return array [0]/[1] is w/h, [2] is file extension and [3] is the filename. 2123 * @see getImageScale(), typo3/show_item.php, fileList_ext::renderImage(), tslib_cObj::getImgResource(), SC_tslib_showpic::show(), maskImageOntoImage(), copyImageOntoImage(), scale() 2124 */ 2125 function imageMagickConvert($imagefile,$newExt='',$w='',$h='',$params='',$frame='',$options='',$mustCreate=0) { 2126 if ($this->NO_IMAGE_MAGICK) { 2127 // Returning file info right away 2128 return $this->getImageDimensions($imagefile); 2129 } 2130 2131 if($info=$this->getImageDimensions($imagefile)) { 2132 $newExt=strtolower(trim($newExt)); 2133 if (!$newExt) { // If no extension is given the original extension is used 2134 $newExt = $info[2]; 2135 } 2136 if ($newExt=='web') { 2137 if (t3lib_div::inList($this->webImageExt,$info[2])) { 2138 $newExt = $info[2]; 2139 } else { 2140 $newExt = $this->gif_or_jpg($info[2],$info[0],$info[1]); 2141 if (!$params) { 2142 $params = $this->cmds[$newExt]; 2143 } 2144 } 2145 } 2146 if (t3lib_div::inList($this->imageFileExt,$newExt)) { 2147 if (strstr($w.$h, 'm')) {$max=1;} else {$max=0;} 2148 2149 $data = $this->getImageScale($info,$w,$h,$options); 2150 $w=$data['origW']; 2151 $h=$data['origH']; 2152 2153 // if no convertion should be performed 2154 $wh_noscale = (!$w && !$h) || ($data[0]==$info[0] && $data[1]==$info[1]); // this flag is true if the width / height does NOT dictate the image to be scaled!! (that is if no w/h is given or if the destination w/h matches the original image-dimensions.... 2155 2156 if ($wh_noscale && !$data['crs'] && !$params && !$frame && $newExt==$info[2] && !$mustCreate) { 2157 $info[3] = $imagefile; 2158 return $info; 2159 } 2160 $info[0]=$data[0]; 2161 $info[1]=$data[1]; 2162 2163 $frame = $this->noFramePrepended ? '' : '['.intval($frame).']'; 2164 2165 if (!$params) { 2166 $params = $this->cmds[$newExt]; 2167 } 2168 2169 $command = $this->scalecmd.' '.$info[0].'x'.$info[1].'! '.$params.' '; 2170 $cropscale = ($data['crs'] ? 'crs-V'.$data['cropV'].'H'.$data['cropH'] : ''); 2171 2172 if ($this->alternativeOutputKey) { 2173 $theOutputName = t3lib_div::shortMD5($command.$cropscale.basename($imagefile).$this->alternativeOutputKey.$frame); 2174 } else { 2175 $theOutputName = t3lib_div::shortMD5($command.$cropscale.$imagefile.filemtime($imagefile).$frame); 2176 } 2177 if ($this->imageMagickConvert_forceFileNameBody) { 2178 $theOutputName = $this->imageMagickConvert_forceFileNameBody; 2179 $this->imageMagickConvert_forceFileNameBody=''; 2180 } 2181 2182 // Making the temporary filename: 2183 $this->createTempSubDir('pics/'); 2184 $output = $this->absPrefix.$this->tempPath.'pics/'.$this->filenamePrefix.$theOutputName.'.'.$newExt; 2185 2186 // Register temporary filename: 2187 $GLOBALS['TEMP_IMAGES_ON_PAGE'][] = $output; 2188 2189 // Cropscaling: 2190 if ($data['crs']) { 2191 if ($this->dontCheckForExistingTempFile || !$this->file_exists_typo3temp_file($output, $imagefile)) { 2192 $crsOutput = str_replace('pics/', 'pics/crs-', $output); 2193 $this->imageMagickExec($imagefile.$frame, $crsOutput, $command); 2194 $gifCreator = t3lib_div::makeInstance('tslib_gifbuilder'); 2195 $gifCreator->init(); 2196 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'] !== 0) { 2197 if (!$data['origW']) { $data['origW'] = $data[0]; } 2198 if (!$data['origH']) { $data['origH'] = $data[1]; } 2199 $ofX = intval(($data['origW'] - $data[0]) * ($data['cropH']+100)/200); 2200 $ofY = intval(($data['origH'] - $data[1]) * ($data['cropV']+100)/200); 2201 $tmpParm = Array('XY' => intval($data['origW']).','.intval($data['origH']), 2202 '10' => 'IMAGE', 2203 '10.' => array('file'=> $crsOutput, 'offset'=> $ofX.','.$ofY), 2204 ); 2205 $gifCreator->start($tmpParm, array()); 2206 $newoutput = $gifCreator->gifBuild(); 2207 if (!copy($newoutput,$output)) { 2208 $output = $newoutput; 2209 } 2210 } else { 2211 $output = $crsOutput; 2212 } 2213 } 2214 } elseif ($this->dontCheckForExistingTempFile || !$this->file_exists_typo3temp_file($output,$imagefile)) { 2215 $this->imageMagickExec($imagefile.$frame,$output,$command); 2216 } 2217 if (@file_exists($output)) { 2218 $info[3] = $output; 2219 $info[2] = $newExt; 2220 if ($params) { // params could realisticly change some imagedata! 2221 $info=$this->getImageDimensions($info[3]); 2222 } 2223 if ($info[2]==$this->gifExtension && !$this->dontCompress) { 2224 t3lib_div::gif_compress($info[3],''); // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD) 2225 } 2226 return $info; 2227 } 2228 } 2229 } 2230 } 2231 2232 /** 2233 * Gets the input image dimensions. 2234 * 2235 * @param string The image filepath 2236 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 2237 * @see imageMagickConvert(), tslib_cObj::getImgResource() 2238 */ 2239 function getImageDimensions($imageFile) { 2240 ereg('([^\.]*)$',$imageFile,$reg); 2241 if (@file_exists($imageFile) && t3lib_div::inList($this->imageFileExt,strtolower($reg[0]))) { 2242 if ($returnArr = $this->getCachedImageDimensions($imageFile)) { 2243 return $returnArr; 2244 } else { 2245 if ($temp = @getImageSize($imageFile)) { 2246 $returnArr = Array($temp[0], $temp[1], strtolower($reg[0]), $imageFile); 2247 } else { 2248 $returnArr = $this->imageMagickIdentify($imageFile); 2249 } 2250 if ($returnArr) { 2251 $this->cacheImageDimensions($returnArr); 2252 return $returnArr; 2253 } 2254 } 2255 } 2256 return false; 2257 } 2258 2259 /** 2260 * Cache the result of the getImageDimensions function into the database. Does not check if the 2261 * file exists! 2262 * 2263 * @param array $identifyResult: Result of the getImageDimensions function 2264 * @return boolean True if operation was successful 2265 * @author Michael Stucki <michael@typo3.org> / Robert Lemke <rl@robertlemke.de> 2266 */ 2267 function cacheImageDimensions($identifyResult) { 2268 global $TYPO3_DB; 2269 // Create a md5 hash of the filename 2270 $md5Hash = md5_file($identifyResult[3]); 2271 if ($md5Hash) { 2272 $fieldArr = array ( 2273 'md5hash' => $md5Hash, 2274 'md5filename' => md5($identifyResult[3]), 2275 'tstamp' => time(), 2276 'filename' => $identifyResult[3], 2277 'imagewidth' => $identifyResult[0], 2278 'imageheight' => $identifyResult[1], 2279 ); 2280 $TYPO3_DB->exec_INSERTquery('cache_imagesizes', $fieldArr); 2281 if (!$err = $TYPO3_DB->sql_error()) { 2282 return true; 2283 } 2284 } 2285 return false; 2286 } 2287 2288 /** 2289 * Fetch the cached imageDimensions from the MySQL database. Does not check if the image file exists! 2290 * 2291 * @param string The image filepath 2292 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 2293 * @author Michael Stucki <michael@typo3.org> / Robert Lemke <rl@robertlemke.de> 2294 */ 2295 function getCachedImageDimensions($imageFile) { 2296 global $TYPO3_DB; 2297 // Create a md5 hash of the filename 2298 $md5Hash = md5_file($imageFile); 2299 ereg('([^\.]*)$',$imageFile,$reg); 2300 $res = $TYPO3_DB->exec_SELECTquery ('md5hash, imagewidth, imageheight', 'cache_imagesizes', 'md5filename='.$TYPO3_DB->fullQuoteStr(md5($imageFile),'cache_imagesizes')); 2301 if ($res) { 2302 if ($row = $TYPO3_DB->sql_fetch_assoc($res)) { 2303 if ($row['md5hash']!=$md5Hash) { 2304 // file has changed, delete the row 2305 $TYPO3_DB->exec_DELETEquery ('cache_imagesizes', 'md5hash='.$TYPO3_DB->fullQuoteStr($row['md5hash'],'cache_imagesizes')); 2306 } else { 2307 return (array($row['imagewidth'], $row['imageheight'], strtolower($reg[0]), $imageFile)); 2308 } 2309 } 2310 } 2311 return false; 2312 } 2313 2314 /** 2315 * Get numbers for scaling the image based on input 2316 * 2317 * @param array Current image information: Width, Height etc. 2318 * @param integer "required" width 2319 * @param integer "required" height 2320 * @param array Options: Keys are like "maxW", "maxH", "minW", "minH" 2321 * @return array 2322 * @access private 2323 * @see imageMagickConvert() 2324 */ 2325 function getImageScale($info,$w,$h,$options) { 2326 if (strstr($w.$h, 'm')) {$max=1;} else {$max=0;} 2327 2328 if (strstr($w.$h, 'c')) { 2329 $out['cropH'] = intval(substr(strstr($w, 'c'), 1)); 2330 $out['cropV'] = intval(substr(strstr($h, 'c'), 1)); 2331 $crs = true; 2332 } else { 2333 $crs = false; 2334 } 2335 $out['crs'] = $crs; 2336 2337 $w=intval($w); 2338 $h=intval($h); 2339 // if there are max-values... 2340 if ($options['maxW']) { 2341 if ($w) { // if width is given... 2342 if ($w>$options['maxW']) { 2343 $w=$options['maxW']; 2344 $max=1; // height should follow 2345 } 2346 } else { 2347 if ($info[0]>$options['maxW']) { 2348 $w=$options['maxW']; 2349 $max=1; // height should follow 2350 } 2351 } 2352 } 2353 if ($options['maxH']) { 2354 if ($h) { // if height is given... 2355 if ($h>$options['maxH']) { 2356 $h=$options['maxH']; 2357 $max=1; // height should follow 2358 } 2359 } else { 2360 if ($info[1]>$options['maxH']) { // Changed [0] to [1] 290801 2361 $h=$options['maxH']; 2362 $max=1; // height should follow 2363 } 2364 } 2365 } 2366 $out['origW']=$w; 2367 $out['origH']=$h; 2368 $out['max'] = $max; 2369 2370 if (!$this->mayScaleUp) { 2371 if ($w>$info[0]){$w=$info[0];} 2372 if ($h>$info[1]){$h=$info[1];} 2373 } 2374 if ($w || $h) { // if scaling should be performed 2375 if ($w && !$h) { 2376 $info[1] = ceil($info[1]*($w/$info[0])); 2377 $info[0] = $w; 2378 } 2379 if (!$w && $h) { 2380 $info[0] = ceil($info[0]*($h/$info[1])); 2381 $info[1] = $h; 2382 } 2383 if ($w && $h) { 2384 if ($max) { 2385 $ratio = $info[0]/$info[1]; 2386 if ($h*$ratio > $w) { 2387 $h = round($w/$ratio); 2388 } else { 2389 $w = round($h*$ratio); 2390 } 2391 } 2392 if ($crs) { 2393 $ratio = $info[0] / $info[1]; 2394 if ($h * $ratio < $w) { 2395 $h = round($w / $ratio); 2396 } else { 2397 $w = round($h * $ratio); 2398 } 2399 } 2400 $info[0] = $w; 2401 $info[1] = $h; 2402 } 2403 } 2404 $out[0]=$info[0]; 2405 $out[1]=$info[1]; 2406 // Set minimum-measures! 2407 if ($options['minW'] && $out[0]<$options['minW']) { 2408 if (($max || $crs) && $out[0]) { 2409 $out[1]= round($out[1]*$options['minW']/$out[0]); 2410 } 2411 $out[0]=$options['minW']; 2412 } 2413 if ($options['minH'] && $out[1]<$options['minH']) { 2414 if (($max || $crs) && $out[1]) { 2415 $out[0]= round($out[0]*$options['minH']/$out[1]); 2416 } 2417 $out[1]=$options['minH']; 2418 } 2419 2420 return $out; 2421 } 2422 2423 /** 2424 * Used to check if a certain process of scaling an image is already being carried out (can be logged in the SQL database) 2425 * 2426 * @param string Output imagefile 2427 * @param string Original basis file 2428 * @return boolean Returns true if the file is already being made; thus "true" means "Don't render the image again" 2429 * @access private 2430 */ 2431 function file_exists_typo3temp_file($output,$orig='') { 2432 if ($this->enable_typo3temp_db_tracking) { 2433 if (@file_exists($output)) { // If file exists, then we return immediately 2434 return 1; 2435 } else { // If not, we look up in the cache_typo3temp_log table to see if there is a image being rendered right now. 2436 $md5Hash=md5($output); 2437 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('md5hash', 'cache_typo3temp_log', 'md5hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log').' AND tstamp>'.(time()-30)); 2438 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // If there was a record, the image is being generated by another proces (we assume) 2439 if (is_object($GLOBALS['TSFE'])) $GLOBALS['TSFE']->set_no_cache(); // ...so we set no_cache, because we dont want this page (which will NOT display an image...!) to be cached! (Only a page with the correct image on...) 2440 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('typo3temp_log: Assume this file is being rendered now: '.$output); 2441 return 2; // Return 'success - 2' 2442 } else { // If the current time is more than 30 seconds since this record was written, we clear the record, write a new and render the image. 2443 2444 $insertFields = array( 2445 'md5hash' => $md5Hash, 2446 'tstamp' => time(), 2447 'filename' => $output, 2448 'orig_filename' => $orig 2449 ); 2450 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_typo3temp_log', 'md5hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log')); 2451 $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_typo3temp_log', $insertFields); 2452 2453 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('typo3temp_log: The row did not exist, so a new is written and file is being processed: '.$output); 2454 return 0; 2455 } 2456 } 2457 } else { 2458 return @file_exists($output); 2459 } 2460 } 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 /*********************************** 2480 * 2481 * ImageMagick API functions 2482 * 2483 ***********************************/ 2484 2485 /** 2486 * Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 2487 * Using ImageMagick 2488 * 2489 * @param string The relative (to PATH_site) image filepath 2490 * @return array 2491 */ 2492 function imageMagickIdentify($imagefile) { 2493 if (!$this->NO_IMAGE_MAGICK) { 2494 $frame = $this->noFramePrepended?'':'[0]'; 2495 $cmd = t3lib_div::imageMagickCommand('identify', $this->wrapFileName($imagefile).$frame); 2496 $returnVal = array(); 2497 exec($cmd, $returnVal); 2498 $splitstring=$returnVal[0]; 2499 $this->IM_commands[] = Array ('identify',$cmd,$returnVal[0]); 2500 if ($splitstring) { 2501 ereg('([^\.]*)$',$imagefile,$reg); 2502 $splitinfo = explode(' ', $splitstring); 2503 while (list($key,$val) = each($splitinfo)) { 2504 $temp = ''; 2505 if ($val) {$temp = explode('x', $val);} 2506 if (intval($temp[0]) && intval($temp[1])) { 2507 $dim=$temp; 2508 break; 2509 } 2510 } 2511 if ($dim[0] && $dim[1]) { 2512 return Array($dim[0], $dim[1], strtolower($reg[0]), $imagefile); 2513 } 2514 } 2515 } 2516 } 2517 2518 /** 2519 * Executes a ImageMagick "convert" on two filenames, $input and $output using $params before them. 2520 * Can be used for many things, mostly scaling and effects. 2521 * 2522 * @param string The relative (to PATH_site) image filepath, input file (read from) 2523 * @param string The relative (to PATH_site) image filepath, output filename (written to) 2524 * @param string ImageMagick parameters 2525 * @return string The result of a call to PHP function "exec()" 2526 */ 2527 function imageMagickExec($input,$output,$params) { 2528 if (!$this->NO_IMAGE_MAGICK) { 2529 $cmd = t3lib_div::imageMagickCommand('convert', $params.' '.$this->wrapFileName($input).' '.$this->wrapFileName($output)); 2530 $this->IM_commands[] = array($output,$cmd); 2531 2532 $ret = exec($cmd); 2533 t3lib_div::fixPermissions($this->wrapFileName($output)); // Change the permissions of the file 2534 2535 return $ret; 2536 } 2537 } 2538 2539 /** 2540 * Executes a ImageMagick "combine" (or composite in newer times) on four filenames - $input, $overlay and $mask as input files and $output as the output filename (written to) 2541 * Can be used for many things, mostly scaling and effects. 2542 * 2543 * @param string The relative (to PATH_site) image filepath, bottom file 2544 * @param string The relative (to PATH_site) image filepath, overlay file (top) 2545 * @param string The relative (to PATH_site) image filepath, the mask file (grayscale) 2546 * @param string The relative (to PATH_site) image filepath, output filename (written to) 2547 * @param [type] $handleNegation: ... 2548 * @return void 2549 */ 2550 function combineExec($input,$overlay,$mask,$output, $handleNegation = false) { 2551 if (!$this->NO_IMAGE_MAGICK) { 2552 $params = '-colorspace GRAY +matte'; 2553 if ($handleNegation) { 2554 if ($this->maskNegate) { 2555 $params .= ' '.$this->maskNegate; 2556 } 2557 } 2558 $theMask = $this->randomName().'.'.$this->gifExtension; 2559 $this->imageMagickExec($mask, $theMask, $params); 2560 $cmd = t3lib_div::imageMagickCommand('combine', '-compose over +matte '.$this->wrapFileName($input).' '.$this->wrapFileName($overlay).' '.$this->wrapFileName($theMask).' '.$this->wrapFileName($output)); // +matte = no alpha layer in output 2561 $this->IM_commands[] = Array ($output,$cmd); 2562 2563 $ret = exec($cmd); 2564 t3lib_div::fixPermissions($this->wrapFileName($output)); // Change the permissions of the file 2565 2566 if (is_file($theMask)) { 2567 @unlink($theMask); 2568 } 2569 2570 return $ret; 2571 } 2572 } 2573 2574 /** 2575 * Wrapping the input filename in double-quotes 2576 * 2577 * @param string Input filename 2578 * @return string The output wrapped in "" (if there are spaces in the filepath) 2579 * @access private 2580 */ 2581 function wrapFileName($inputName) { 2582 if (strstr($inputName,' ')) { 2583 $inputName='"'.$inputName.'"'; 2584 } 2585 return $inputName; 2586 } 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 /*********************************** 2611 * 2612 * Various IO functions 2613 * 2614 ***********************************/ 2615 2616 /** 2617 * Returns true if the input file existed 2618 * 2619 * @param string Input file to check 2620 * @return string Returns the filename if the file existed, otherwise empty. 2621 */ 2622 function checkFile($file) { 2623 if (@is_file($file)) { 2624 return $file; 2625 } else { 2626 return ''; 2627 } 2628 } 2629 2630 /** 2631 * Creates subdirectory in typo3temp/ if not already found. 2632 * 2633 * @param string Name of sub directory 2634 * @return boolean Result of t3lib_div::mkdir(), true if it went well. 2635 */ 2636 function createTempSubDir($dirName) { 2637 2638 // Checking if the this->tempPath is already prefixed with PATH_site and if not, prefix it with that constant. 2639 if (t3lib_div::isFirstPartOfStr($this->tempPath,PATH_site)) { 2640 $tmpPath = $this->tempPath; 2641 } else { 2642 $tmpPath = PATH_site.$this->tempPath; 2643 } 2644 2645 // Making the temporary filename: 2646 if (!@is_dir($tmpPath.$dirName)) { 2647 return t3lib_div::mkdir($tmpPath.$dirName); 2648 } 2649 } 2650 2651 /** 2652 * Applies an ImageMagick parameter to a GDlib image pointer resource by writing the resource to file, performing an IM operation upon it and reading back the result into the ImagePointer. 2653 * 2654 * @param pointer The image pointer (reference) 2655 * @param string The ImageMagick parameters. Like effects, scaling etc. 2656 * @return void 2657 */ 2658 function applyImageMagickToPHPGif(&$im, $command) { 2659 $tmpStr = $this->randomName(); 2660 $theFile = $tmpStr.'.'.$this->gifExtension; 2661 $this->ImageWrite($im, $theFile); 2662 $this->imageMagickExec($theFile,$theFile,$command); 2663 $tmpImg = $this->imageCreateFromFile($theFile); 2664 if ($tmpImg) { 2665 ImageDestroy($im); 2666 $im = $tmpImg; 2667 $this->w = imagesx($im); 2668 $this->h = imagesy($im); 2669 } 2670 if (!$this->dontUnlinkTempFiles) { 2671 unlink($theFile); 2672 } 2673 } 2674 2675 /** 2676 * Returns an image extension for an output image based on the number of pixels of the output and the file extension of the original file. 2677 * For example: If the number of pixels exceeds $this->pixelLimitGif (normally 10000) then it will be a "jpg" string in return. 2678 * 2679 * @param string The file extension, lowercase. 2680 * @param integer The width of the output image. 2681 * @param integer The height of the output image. 2682 * @return string The filename, either "jpg" or "gif"/"png" (whatever $this->gifExtension is set to.) 2683 */ 2684 function gif_or_jpg($type,$w,$h) { 2685 if ($type=='ai' || $w*$h < $this->pixelLimitGif) { 2686 return $this->gifExtension; 2687 } else { 2688 return 'jpg'; 2689 } 2690 } 2691 2692 /** 2693 * Writing the internal image pointer, $this->im, to file based on the extension of the input filename 2694 * Used in GIFBUILDER 2695 * Uses $this->setup['reduceColors'] for gif/png images and $this->setup['quality'] for jpg images to reduce size/quality if needed. 2696 * 2697 * @param string The filename to write to. 2698 * @return string Returns input filename 2699 * @see tslib_gifBuilder::gifBuild() 2700 */ 2701 function output($file) { 2702 if ($file) { 2703 $reg = array(); 2704 ereg('([^\.]*)$',$file,$reg); 2705 $ext=strtolower($reg[0]); 2706 switch($ext) { 2707 case 'gif': 2708 case 'png': 2709 if ($this->ImageWrite($this->im, $file)) { 2710 // ImageMagick operations 2711 if ($this->setup['reduceColors'] || (!$this->png_truecolor && $this->truecolor)) { 2712 $reduced = $this->IMreduceColors($file, t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256)); 2713 if ($reduced) { 2714 @copy($reduced, $file); 2715 @unlink($reduced); 2716 } 2717 } 2718 t3lib_div::gif_compress($file, 'IM'); // Compress with IM! (adds extra compression, LZW from ImageMagick) (Workaround for the absence of lzw-compression in GD) 2719 } 2720 break; 2721 case 'jpg': 2722 case 'jpeg': 2723 $quality = 0; // Use the default 2724 if($this->setup['quality']) { 2725 $quality = t3lib_div::intInRange($this->setup['quality'],10,100); 2726 } 2727 if ($this->ImageWrite($this->im, $file, $quality)); 2728 break; 2729 } 2730 $GLOBALS['TEMP_IMAGES_ON_PAGE'][]=$file; 2731 } 2732 return $file; 2733 } 2734 2735 /** 2736 * Destroy internal image pointer, $this->im 2737 * 2738 * @return void 2739 * @see tslib_gifBuilder::gifBuild() 2740 */ 2741 function destroy() { 2742 ImageDestroy($this->im); 2743 } 2744 2745 /** 2746 * Returns Image Tag for input image information array. 2747 * 2748 * @param array Image information array, key 0/1 is width/height and key 3 is the src value 2749 * @return string Image tag for the input image information array. 2750 */ 2751 function imgTag ($imgInfo) { 2752 return '<img src="'.$imgInfo[3].'" width="'.$imgInfo[0].'" height="'.$imgInfo[1].'" border="0" alt="" />'; 2753 } 2754 2755 /** 2756 * Writes the input GDlib image pointer to file 2757 * 2758 * @param pointer The GDlib image resource pointer 2759 * @param string The filename to write to 2760 * @param integer The image quality (for JPEGs) 2761 * @return mixed The output of either imageGif, imagePng or imageJpeg based on the filename to write 2762 * @see maskImageOntoImage(), scale(), output() 2763 */ 2764 function ImageWrite($destImg, $theImage, $quality=0) { 2765 imageinterlace ($destImg,0); 2766 $ext = strtolower(substr($theImage, strrpos($theImage, '.')+1)); 2767 switch ($ext) { 2768 case 'jpg': 2769 case 'jpeg': 2770 if (function_exists('imageJpeg')) { 2771 if ($quality == 0) { 2772 $quality = $this->jpegQuality; 2773 } 2774 return imageJpeg($destImg, $theImage, $quality); 2775 } 2776 break; 2777 case 'gif': 2778 if (function_exists('imageGif')) { 2779 if ($this->truecolor) { 2780 imagetruecolortopalette($destImg, true, 256); 2781 } 2782 return imageGif($destImg, $theImage); 2783 } 2784 break; 2785 case 'png': 2786 if (function_exists('imagePng')) { 2787 return ImagePng($destImg, $theImage); 2788 } 2789 break; 2790 } 2791 return false; // Extension invalid or write-function does not exist 2792 } 2793 2794 2795 2796 /** 2797 * Writes the input GDlib image pointer to file. Now just a wrapper to ImageWrite. 2798 * 2799 * @param pointer The GDlib image resource pointer 2800 * @param string The filename to write to 2801 * @return mixed The output of either imageGif, imagePng or imageJpeg based on the filename to write 2802 * @see imageWrite() 2803 * @deprecated 2804 */ 2805 function imageGif($destImg, $theImage) { 2806 return $this->imageWrite($destImg, $theImage); 2807 } 2808 2809 /** 2810 * This function has been renamed and only exists for providing backwards compatibility. 2811 * Please use $this->imageCreateFromFile() instead. 2812 * 2813 * @param string Image filename 2814 * @return pointer Image Resource pointer 2815 * @deprecated 2816 */ 2817 function imageCreateFromGif($sourceImg) { 2818 return $this->imageCreateFromFile($sourceImg); 2819 } 2820 2821 /** 2822 * Creates a new GDlib image resource based on the input image filename. 2823 * If it fails creating a image from the input file a blank gray image with the dimensions of the input image will be created instead. 2824 * 2825 * @param string Image filename 2826 * @return pointer Image Resource pointer 2827 */ 2828 function imageCreateFromFile($sourceImg) { 2829 $imgInf = pathinfo($sourceImg); 2830 $ext = strtolower($imgInf['extension']); 2831 2832 switch ($ext) { 2833 case 'gif': 2834 if (function_exists('imagecreatefromgif')) { 2835 return imageCreateFromGif($sourceImg); 2836 } 2837 break; 2838 case 'png': 2839 if (function_exists('imagecreatefrompng')) { 2840 return imageCreateFromPng($sourceImg); 2841 } 2842 break; 2843 case 'jpg': 2844 case 'jpeg': 2845 if (function_exists('imagecreatefromjpeg')) { 2846 return imageCreateFromJpeg($sourceImg); 2847 } 2848 break; 2849 } 2850 2851 // If non of the above: 2852 $i = @getimagesize($sourceImg); 2853 $im = $this->imagecreate($i[0],$i[1]); 2854 $Bcolor = ImageColorAllocate($im, 128,128,128); 2855 ImageFilledRectangle($im, 0, 0, $i[0], $i[1], $Bcolor); 2856 return $im; 2857 } 2858 2859 2860 /** 2861 * Creates a new GD image resource. Wrapper for imagecreate(truecolor) depended if GD2 is used. 2862 * 2863 * @param integer Width of image 2864 * @param integer Height of image 2865 * @return pointer Image Resource pointer 2866 */ 2867 function imagecreate($w, $h) { 2868 if($this->truecolor && function_exists('imagecreatetruecolor')) { 2869 return imagecreatetruecolor($w, $h); 2870 } else { 2871 return imagecreate($w, $h); 2872 } 2873 2874 } 2875 2876 /** 2877 * Returns the HEX color value for an RGB color array 2878 * 2879 * @param array RGB color array 2880 * @return string HEX color value 2881 */ 2882 function hexColor($col) { 2883 $r = dechex($col[0]); 2884 if (strlen($r)<2) { $r = '0'.$r; } 2885 $g = dechex($col[1]); 2886 if (strlen($g)<2) { $g = '0'.$g; } 2887 $b = dechex($col[2]); 2888 if (strlen($b)<2) { $b = '0'.$b; } 2889 return '#'.$r.$g.$b; 2890 } 2891 2892 /** 2893 * Unifies all colors given in the colArr color array to the first color in the array. 2894 * 2895 * @param pointer Image resource 2896 * @param array Array containing RGB color arrays 2897 * @param [type] $closest: ... 2898 * @return integer The index of the unified color 2899 */ 2900 function unifyColors(&$img, $colArr, $closest = false) { 2901 $retCol = -1; 2902 if (is_array($colArr) && count($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) { 2903 $firstCol = array_shift($colArr); 2904 $firstColArr = $this->convertColor($firstCol); 2905 if (count($colArr)>1) { 2906 $origName = $preName = $this->randomName().'.png'; 2907 $postName = $this->randomName().'.png'; 2908 $this->imageWrite($img, $preName); 2909 $firstCol = $this->hexColor($firstColArr); 2910 foreach ($colArr as $transparentColor) { 2911 $transparentColor = $this->convertColor($transparentColor); 2912 $transparentColor = $this->hexColor($transparentColor); 2913 $cmd = '-fill "'.$firstCol.'" -opaque "'.$transparentColor.'"'; 2914 $this->imageMagickExec($preName, $postName, $cmd); 2915 $preName = $postName; 2916 } 2917 $this->imageMagickExec($postName, $origName, ''); 2918 if (@is_file($origName)) { 2919 $tmpImg = $this->imageCreateFromFile($origName); 2920 } 2921 } else { 2922 $tmpImg = $img; 2923 } 2924 if ($tmpImg) { 2925 $img = $tmpImg; 2926 if ($closest) { 2927 $retCol = ImageColorClosest ($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]); 2928 } else { 2929 $retCol = ImageColorExact ($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]); 2930 } 2931 } 2932 // unlink files from process 2933 if (!$this->dontUnlinkTempFiles) { 2934 if ($origName) { 2935 @unlink($origName); 2936 } 2937 if ($postName) { 2938 @unlink($postName); 2939 } 2940 } 2941 } 2942 return $retCol; 2943 } 2944 2945 2946 } 2947 2948 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php']) { 2949 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php']); 2950 } 2951 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sun Nov 25 17:13:16 2007 | par Balluche grâce à PHPXref 0.7 |
|