|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com) 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 /** 00028 * Standard graphical functions 00029 * 00030 * $Id: class.t3lib_stdgraphic.php 10662 2011-02-28 19:28:53Z lolli $ 00031 * Revised for TYPO3 3.6 July/2003 by Kasper Skårhøj 00032 * 00033 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00034 */ 00035 /** 00036 * [CLASS/FUNCTION INDEX of SCRIPT] 00037 * 00038 * 00039 * 00040 * 155: class t3lib_stdGraphic 00041 * 236: function init() 00042 * 00043 * SECTION: Layering images / "IMAGE" GIFBUILDER object 00044 * 366: function maskImageOntoImage(&$im,$conf,$workArea) 00045 * 436: function copyImageOntoImage(&$im,$conf,$workArea) 00046 * 458: function copyGifOntoGif(&$im,$cpImg,$conf,$workArea) 00047 * 537: function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) 00048 * 00049 * SECTION: Text / "TEXT" GIFBUILDER object 00050 * 587: function makeText(&$im,$conf,$workArea) 00051 * 707: function txtPosition($conf,$workArea,$BB) 00052 * 761: function calcBBox($conf) 00053 * 820: function addToMap($cords,$conf) 00054 * 843: function calcTextCordsForMap($cords,$offset, $conf) 00055 * 878: function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF=1) 00056 * 915: function fontResize($conf) 00057 * 958: function ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF=1) 00058 * 1005: function ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering,$sF=1) 00059 * 1058: function splitString($string,$splitRendering,$fontSize,$fontFile) 00060 * 1208: function calcWordSpacing($conf, $scaleFactor=1) 00061 * 1227: function getTextScalFactor($conf) 00062 * 00063 * SECTION: Other GIFBUILDER objects related to TEXT 00064 * 1262: function makeOutline(&$im,$conf,$workArea,$txtConf) 00065 * 1291: function circleOffset($distance, $iterations) 00066 * 1315: function makeEmboss(&$im,$conf,$workArea,$txtConf) 00067 * 1337: function makeShadow(&$im,$conf,$workArea,$txtConf) 00068 * 00069 * SECTION: Other GIFBUILDER objects 00070 * 1469: function makeBox(&$im,$conf,$workArea) 00071 * 1491: function makeEffect(&$im, $conf) 00072 * 1506: function IMparams($setup) 00073 * 1589: function adjust(&$im, $conf) 00074 * 1621: function crop(&$im,$conf) 00075 * 1652: function scale(&$im,$conf) 00076 * 1684: function setWorkArea($workArea) 00077 * 00078 * SECTION: Adjustment functions 00079 * 1725: function autolevels(&$im) 00080 * 1756: function outputLevels(&$im,$low,$high,$swap='') 00081 * 1788: function inputLevels(&$im,$low,$high,$swap='') 00082 * 1819: function reduceColors(&$im,$limit, $cols) 00083 * 1832: function IMreduceColors($file, $cols) 00084 * 00085 * SECTION: GIFBUILDER Helper functions 00086 * 1875: function prependAbsolutePath($fontFile) 00087 * 1889: function v5_sharpen($factor) 00088 * 1908: function v5_blur($factor) 00089 * 1925: function randomName() 00090 * 1938: function applyOffset($cords,$OFFSET) 00091 * 1951: function convertColor($string) 00092 * 2001: function recodeString($string) 00093 * 2023: function singleChars($theText,$returnUnicodeNumber=FALSE) 00094 * 2046: function objPosition($conf,$workArea,$BB) 00095 * 00096 * SECTION: Scaling, Dimensions of images 00097 * 2125: function imageMagickConvert($imagefile,$newExt='',$w='',$h='',$params='',$frame='',$options='',$mustCreate=0) 00098 * 2238: function getImageDimensions($imageFile) 00099 * 2266: function cacheImageDimensions($identifyResult) 00100 * 2298: function getCachedImageDimensions($imageFile) 00101 * 2332: function getImageScale($info,$w,$h,$options) 00102 * 2438: function file_exists_typo3temp_file($output,$orig='') 00103 * 00104 * SECTION: ImageMagick API functions 00105 * 2499: function imageMagickIdentify($imagefile) 00106 * 2534: function imageMagickExec($input,$output,$params) 00107 * 2557: function combineExec($input,$overlay,$mask,$output, $handleNegation = false) 00108 * 2588: function wrapFileName($inputName) 00109 * 00110 * SECTION: Various IO functions 00111 * 2629: function checkFile($file) 00112 * 2643: function createTempSubDir($dirName) 00113 * 2665: function applyImageMagickToPHPGif(&$im, $command) 00114 * 2691: function gif_or_jpg($type,$w,$h) 00115 * 2708: function output($file) 00116 * 2748: function destroy() 00117 * 2758: function imgTag ($imgInfo) 00118 * 2770: function ImageWrite($destImg, $theImage) 00119 * 2808: function imageGif($destImg, $theImage) 00120 * 2820: function imageCreateFromGif($sourceImg) 00121 * 2831: function imageCreateFromFile($sourceImg) 00122 * 2870: function imagecreate($w, $h) 00123 * 2885: function hexColor($col) 00124 * 2903: function unifyColors(&$img, $colArr, $closest = false) 00125 * 00126 * TOTAL FUNCTIONS: 66 00127 * (This index is automatically created/updated by the extension "extdeveval") 00128 * 00129 */ 00130 00131 00132 /** 00133 * Class contains a bunch of cool functions for manipulating graphics with GDlib/Freetype and ImageMagick 00134 * VERY OFTEN used with gifbuilder that extends this class and provides a TypoScript API to using these functions 00135 * 00136 * With TYPO3 4.4 GDlib 1.x support was dropped, also an option from config_default.php: 00137 * $TYPO3_CONF_VARS['GFX']['gdlib_2'] = 0, // String/Boolean. Set this if you are using the new GDlib 2.0.1+. If you don't set this flag and still use GDlib2, you might encounter strange behaviours like black images etc. This feature might take effect only if ImageMagick is installed and working as well! You can also use the value "no_imagecopyresized_fix" - in that case it will NOT try to fix a known issue where "imagecopyresized" does not work correctly. 00138 * 00139 * @author Kasper Skårhøj <kasperYYYY@typo3.com> 00140 * @package TYPO3 00141 * @subpackage t3lib 00142 * @see tslib_gifBuilder 00143 */ 00144 class t3lib_stdGraphic { 00145 00146 // Internal configuration, set in init() 00147 var $combineScript = 'combine'; // The ImageMagick filename used for combining two images. This name changed during the versions. 00148 var $noFramePrepended = 0; // If set, there is no frame pointer prepended to the filenames. 00149 var $GD2 = 1; // Set, if the GDlib used is version 2. @deprecated as of TYPO3 4.4, as this variables is now always set (GDlib2 always has this method, and PHP recommends to only use imagecreatetruecolor() over imagecreate()) 00150 var $imagecopyresized_fix = 0; // If set, imagecopyresized will not be called directly. For GD2 (some PHP installs?) 00151 var $gifExtension = 'gif'; // This should be changed to 'png' if you want this class to read/make PNG-files instead! 00152 var $gdlibExtensions = ''; // File formats supported by gdlib. This variable get's filled in "init" method 00153 var $png_truecolor = FALSE; // Set to true if generated png's should be truecolor by default 00154 var $truecolorColors = 0xffffff; // 16777216 Colors is the maximum value for PNG, JPEG truecolor images (24-bit, 8-bit / Channel) 00155 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. 00156 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! 00157 var $webImageExt = 'gif,jpg,jpeg,png'; // Commalist of web image extensions (can be shown by a webbrowser) 00158 var $maskNegate = ''; // Will be ' -negate' if ImageMagick ver 5.2+. See init(); 00159 var $NO_IM_EFFECTS = ''; 00160 var $cmds = array( 00161 'jpg' => '', 00162 'jpeg' => '', 00163 'gif' => '', 00164 'png' => '-colors 64' 00165 ); 00166 var $NO_IMAGE_MAGICK = ''; 00167 var $V5_EFFECTS = 0; 00168 var $im_version_4 = 0; 00169 var $mayScaleUp = 1; 00170 00171 // Variables for testing, alternative usage etc. 00172 var $filenamePrefix = ''; // Filename prefix for images scaled in imageMagickConvert() 00173 var $imageMagickConvert_forceFileNameBody = ''; // Forcing the output filename of imageMagickConvert() to this value. However after calling imageMagickConvert() it will be set blank again. 00174 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. 00175 var $dontCompress = 0; // Prevents imageMagickConvert() from compressing the gif-files with t3lib_div::gif_compress() 00176 var $dontUnlinkTempFiles = 0; // For debugging ONLY! 00177 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... 00178 00179 // Internal: 00180 var $IM_commands = array(); // All ImageMagick commands executed is stored in this array for tracking. Used by the Install Tools Image section 00181 var $workArea = array(); 00182 00183 // Constants: 00184 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. 00185 var $absPrefix = ''; // Prefix for relative paths. Used in "show_item.php" script. Is prefixed the output file name IN imageMagickConvert() 00186 var $scalecmd = '-geometry'; // ImageMagick scaling command; "-geometry" eller "-sample". Used in makeText() and imageMagickConvert() 00187 var $im5fx_blurSteps = '1x2,2x2,3x2,4x3,5x3,5x4,6x4,7x5,8x5,9x5'; // Used by v5_blur() to simulate 10 continuous steps of blurring 00188 var $im5fx_sharpenSteps = '1x2,2x2,3x2,2x3,3x3,4x3,3x4,4x4,4x5,5x5'; // Used by v5_sharpen() to simulate 10 continuous steps of sharpening. 00189 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 00190 var $colMap = array( // Array mapping HTML color names to RGB values. 00191 'aqua' => array(0, 255, 255), 00192 'black' => array(0, 0, 0), 00193 'blue' => array(0, 0, 255), 00194 'fuchsia' => array(255, 0, 255), 00195 'gray' => array(128, 128, 128), 00196 'green' => array(0, 128, 0), 00197 'lime' => array(0, 255, 0), 00198 'maroon' => array(128, 0, 0), 00199 'navy' => array(0, 0, 128), 00200 'olive' => array(128, 128, 0), 00201 'purple' => array(128, 0, 128), 00202 'red' => array(255, 0, 0), 00203 'silver' => array(192, 192, 192), 00204 'teal' => array(0, 128, 128), 00205 'yellow' => array(255, 255, 0), 00206 'white' => array(255, 255, 255) 00207 ); 00208 00209 /** 00210 * Charset conversion object: 00211 * 00212 * @var t3lib_cs 00213 */ 00214 var $csConvObj; 00215 var $nativeCharset = ''; // Is set to the native character set of the input strings. 00216 00217 00218 /** 00219 * Init function. Must always call this when using the class. 00220 * This function will read the configuration information from $GLOBALS['TYPO3_CONF_VARS']['GFX'] can set some values in internal variables. 00221 * 00222 * @return void 00223 */ 00224 function init() { 00225 $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX']; 00226 00227 if (function_exists('imagecreatefromjpeg') && function_exists('imagejpeg')) { 00228 $this->gdlibExtensions .= ',jpg,jpeg'; 00229 } 00230 if (function_exists('imagecreatefrompng') && function_exists('imagepng')) { 00231 $this->gdlibExtensions .= ',png'; 00232 } 00233 if (function_exists('imagecreatefromgif') && function_exists('imagegif')) { 00234 $this->gdlibExtensions .= ',gif'; 00235 } 00236 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['png_truecolor']) { 00237 $this->png_truecolor = true; 00238 } 00239 if (!$gfxConf['im_version_5']) { 00240 t3lib_div::deprecationLog('The option $TYPO3_CONF_VARS[\'GFX\'][\'im_version_5\'] is not set, ImageMagic 4 is assumed. This is deprecated since TYPO3 4.5, support will be removed in TYPO3 4.6. Make sure to upgrade to ImageMagick version 6 or GraphichsMagick.'); 00241 $this->im_version_4 = true; 00242 } elseif ($gfxConf['im_version_5'] === 'im5') { 00243 t3lib_div::deprecationLog('The option $TYPO3_CONF_VARS[\'GFX\'][\'im_version_5\'] is set to \'im5\'. This is deprecated since TYPO3 4.5, support will be removed in TYPO3 4.6. Make sure to upgrade to ImageMagick version 6 or GraphichsMagick.'); 00244 } 00245 00246 // When GIFBUILDER gets used in truecolor mode 00247 // No colors parameter if we generate truecolor images. 00248 if ($this->png_truecolor) { 00249 $this->cmds['png'] = ''; 00250 } 00251 00252 // Setting default JPG parameters: 00253 $this->jpegQuality = t3lib_div::intInRange($gfxConf['jpg_quality'], 10, 100, 75); 00254 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -sharpen 50 -quality ' . $this->jpegQuality; 00255 00256 if ($gfxConf['im_combine_filename']) { 00257 $this->combineScript = $gfxConf['im_combine_filename']; 00258 } 00259 if ($gfxConf['im_noFramePrepended']) { 00260 $this->noFramePrepended = 1; 00261 } 00262 00263 // kept for backwards compatibility, can be turned on manually through localconf.php, 00264 // but not through the installer anymore 00265 $this->imagecopyresized_fix = ($gfxConf['gdlib_2'] === 'no_imagecopyresized_fix' ? 0 : 1); 00266 00267 if ($gfxConf['gdlib_png']) { 00268 $this->gifExtension = 'png'; 00269 } 00270 if ($gfxConf['enable_typo3temp_db_tracking']) { 00271 $this->enable_typo3temp_db_tracking = $gfxConf['enable_typo3temp_db_tracking']; 00272 } 00273 00274 $this->imageFileExt = $gfxConf['imagefile_ext']; 00275 00276 // This should be set if ImageMagick ver. 5+ is used. 00277 if ($gfxConf['im_negate_mask']) { 00278 // Boolean. Indicates if the mask images should be inverted first. 00279 // This depends of the ImageMagick version. Below ver. 5.1 this should be false. 00280 // Above ImageMagick version 5.2+ it should be true. 00281 // Just set the flag if the masks works opposite the intension! 00282 $this->maskNegate = ' -negate'; 00283 } 00284 if ($gfxConf['im_no_effects']) { 00285 // Boolean. This is necessary if using ImageMagick 5+. 00286 // Effects in Imagemagick 5+ tends to render very slowly!! 00287 // - therefore must be disabled in order not to perform sharpen, blurring and such. 00288 $this->NO_IM_EFFECTS = 1; 00289 00290 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -quality ' . $this->jpegQuality; 00291 } 00292 // ... but if 'im_v5effects' is set, don't care about 'im_no_effects' 00293 if ($gfxConf['im_v5effects']) { 00294 $this->NO_IM_EFFECTS = 0; 00295 $this->V5_EFFECTS = 1; 00296 00297 if ($gfxConf['im_v5effects'] > 0) { 00298 $this->cmds['jpg'] = $this->cmds['jpeg'] = '-colorspace RGB -quality ' . intval($gfxConf['jpg_quality']) . $this->v5_sharpen(10); 00299 } 00300 } 00301 00302 if (!$gfxConf['im']) { 00303 $this->NO_IMAGE_MAGICK = 1; 00304 } 00305 // Secures that images are not scaled up. 00306 if ($gfxConf['im_noScaleUp']) { 00307 $this->mayScaleUp = 0; 00308 } 00309 00310 if (TYPO3_MODE == 'FE') { 00311 $this->csConvObj = $GLOBALS['TSFE']->csConvObj; 00312 } elseif (is_object($GLOBALS['LANG'])) { // BE assumed: 00313 $this->csConvObj = $GLOBALS['LANG']->csConvObj; 00314 } else { // The object may not exist yet, so we need to create it now. Happens in the Install Tool for example. 00315 $this->csConvObj = t3lib_div::makeInstance('t3lib_cs'); 00316 } 00317 $this->nativeCharset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']; 00318 } 00319 00320 00321 /************************************************* 00322 * 00323 * Layering images / "IMAGE" GIFBUILDER object 00324 * 00325 *************************************************/ 00326 00327 /** 00328 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is true. 00329 * 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 00330 * The operation involves ImageMagick for combining. 00331 * 00332 * @param pointer GDlib image pointer 00333 * @param array TypoScript array with configuration for the GIFBUILDER object. 00334 * @param array The current working area coordinates. 00335 * @return void 00336 * @see tslib_gifBuilder::make() 00337 */ 00338 function maskImageOntoImage(&$im, $conf, $workArea) { 00339 if ($conf['file'] && $conf['mask']) { 00340 $imgInf = pathinfo($conf['file']); 00341 $imgExt = strtolower($imgInf['extension']); 00342 if (!t3lib_div::inList($this->gdlibExtensions, $imgExt)) { 00343 $BBimage = $this->imageMagickConvert($conf['file'], $this->gifExtension, '', '', '', '', ''); 00344 } else { 00345 $BBimage = $this->getImageDimensions($conf['file']); 00346 } 00347 $maskInf = pathinfo($conf['mask']); 00348 $maskExt = strtolower($maskInf['extension']); 00349 if (!t3lib_div::inList($this->gdlibExtensions, $maskExt)) { 00350 $BBmask = $this->imageMagickConvert($conf['mask'], $this->gifExtension, '', '', '', '', ''); 00351 } else { 00352 $BBmask = $this->getImageDimensions($conf['mask']); 00353 } 00354 if ($BBimage && $BBmask) { 00355 $w = imagesx($im); 00356 $h = imagesy($im); 00357 $tmpStr = $this->randomName(); 00358 $theImage = $tmpStr . '_img.' . $this->gifExtension; 00359 $theDest = $tmpStr . '_dest.' . $this->gifExtension; 00360 $theMask = $tmpStr . '_mask.' . $this->gifExtension; 00361 // prepare overlay image 00362 $cpImg = $this->imageCreateFromFile($BBimage[3]); 00363 $destImg = imagecreatetruecolor($w, $h); 00364 $Bcolor = ImageColorAllocate($destImg, 0, 0, 0); 00365 ImageFilledRectangle($destImg, 0, 0, $w, $h, $Bcolor); 00366 $this->copyGifOntoGif($destImg, $cpImg, $conf, $workArea); 00367 $this->ImageWrite($destImg, $theImage); 00368 imageDestroy($cpImg); 00369 imageDestroy($destImg); 00370 // prepare mask image 00371 $cpImg = $this->imageCreateFromFile($BBmask[3]); 00372 $destImg = imagecreatetruecolor($w, $h); 00373 $Bcolor = ImageColorAllocate($destImg, 0, 0, 0); 00374 ImageFilledRectangle($destImg, 0, 0, $w, $h, $Bcolor); 00375 $this->copyGifOntoGif($destImg, $cpImg, $conf, $workArea); 00376 $this->ImageWrite($destImg, $theMask); 00377 imageDestroy($cpImg); 00378 imageDestroy($destImg); 00379 // mask the images 00380 $this->ImageWrite($im, $theDest); 00381 00382 $this->combineExec($theDest, $theImage, $theMask, $theDest, TRUE); // Let combineExec handle maskNegation 00383 00384 $backIm = $this->imageCreateFromFile($theDest); // The main image is loaded again... 00385 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 00386 ImageColorTransparent($backIm, -1); 00387 $im = $backIm; 00388 } 00389 // unlink files from process 00390 if (!$this->dontUnlinkTempFiles) { 00391 unlink($theDest); 00392 unlink($theImage); 00393 unlink($theMask); 00394 } 00395 } 00396 } 00397 } 00398 00399 /** 00400 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is false (using only $conf['file']) 00401 * 00402 * @param pointer GDlib image pointer 00403 * @param array TypoScript array with configuration for the GIFBUILDER object. 00404 * @param array The current working area coordinates. 00405 * @return void 00406 * @see tslib_gifBuilder::make(), maskImageOntoImage() 00407 */ 00408 function copyImageOntoImage(&$im, $conf, $workArea) { 00409 if ($conf['file']) { 00410 if (!t3lib_div::inList($this->gdlibExtensions, $conf['BBOX'][2])) { 00411 $conf['BBOX'] = $this->imageMagickConvert($conf['BBOX'][3], $this->gifExtension, '', '', '', '', ''); 00412 $conf['file'] = $conf['BBOX'][3]; 00413 } 00414 $cpImg = $this->imageCreateFromFile($conf['file']); 00415 $this->copyGifOntoGif($im, $cpImg, $conf, $workArea); 00416 imageDestroy($cpImg); 00417 } 00418 } 00419 00420 /** 00421 * Copies two GDlib image pointers onto each other, using TypoScript configuration from $conf and the input $workArea definition. 00422 * 00423 * @param pointer GDlib image pointer, destination (bottom image) 00424 * @param pointer GDlib image pointer, source (top image) 00425 * @param array TypoScript array with the properties for the IMAGE GIFBUILDER object. Only used for the "tile" property value. 00426 * @param array Work area 00427 * @return void Works on the $im image pointer 00428 * @access private 00429 */ 00430 function copyGifOntoGif(&$im, $cpImg, $conf, $workArea) { 00431 $cpW = imagesx($cpImg); 00432 $cpH = imagesy($cpImg); 00433 $tile = t3lib_div::intExplode(',', $conf['tile']); 00434 $tile[0] = t3lib_div::intInRange($tile[0], 1, 20); 00435 $tile[1] = t3lib_div::intInRange($tile[1], 1, 20); 00436 $cpOff = $this->objPosition($conf, $workArea, array($cpW * $tile[0], $cpH * $tile[1])); 00437 00438 for ($xt = 0; $xt < $tile[0]; $xt++) { 00439 $Xstart = $cpOff[0] + $cpW * $xt; 00440 if ($Xstart + $cpW > $workArea[0]) { // if this image is inside of the workArea, then go on 00441 // X: 00442 if ($Xstart < $workArea[0]) { 00443 $cpImgCutX = $workArea[0] - $Xstart; 00444 $Xstart = $workArea[0]; 00445 } else { 00446 $cpImgCutX = 0; 00447 } 00448 $w = $cpW - $cpImgCutX; 00449 if ($Xstart > $workArea[0] + $workArea[2] - $w) { 00450 $w = $workArea[0] + $workArea[2] - $Xstart; 00451 } 00452 if ($Xstart < $workArea[0] + $workArea[2]) { // if this image is inside of the workArea, then go on 00453 // Y: 00454 for ($yt = 0; $yt < $tile[1]; $yt++) { 00455 $Ystart = $cpOff[1] + $cpH * $yt; 00456 if ($Ystart + $cpH > $workArea[1]) { // if this image is inside of the workArea, then go on 00457 if ($Ystart < $workArea[1]) { 00458 $cpImgCutY = $workArea[1] - $Ystart; 00459 $Ystart = $workArea[1]; 00460 } else { 00461 $cpImgCutY = 0; 00462 } 00463 $h = $cpH - $cpImgCutY; 00464 if ($Ystart > $workArea[1] + $workArea[3] - $h) { 00465 $h = $workArea[1] + $workArea[3] - $Ystart; 00466 } 00467 if ($Ystart < $workArea[1] + $workArea[3]) { // if this image is inside of the workArea, then go on 00468 $this->imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); 00469 } 00470 } 00471 } // Y: 00472 } 00473 } 00474 } 00475 } 00476 00477 /** 00478 * Alternative function for using the similar PHP function imagecopyresized(). Used for GD2 only. 00479 * 00480 * OK, the reason for this stupid fix is the following story: 00481 * GD1.x was capable of copying two images together and combining their palettes! GD2 is apparently not. 00482 * With GD2 only the palette of the dest-image is used which mostly results in totally black images when trying to 00483 * copy a color-ful image onto the destination. 00484 * The GD2-fix is to 00485 * 1) Create a blank TRUE-COLOR image 00486 * 2) Copy the destination image onto that one 00487 * 3) Then do the actual operation; Copying the source (top image) onto that 00488 * 4) ... and return the result pointer. 00489 * 5) Reduce colors (if we do not, the result may become strange!) 00490 * It works, but the resulting images is now a true-color PNG which may be very large. 00491 * So, why not use 'imagetruecolortopalette ($im, TRUE, 256)' - well because it does NOT WORK! So simple is that. 00492 * 00493 * For parameters, see PHP function "imagecopyresized()" 00494 * 00495 * @param pointer see PHP function "imagecopyresized()" 00496 * @param pointer see PHP function "imagecopyresized()" 00497 * @param integer see PHP function "imagecopyresized()" 00498 * @param integer see PHP function "imagecopyresized()" 00499 * @param integer see PHP function "imagecopyresized()" 00500 * @param integer see PHP function "imagecopyresized()" 00501 * @param integer see PHP function "imagecopyresized()" 00502 * @param integer see PHP function "imagecopyresized()" 00503 * @param integer see PHP function "imagecopyresized()" 00504 * @param integer see PHP function "imagecopyresized()" 00505 * @return void 00506 * @access private 00507 * @see t3lib_iconWorks::imagecopyresized() 00508 */ 00509 function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) { 00510 if ($this->imagecopyresized_fix) { 00511 $im_base = imagecreatetruecolor(imagesx($im), imagesy($im)); // Make true color image 00512 imagecopyresized($im_base, $im, 0, 0, 0, 0, imagesx($im), imagesy($im), imagesx($im), imagesy($im)); // Copy the source image onto that 00513 imagecopyresized($im_base, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); // Then copy the $cpImg onto that (the actual operation!) 00514 $im = $im_base; // Set pointer 00515 } else { 00516 imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); 00517 } 00518 } 00519 00520 00521 /******************************** 00522 * 00523 * Text / "TEXT" GIFBUILDER object 00524 * 00525 ********************************/ 00526 00527 /** 00528 * Implements the "TEXT" GIFBUILDER object 00529 * 00530 * @param pointer GDlib image pointer 00531 * @param array TypoScript array with configuration for the GIFBUILDER object. 00532 * @param array The current working area coordinates. 00533 * @return void 00534 * @see tslib_gifBuilder::make() 00535 */ 00536 function makeText(&$im, $conf, $workArea) { 00537 // Spacing 00538 list($spacing, $wordSpacing) = $this->calcWordSpacing($conf); 00539 // Position 00540 $txtPos = $this->txtPosition($conf, $workArea, $conf['BBOX']); 00541 $theText = $this->recodeString($conf['text']); 00542 00543 if ($conf['imgMap'] && is_array($conf['imgMap.'])) { 00544 $this->addToMap($this->calcTextCordsForMap($conf['BBOX'][2], $txtPos, $conf['imgMap.']), $conf['imgMap.']); 00545 } 00546 if (!$conf['hideButCreateMap']) { 00547 // Font Color: 00548 $cols = $this->convertColor($conf['fontColor']); 00549 // NiceText is calculated 00550 if (!$conf['niceText']) { 00551 $Fcolor = ImageColorAllocate($im, $cols[0], $cols[1], $cols[2]); 00552 // antiAliasing is setup: 00553 $Fcolor = ($conf['antiAlias']) ? $Fcolor : -$Fcolor; 00554 00555 for ($a = 0; $a < $conf['iterations']; $a++) { 00556 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 00557 $this->SpacedImageTTFText($im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.']); 00558 } else { 00559 $this->renderTTFText($im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'], $conf); 00560 } 00561 } 00562 } else { // NICETEXT:: 00563 // options anti_aliased and iterations is NOT available when doing this!! 00564 $w = imagesx($im); 00565 $h = imagesy($im); 00566 $tmpStr = $this->randomName(); 00567 00568 $fileMenu = $tmpStr . '_menuNT.' . $this->gifExtension; 00569 $fileColor = $tmpStr . '_colorNT.' . $this->gifExtension; 00570 $fileMask = $tmpStr . '_maskNT.' . $this->gifExtension; 00571 // Scalefactor 00572 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'], 2, 5); 00573 $newW = ceil($sF * imagesx($im)); 00574 $newH = ceil($sF * imagesy($im)); 00575 00576 // Make mask 00577 $maskImg = imagecreatetruecolor($newW, $newH); 00578 $Bcolor = ImageColorAllocate($maskImg, 255, 255, 255); 00579 ImageFilledRectangle($maskImg, 0, 0, $newW, $newH, $Bcolor); 00580 $Fcolor = ImageColorAllocate($maskImg, 0, 0, 0); 00581 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 00582 $this->SpacedImageTTFText($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, $spacing, $wordSpacing, $conf['splitRendering.'], $sF); 00583 } else { 00584 $this->renderTTFText($maskImg, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, $conf['fontFile'], $theText, $conf['splitRendering.'], $conf, $sF); 00585 } 00586 $this->ImageWrite($maskImg, $fileMask); 00587 ImageDestroy($maskImg); 00588 00589 // Downscales the mask 00590 if ($this->NO_IM_EFFECTS) { 00591 if ($this->maskNegate) { 00592 $command = trim($this->scalecmd . ' ' . $w . 'x' . $h . '!'); // Negate 2 times makes no negate... 00593 } else { 00594 $command = trim($this->scalecmd . ' ' . $w . 'x' . $h . '! -negate'); 00595 } 00596 } else { 00597 if ($this->maskNegate) { 00598 $command = trim($conf['niceText.']['before'] . ' ' . $this->scalecmd . ' ' . $w . 'x' . $h . '! ' . $conf['niceText.']['after']); 00599 } else { 00600 $command = trim($conf['niceText.']['before'] . ' ' . $this->scalecmd . ' ' . $w . 'x' . $h . '! ' . $conf['niceText.']['after'] . ' -negate'); 00601 } 00602 if ($conf['niceText.']['sharpen']) { 00603 if ($this->V5_EFFECTS) { 00604 $command .= $this->v5_sharpen($conf['niceText.']['sharpen']); 00605 } else { 00606 $command .= ' -sharpen ' . t3lib_div::intInRange($conf['niceText.']['sharpen'], 1, 99); 00607 } 00608 } 00609 } 00610 00611 $this->imageMagickExec($fileMask, $fileMask, $command); 00612 00613 // Make the color-file 00614 $colorImg = imagecreatetruecolor($w, $h); 00615 $Ccolor = ImageColorAllocate($colorImg, $cols[0], $cols[1], $cols[2]); 00616 ImageFilledRectangle($colorImg, 0, 0, $w, $h, $Ccolor); 00617 $this->ImageWrite($colorImg, $fileColor); 00618 ImageDestroy($colorImg); 00619 00620 // The mask is applied 00621 $this->ImageWrite($im, $fileMenu); // The main pictures is saved temporarily 00622 00623 $this->combineExec($fileMenu, $fileColor, $fileMask, $fileMenu); 00624 00625 $backIm = $this->imageCreateFromFile($fileMenu); // The main image is loaded again... 00626 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 00627 ImageColorTransparent($backIm, -1); 00628 $im = $backIm; 00629 } 00630 00631 // Deleting temporary files; 00632 if (!$this->dontUnlinkTempFiles) { 00633 unlink($fileMenu); 00634 unlink($fileColor); 00635 unlink($fileMask); 00636 } 00637 } 00638 } 00639 } 00640 00641 /** 00642 * Calculates text position for printing the text onto the image based on configuration like alignment and workarea. 00643 * 00644 * @param array TypoScript array for the TEXT GIFBUILDER object 00645 * @param array Workarea definition 00646 * @param array Bounding box information, was set in tslib_gifBuilder::start() 00647 * @return array [0]=x, [1]=y, [2]=w, [3]=h 00648 * @access private 00649 * @see makeText() 00650 */ 00651 function txtPosition($conf, $workArea, $BB) { 00652 $bbox = $BB[2]; 00653 $angle = intval($conf['angle']) / 180 * pi(); 00654 $conf['angle'] = 0; 00655 $straightBB = $this->calcBBox($conf); 00656 00657 // offset, align, valign, workarea 00658 $result = array(); // [0]=x, [1]=y, [2]=w, [3]=h 00659 $result[2] = $BB[0]; 00660 $result[3] = $BB[1]; 00661 $w = $workArea[2]; 00662 $h = $workArea[3]; 00663 00664 switch ($conf['align']) { 00665 case 'right': 00666 case 'center': 00667 $factor = abs(cos($angle)); 00668 $sign = (cos($angle) < 0) ? -1 : 1; 00669 $len1 = $sign * $factor * $straightBB[0]; 00670 $len2 = $sign * $BB[0]; 00671 $result[0] = $w - ceil($len2 * $factor + (1 - $factor) * $len1); 00672 00673 $factor = abs(sin($angle)); 00674 $sign = (sin($angle) < 0) ? -1 : 1; 00675 $len1 = $sign * $factor * $straightBB[0]; 00676 $len2 = $sign * $BB[1]; 00677 $result[1] = ceil($len2 * $factor + (1 - $factor) * $len1); 00678 break; 00679 } 00680 switch ($conf['align']) { 00681 case 'right': 00682 break; 00683 case 'center': 00684 $result[0] = round(($result[0]) / 2); 00685 $result[1] = round(($result[1]) / 2); 00686 break; 00687 default: 00688 $result[0] = 0; 00689 $result[1] = 0; 00690 break; 00691 } 00692 $result = $this->applyOffset($result, t3lib_div::intExplode(',', $conf['offset'])); 00693 $result = $this->applyOffset($result, $workArea); 00694 return $result; 00695 } 00696 00697 /** 00698 * Calculates bounding box information for the TEXT GIFBUILDER object. 00699 * 00700 * @param array TypoScript array for the TEXT GIFBUILDER object 00701 * @return array Array with three keys [0]/[1] being x/y and [2] being the bounding box array 00702 * @access private 00703 * @see txtPosition(), tslib_gifBuilder::start() 00704 */ 00705 function calcBBox($conf) { 00706 $sF = $this->getTextScalFactor($conf); 00707 list($spacing, $wordSpacing) = $this->calcWordSpacing($conf, $sF); 00708 $theText = $this->recodeString($conf['text']); 00709 00710 $charInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $theText, $conf['splitRendering.'], $sF); 00711 $theBBoxInfo = $charInf; 00712 if ($conf['angle']) { 00713 $xArr = array($charInf[0], $charInf[2], $charInf[4], $charInf[6]); 00714 $yArr = array($charInf[1], $charInf[3], $charInf[5], $charInf[7]); 00715 $x = max($xArr) - min($xArr); 00716 $y = max($yArr) - min($yArr); 00717 } else { 00718 $x = ($charInf[2] - $charInf[0]); 00719 $y = ($charInf[1] - $charInf[7]); 00720 } 00721 // Set original lineHeight (used by line breaks): 00722 $theBBoxInfo['lineHeight'] = $y; 00723 00724 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 00725 $x = 0; 00726 if (!$spacing && $wordSpacing) { 00727 $bits = explode(' ', $theText); 00728 foreach ($bits as $word) { 00729 $word .= ' '; 00730 $wordInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $word, $conf['splitRendering.'], $sF); 00731 $wordW = ($wordInf[2] - $wordInf[0]); 00732 $x += $wordW + $wordSpacing; 00733 } 00734 } else { 00735 $utf8Chars = $this->singleChars($theText); 00736 // For each UTF-8 char, do: 00737 foreach ($utf8Chars as $char) { 00738 $charInf = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $char, $conf['splitRendering.'], $sF); 00739 $charW = ($charInf[2] - $charInf[0]); 00740 $x += $charW + (($char == ' ') ? $wordSpacing : $spacing); 00741 } 00742 } 00743 } elseif (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->getRenderedTextWidth($conf['text'], $conf) > $conf['breakWidth']) { 00744 $maxWidth = 0; 00745 $currentWidth = 0; 00746 $breakWidth = $conf['breakWidth']; 00747 $breakSpace = $this->getBreakSpace($conf, $theBBoxInfo); 00748 00749 $wordPairs = $this->getWordPairsForLineBreak($conf['text']); 00750 // Iterate through all word pairs: 00751 foreach ($wordPairs as $index => $wordPair) { 00752 $wordWidth = $this->getRenderedTextWidth($wordPair, $conf); 00753 if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) { 00754 $currentWidth += $wordWidth; 00755 } else { 00756 $maxWidth = max($maxWidth, $currentWidth); 00757 $y += $breakSpace; 00758 // Restart: 00759 $currentWidth = $wordWidth; 00760 } 00761 } 00762 $x = max($maxWidth, $currentWidth) * $sF; 00763 } 00764 00765 if ($sF > 1) { 00766 $x = ceil($x / $sF); 00767 $y = ceil($y / $sF); 00768 if (is_array($theBBoxInfo)) { 00769 foreach ($theBBoxInfo as &$value) { 00770 $value = ceil($value / $sF); 00771 } 00772 } 00773 } 00774 return array($x, $y, $theBBoxInfo); 00775 } 00776 00777 /** 00778 * Adds an <area> tag to the internal variable $this->map which is used to accumulate the content for an ImageMap 00779 * 00780 * @param array Coordinates for a polygon image map as created by ->calcTextCordsForMap() 00781 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object. 00782 * @return void 00783 * @access private 00784 * @see makeText(), calcTextCordsForMap() 00785 */ 00786 function addToMap($cords, $conf) { 00787 $JS = $conf['noBlur'] ? '' : ' onfocus="blurLink(this);"'; 00788 00789 $this->map .= '<area' . 00790 ' shape="poly"' . 00791 ' coords="' . implode(',', $cords) . '"' . 00792 ' href="' . htmlspecialchars($conf['url']) . '"' . 00793 ($conf['target'] ? ' target="' . htmlspecialchars($conf['target']) . '"' : '') . 00794 $JS . 00795 (strlen($conf['titleText']) ? ' title="' . htmlspecialchars($conf['titleText']) . '"' : '') . 00796 ' alt="' . htmlspecialchars($conf['altText']) . '" />'; 00797 } 00798 00799 /** 00800 * Calculating the coordinates for a TEXT string on an image map. Used in an <area> tag 00801 * 00802 * @param array Coordinates (from BBOX array) 00803 * @param array Offset array 00804 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object. 00805 * @return array 00806 * @access private 00807 * @see makeText(), calcTextCordsForMap() 00808 */ 00809 function calcTextCordsForMap($cords, $offset, $conf) { 00810 $pars = t3lib_div::intExplode(',', $conf['explode'] . ','); 00811 00812 $newCords[0] = $cords[0] + $offset[0] - $pars[0]; 00813 $newCords[1] = $cords[1] + $offset[1] + $pars[1]; 00814 $newCords[2] = $cords[2] + $offset[0] + $pars[0]; 00815 $newCords[3] = $cords[3] + $offset[1] + $pars[1]; 00816 $newCords[4] = $cords[4] + $offset[0] + $pars[0]; 00817 $newCords[5] = $cords[5] + $offset[1] - $pars[1]; 00818 $newCords[6] = $cords[6] + $offset[0] - $pars[0]; 00819 $newCords[7] = $cords[7] + $offset[1] - $pars[1]; 00820 00821 return $newCords; 00822 } 00823 00824 /** 00825 * Printing text onto an image like the PHP function imageTTFText does but in addition it offers options for spacing of letters and words. 00826 * Spacing is done by printing one char at a time and this means that the spacing is rather uneven and probably not very nice. 00827 * See 00828 * 00829 * @param pointer (See argument for PHP function imageTTFtext()) 00830 * @param integer (See argument for PHP function imageTTFtext()) 00831 * @param integer (See argument for PHP function imageTTFtext()) 00832 * @param integer (See argument for PHP function imageTTFtext()) 00833 * @param integer (See argument for PHP function imageTTFtext()) 00834 * @param integer (See argument for PHP function imageTTFtext()) 00835 * @param string (See argument for PHP function imageTTFtext()) 00836 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in. 00837 * @param integer The spacing of letters in pixels 00838 * @param integer The spacing of words in pixels 00839 * @param array $splitRenderingConf array 00840 * @param integer Scale factor 00841 * @return void 00842 * @access private 00843 */ 00844 function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing, $splitRenderingConf, $sF = 1) { 00845 00846 $spacing *= $sF; 00847 $wordSpacing *= $sF; 00848 00849 if (!$spacing && $wordSpacing) { 00850 $bits = explode(' ', $text); 00851 foreach ($bits as $word) { 00852 $word .= ' '; 00853 $wordInf = $this->ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $word, $splitRenderingConf, $sF); 00854 $wordW = ($wordInf[2] - $wordInf[0]); 00855 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $word, $splitRenderingConf, $sF); 00856 $x += $wordW + $wordSpacing; 00857 } 00858 } else { 00859 $utf8Chars = $this->singleChars($text); 00860 // For each UTF-8 char, do: 00861 foreach ($utf8Chars as $char) { 00862 $charInf = $this->ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $char, $splitRenderingConf, $sF); 00863 $charW = ($charInf[2] - $charInf[0]); 00864 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $char, $splitRenderingConf, $sF); 00865 $x += $charW + (($char == ' ') ? $wordSpacing : $spacing); 00866 } 00867 } 00868 } 00869 00870 /** 00871 * Function that finds the right fontsize that will render the textstring within a certain width 00872 * 00873 * @param array The TypoScript properties of the TEXT GIFBUILDER object 00874 * @return integer The new fontSize 00875 * @access private 00876 * @author René Fritz <r.fritz@colorcube.de> 00877 * @see tslib_gifBuilder::start() 00878 */ 00879 function fontResize($conf) { 00880 // 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!!!! 00881 $maxWidth = intval($conf['maxWidth']); 00882 list($spacing, $wordSpacing) = $this->calcWordSpacing($conf); 00883 if ($maxWidth) { 00884 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function: 00885 return $conf['fontSize']; 00886 // ################ no calc for spacing yet !!!!!! 00887 } else { 00888 do { 00889 // determine bounding box. 00890 $bounds = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $this->recodeString($conf['text']), $conf['splitRendering.']); 00891 if ($conf['angle'] < 0) { 00892 $pixelWidth = abs($bounds[4] - $bounds[0]); 00893 } elseif ($conf['angle'] > 0) { 00894 $pixelWidth = abs($bounds[2] - $bounds[6]); 00895 } else { 00896 $pixelWidth = abs($bounds[4] - $bounds[6]); 00897 } 00898 00899 // Size is fine, exit: 00900 if ($pixelWidth <= $maxWidth) { 00901 break; 00902 } else { 00903 $conf['fontSize']--; 00904 } 00905 } while ($conf['fontSize'] > 1); 00906 } 00907 //if spacing 00908 } 00909 return $conf['fontSize']; 00910 } 00911 00912 /** 00913 * Wrapper for ImageTTFBBox 00914 * 00915 * @param integer (See argument for PHP function ImageTTFBBox()) 00916 * @param integer (See argument for PHP function ImageTTFBBox()) 00917 * @param string (See argument for PHP function ImageTTFBBox()) 00918 * @param string (See argument for PHP function ImageTTFBBox()) 00919 * @param array Split-rendering configuration 00920 * @param integer Scale factor 00921 * @return array Information array. 00922 */ 00923 function ImageTTFBBoxWrapper($fontSize, $angle, $fontFile, $string, $splitRendering, $sF = 1) { 00924 00925 // Initialize: 00926 $offsetInfo = array(); 00927 $stringParts = $this->splitString($string, $splitRendering, $fontSize, $fontFile); 00928 00929 // Traverse string parts: 00930 foreach ($stringParts as $strCfg) { 00931 $fontFile = t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']); 00932 if (is_readable($fontFile)) { 00933 00934 // Calculate Bounding Box for part: 00935 $calc = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF * $strCfg['fontSize']), $angle, $fontFile, $strCfg['str']); 00936 00937 // Calculate offsets: 00938 if (!count($offsetInfo)) { 00939 $offsetInfo = $calc; // First run, just copy over. 00940 } else { 00941 $offsetInfo[2] += $calc[2] - $calc[0] + intval($splitRendering['compX']) + intval($strCfg['xSpaceBefore']) + intval($strCfg['xSpaceAfter']); 00942 $offsetInfo[3] += $calc[3] - $calc[1] - intval($splitRendering['compY']) - intval($strCfg['ySpaceBefore']) - intval($strCfg['ySpaceAfter']); 00943 $offsetInfo[4] += $calc[4] - $calc[6] + intval($splitRendering['compX']) + intval($strCfg['xSpaceBefore']) + intval($strCfg['xSpaceAfter']); 00944 $offsetInfo[5] += $calc[5] - $calc[7] - intval($splitRendering['compY']) - intval($strCfg['ySpaceBefore']) - intval($strCfg['ySpaceAfter']); 00945 } 00946 00947 } else { 00948 debug('cannot read file: ' . $fontFile, 't3lib_stdGraphic::ImageTTFBBoxWrapper()'); 00949 } 00950 } 00951 00952 return $offsetInfo; 00953 } 00954 00955 /** 00956 * Wrapper for ImageTTFText 00957 * 00958 * @param pointer (See argument for PHP function imageTTFtext()) 00959 * @param integer (See argument for PHP function imageTTFtext()) 00960 * @param integer (See argument for PHP function imageTTFtext()) 00961 * @param integer (See argument for PHP function imageTTFtext()) 00962 * @param integer (See argument for PHP function imageTTFtext()) 00963 * @param integer (See argument for PHP function imageTTFtext()) 00964 * @param string (See argument for PHP function imageTTFtext()) 00965 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in. 00966 * @param array Split-rendering configuration 00967 * @param integer Scale factor 00968 * @return void 00969 */ 00970 function ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF = 1) { 00971 00972 // Initialize: 00973 $stringParts = $this->splitString($string, $splitRendering, $fontSize, $fontFile); 00974 $x = ceil($sF * $x); 00975 $y = ceil($sF * $y); 00976 00977 // Traverse string parts: 00978 foreach ($stringParts as $i => $strCfg) { 00979 00980 // Initialize: 00981 $colorIndex = $color; 00982 00983 // Set custom color if any (only when niceText is off): 00984 if ($strCfg['color'] && $sF == 1) { 00985 $cols = $this->convertColor($strCfg['color']); 00986 $colorIndex = ImageColorAllocate($im, $cols[0], $cols[1], $cols[2]); 00987 $colorIndex = $color >= 0 ? $colorIndex : -$colorIndex; 00988 } 00989 00990 // Setting xSpaceBefore 00991 if ($i) { 00992 $x += intval($strCfg['xSpaceBefore']); 00993 $y -= intval($strCfg['ySpaceBefore']); 00994 } 00995 00996 $fontFile = t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']); 00997 if (is_readable($fontFile)) { 00998 00999 // Render part: 01000 ImageTTFText($im, t3lib_div::freetypeDpiComp($sF * $strCfg['fontSize']), $angle, $x, $y, $colorIndex, $fontFile, $strCfg['str']); 01001 01002 // Calculate offset to apply: 01003 $wordInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF * $strCfg['fontSize']), $angle, t3lib_stdGraphic::prependAbsolutePath($strCfg['fontFile']), $strCfg['str']); 01004 $x += $wordInf[2] - $wordInf[0] + intval($splitRendering['compX']) + intval($strCfg['xSpaceAfter']); 01005 $y += $wordInf[5] - $wordInf[7] - intval($splitRendering['compY']) - intval($strCfg['ySpaceAfter']); 01006 01007 } else { 01008 debug('cannot read file: ' . $fontFile, 't3lib_stdGraphic::ImageTTFTextWrapper()'); 01009 } 01010 01011 } 01012 } 01013 01014 /** 01015 * Splitting a string for ImageTTFBBox up into an array where each part has its own configuration options. 01016 * 01017 * @param string UTF-8 string 01018 * @param array Split-rendering configuration from GIFBUILDER TEXT object. 01019 * @param integer Current fontsize 01020 * @param string Current font file 01021 * @return array Array with input string splitted according to configuration 01022 */ 01023 function splitString($string, $splitRendering, $fontSize, $fontFile) { 01024 01025 // Initialize by setting the whole string and default configuration as the first entry. 01026 $result = array(); 01027 $result[] = array( 01028 'str' => $string, 01029 'fontSize' => $fontSize, 01030 'fontFile' => $fontFile 01031 ); 01032 01033 // Traverse the split-rendering configuration: 01034 // Splitting will create more entries in $result with individual configurations. 01035 if (is_array($splitRendering)) { 01036 $sKeyArray = t3lib_TStemplate::sortedKeyList($splitRendering); 01037 01038 // Traverse configured options: 01039 foreach ($sKeyArray as $key) { 01040 $cfg = $splitRendering[$key . '.']; 01041 01042 // Process each type of split rendering keyword: 01043 switch ((string) $splitRendering[$key]) { 01044 case 'highlightWord': 01045 if (strlen($cfg['value'])) { 01046 $newResult = array(); 01047 01048 // Traverse the current parts of the result array: 01049 foreach ($result as $part) { 01050 // Explode the string value by the word value to highlight: 01051 $explodedParts = explode($cfg['value'], $part['str']); 01052 foreach ($explodedParts as $c => $expValue) { 01053 if (strlen($expValue)) { 01054 $newResult[] = array_merge($part, array('str' => $expValue)); 01055 } 01056 if ($c + 1 < count($explodedParts)) { 01057 $newResult[] = array( 01058 'str' => $cfg['value'], 01059 'fontSize' => $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 01060 'fontFile' => $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 01061 'color' => $cfg['color'], 01062 'xSpaceBefore' => $cfg['xSpaceBefore'], 01063 'xSpaceAfter' => $cfg['xSpaceAfter'], 01064 'ySpaceBefore' => $cfg['ySpaceBefore'], 01065 'ySpaceAfter' => $cfg['ySpaceAfter'], 01066 ); 01067 } 01068 } 01069 } 01070 01071 // Set the new result as result array: 01072 if (count($newResult)) { 01073 $result = $newResult; 01074 } 01075 } 01076 break; 01077 case 'charRange': 01078 if (strlen($cfg['value'])) { 01079 01080 // Initialize range: 01081 $ranges = t3lib_div::trimExplode(',', $cfg['value'], 1); 01082 foreach ($ranges as $i => $rangeDef) { 01083 $ranges[$i] = t3lib_div::intExplode('-', $ranges[$i]); 01084 if (!isset($ranges[$i][1])) { 01085 $ranges[$i][1] = $ranges[$i][0]; 01086 } 01087 } 01088 $newResult = array(); 01089 01090 // Traverse the current parts of the result array: 01091 foreach ($result as $part) { 01092 01093 // Initialize: 01094 $currentState = -1; 01095 $bankAccum = ''; 01096 01097 // Explode the string value by the word value to highlight: 01098 $utf8Chars = $this->singleChars($part['str']); 01099 foreach ($utf8Chars as $utfChar) { 01100 01101 // Find number and evaluate position: 01102 $uNumber = $this->csConvObj->utf8CharToUnumber($utfChar); 01103 $inRange = 0; 01104 foreach ($ranges as $rangeDef) { 01105 if ($uNumber >= $rangeDef[0] && (!$rangeDef[1] || $uNumber <= $rangeDef[1])) { 01106 $inRange = 1; 01107 break; 01108 } 01109 } 01110 if ($currentState == -1) { 01111 $currentState = $inRange; 01112 } // Initialize first char 01113 01114 // Switch bank: 01115 if ($inRange != $currentState && !t3lib_div::inList('32,10,13,9', $uNumber)) { 01116 01117 // Set result: 01118 if (strlen($bankAccum)) { 01119 $newResult[] = array( 01120 'str' => $bankAccum, 01121 'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 01122 'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 01123 'color' => $currentState ? $cfg['color'] : '', 01124 'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '', 01125 'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '', 01126 'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '', 01127 'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '', 01128 ); 01129 } 01130 01131 // Initialize new settings: 01132 $currentState = $inRange; 01133 $bankAccum = ''; 01134 } 01135 01136 // Add char to bank: 01137 $bankAccum .= $utfChar; 01138 } 01139 01140 // Set result for FINAL part: 01141 if (strlen($bankAccum)) { 01142 $newResult[] = array( 01143 'str' => $bankAccum, 01144 'fontSize' => $currentState && $cfg['fontSize'] ? $cfg['fontSize'] : $part['fontSize'], 01145 'fontFile' => $currentState && $cfg['fontFile'] ? $cfg['fontFile'] : $part['fontFile'], 01146 'color' => $currentState ? $cfg['color'] : '', 01147 'xSpaceBefore' => $currentState ? $cfg['xSpaceBefore'] : '', 01148 'xSpaceAfter' => $currentState ? $cfg['xSpaceAfter'] : '', 01149 'ySpaceBefore' => $currentState ? $cfg['ySpaceBefore'] : '', 01150 'ySpaceAfter' => $currentState ? $cfg['ySpaceAfter'] : '', 01151 ); 01152 } 01153 } 01154 01155 // Set the new result as result array: 01156 if (count($newResult)) { 01157 $result = $newResult; 01158 } 01159 } 01160 break; 01161 } 01162 } 01163 } 01164 01165 return $result; 01166 } 01167 01168 /** 01169 * Calculates the spacing and wordSpacing values 01170 * 01171 * @param array TypoScript array for the TEXT GIFBUILDER object 01172 * @param integer TypoScript value from eg $conf['niceText.']['scaleFactor'] 01173 * @return array Array with two keys [0]/[1] being array($spacing,$wordSpacing) 01174 * @access private 01175 * @see calcBBox() 01176 */ 01177 function calcWordSpacing($conf, $scaleFactor = 1) { 01178 01179 $spacing = intval($conf['spacing']); 01180 $wordSpacing = intval($conf['wordSpacing']); 01181 $wordSpacing = $wordSpacing ? $wordSpacing : $spacing * 2; 01182 01183 $spacing *= $scaleFactor; 01184 $wordSpacing *= $scaleFactor; 01185 01186 return array($spacing, $wordSpacing); 01187 } 01188 01189 /** 01190 * Calculates and returns the niceText.scaleFactor 01191 * 01192 * @param array TypoScript array for the TEXT GIFBUILDER object 01193 * @return integer TypoScript value from eg $conf['niceText.']['scaleFactor'] 01194 * @access private 01195 */ 01196 function getTextScalFactor($conf) { 01197 if (!$conf['niceText']) { 01198 $sF = 1; 01199 } else { // NICETEXT:: 01200 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'], 2, 5); 01201 } 01202 return $sF; 01203 } 01204 01205 /** 01206 * Renders a regular text and takes care of a possible line break automatically. 01207 * 01208 * @param pointer (See argument for PHP function imageTTFtext()) 01209 * @param integer (See argument for PHP function imageTTFtext()) 01210 * @param integer (See argument for PHP function imageTTFtext()) 01211 * @param integer (See argument for PHP function imageTTFtext()) 01212 * @param integer (See argument for PHP function imageTTFtext()) 01213 * @param integer (See argument for PHP function imageTTFtext()) 01214 * @param string (See argument for PHP function imageTTFtext()) 01215 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in. 01216 * @param array Split-rendering configuration 01217 * @param integer Scale factor 01218 * @param array $conf: The configuration 01219 * @return void 01220 */ 01221 protected function renderTTFText(&$im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $conf, $sF = 1) { 01222 if (isset($conf['breakWidth']) && $conf['breakWidth'] && $this->getRenderedTextWidth($string, $conf) > $conf['breakWidth']) { 01223 $phrase = ''; 01224 $currentWidth = 0; 01225 01226 $breakWidth = $conf['breakWidth']; 01227 $breakSpace = $this->getBreakSpace($conf); 01228 01229 $wordPairs = $this->getWordPairsForLineBreak($string); 01230 // Iterate through all word pairs: 01231 foreach ($wordPairs as $index => $wordPair) { 01232 $wordWidth = $this->getRenderedTextWidth($wordPair, $conf); 01233 if ($index == 0 || $currentWidth + $wordWidth <= $breakWidth) { 01234 $currentWidth += $wordWidth; 01235 $phrase .= $wordPair; 01236 } else { 01237 // Render the current phrase that is below breakWidth: 01238 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF); 01239 // Calculate the news height offset: 01240 $y += $breakSpace; 01241 // Restart the phrase: 01242 $currentWidth = $wordWidth; 01243 $phrase = $wordPair; 01244 } 01245 } 01246 // Render the remaining phrase: 01247 if ($currentWidth) { 01248 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $phrase, $splitRendering, $sF); 01249 } 01250 } else { 01251 $this->ImageTTFTextWrapper($im, $fontSize, $angle, $x, $y, $color, $fontFile, $string, $splitRendering, $sF); 01252 } 01253 } 01254 01255 /** 01256 * Gets the word pairs used for automatic line breaks. 01257 * 01258 * @param string $string 01259 * @return array 01260 */ 01261 protected function getWordPairsForLineBreak($string) { 01262 $wordPairs = array(); 01263 01264 $wordsArray = preg_split('#([- .,!:]+)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE); 01265 $wordsCount = count($wordsArray); 01266 for ($index = 0; $index < $wordsCount; $index += 2) { 01267 $wordPairs[] = $wordsArray[$index] . $wordsArray[$index + 1]; 01268 } 01269 01270 return $wordPairs; 01271 } 01272 01273 /** 01274 * Gets the rendered text width. 01275 * 01276 * @param string $text 01277 * @param array $conf 01278 * @param integer 01279 */ 01280 protected function getRenderedTextWidth($text, $conf) { 01281 $bounds = $this->ImageTTFBBoxWrapper($conf['fontSize'], $conf['angle'], $conf['fontFile'], $this->recodeString($text), $conf['splitRendering.']); 01282 if ($conf['angle'] < 0) { 01283 $pixelWidth = abs($bounds[4] - $bounds[0]); 01284 } elseif ($conf['angle'] > 0) { 01285 $pixelWidth = abs($bounds[2] - $bounds[6]); 01286 } else { 01287 $pixelWidth = abs($bounds[4] - $bounds[6]); 01288 } 01289 return $pixelWidth; 01290 } 01291 01292 /** 01293 * Gets the break space for each new line. 01294 * 01295 * @param array $conf: TypoScript configuration for the currently rendered object 01296 * @param array $boundingBox: The bounding box the the currently rendered object 01297 * @return integer The break space 01298 */ 01299 protected function getBreakSpace($conf, array $boundingBox = NULL) { 01300 if (!isset($boundingBox)) { 01301 $boundingBox = $this->calcBBox($conf); 01302 $boundingBox = $boundingBox[2]; 01303 } 01304 01305 if (isset($conf['breakSpace']) && $conf['breakSpace']) { 01306 $breakSpace = $boundingBox['lineHeight'] * $conf['breakSpace']; 01307 } else { 01308 $breakSpace = $boundingBox['lineHeight']; 01309 } 01310 01311 return $breakSpace; 01312 } 01313 01314 01315 /********************************************* 01316 * 01317 * Other GIFBUILDER objects related to TEXT 01318 * 01319 *********************************************/ 01320 01321 /** 01322 * Implements the "OUTLINE" GIFBUILDER object / property for the TEXT object 01323 * 01324 * @param pointer GDlib image pointer 01325 * @param array TypoScript array with configuration for the GIFBUILDER object. 01326 * @param array The current working area coordinates. 01327 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 01328 * @return void 01329 * @see tslib_gifBuilder::make(), makeText() 01330 */ 01331 function makeOutline(&$im, $conf, $workArea, $txtConf) { 01332 $thickness = intval($conf['thickness']); 01333 if ($thickness) { 01334 $txtConf['fontColor'] = $conf['color']; 01335 $outLineDist = t3lib_div::intInRange($thickness, 1, 2); 01336 for ($b = 1; $b <= $outLineDist; $b++) { 01337 if ($b == 1) { 01338 $it = 8; 01339 } else { 01340 $it = 16; 01341 } 01342 $outL = $this->circleOffset($b, $it); 01343 for ($a = 0; $a < $it; $a++) { 01344 $this->makeText($im, $txtConf, $this->applyOffset($workArea, $outL[$a])); 01345 } 01346 } 01347 } 01348 } 01349 01350 /** 01351 * Creates some offset values in an array used to simulate a circularly applied outline around TEXT 01352 * 01353 * access private 01354 * 01355 * @param integer Distance 01356 * @param integer Iterations. 01357 * @return array 01358 * @see makeOutline() 01359 */ 01360 function circleOffset($distance, $iterations) { 01361 $res = array(); 01362 if ($distance && $iterations) { 01363 for ($a = 0; $a < $iterations; $a++) { 01364 $yOff = round(sin(2 * pi() / $iterations * ($a + 1)) * 100 * $distance); 01365 if ($yOff) { 01366 $yOff = intval(ceil(abs($yOff / 100)) * ($yOff / abs($yOff))); 01367 } 01368 $xOff = round(cos(2 * pi() / $iterations * ($a + 1)) * 100 * $distance); 01369 if ($xOff) { 01370 $xOff = intval(ceil(abs($xOff / 100)) * ($xOff / abs($xOff))); 01371 } 01372 $res[$a] = array($xOff, $yOff); 01373 } 01374 } 01375 return $res; 01376 } 01377 01378 /** 01379 * Implements the "EMBOSS" GIFBUILDER object / property for the TEXT object 01380 * 01381 * @param pointer GDlib image pointer 01382 * @param array TypoScript array with configuration for the GIFBUILDER object. 01383 * @param array The current working area coordinates. 01384 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 01385 * @return void 01386 * @see tslib_gifBuilder::make(), makeShadow() 01387 */ 01388 function makeEmboss(&$im, $conf, $workArea, $txtConf) { 01389 $conf['color'] = $conf['highColor']; 01390 $this->makeShadow($im, $conf, $workArea, $txtConf); 01391 $newOffset = t3lib_div::intExplode(',', $conf['offset']); 01392 $newOffset[0] *= -1; 01393 $newOffset[1] *= -1; 01394 $conf['offset'] = implode(',', $newOffset); 01395 $conf['color'] = $conf['lowColor']; 01396 $this->makeShadow($im, $conf, $workArea, $txtConf); 01397 } 01398 01399 /** 01400 * Implements the "SHADOW" GIFBUILDER object / property for the TEXT object 01401 * The operation involves ImageMagick for combining. 01402 * 01403 * @param pointer GDlib image pointer 01404 * @param array TypoScript array with configuration for the GIFBUILDER object. 01405 * @param array The current working area coordinates. 01406 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object. 01407 * @return void 01408 * @see tslib_gifBuilder::make(), makeText(), makeEmboss() 01409 */ 01410 function makeShadow(&$im, $conf, $workArea, $txtConf) { 01411 $workArea = $this->applyOffset($workArea, t3lib_div::intExplode(',', $conf['offset'])); 01412 $blurRate = t3lib_div::intInRange(intval($conf['blur']), 0, 99); 01413 01414 if (!$blurRate || $this->NO_IM_EFFECTS) { // No effects if ImageMagick ver. 5+ 01415 $txtConf['fontColor'] = $conf['color']; 01416 $this->makeText($im, $txtConf, $workArea); 01417 } else { 01418 $w = imagesx($im); 01419 $h = imagesy($im); 01420 $blurBorder = 3; // area around the blur used for cropping something 01421 $tmpStr = $this->randomName(); 01422 $fileMenu = $tmpStr . '_menu.' . $this->gifExtension; 01423 $fileColor = $tmpStr . '_color.' . $this->gifExtension; 01424 $fileMask = $tmpStr . '_mask.' . $this->gifExtension; 01425 01426 // BlurColor Image laves 01427 $blurColImg = imagecreatetruecolor($w, $h); 01428 $bcols = $this->convertColor($conf['color']); 01429 $Bcolor = ImageColorAllocate($blurColImg, $bcols[0], $bcols[1], $bcols[2]); 01430 ImageFilledRectangle($blurColImg, 0, 0, $w, $h, $Bcolor); 01431 $this->ImageWrite($blurColImg, $fileColor); 01432 ImageDestroy($blurColImg); 01433 01434 // The mask is made: BlurTextImage 01435 $blurTextImg = imagecreatetruecolor($w + $blurBorder * 2, $h + $blurBorder * 2); 01436 $Bcolor = ImageColorAllocate($blurTextImg, 0, 0, 0); // black background 01437 ImageFilledRectangle($blurTextImg, 0, 0, $w + $blurBorder * 2, $h + $blurBorder * 2, $Bcolor); 01438 $txtConf['fontColor'] = 'white'; 01439 $blurBordArr = array($blurBorder, $blurBorder); 01440 $this->makeText($blurTextImg, $txtConf, $this->applyOffset($workArea, $blurBordArr)); 01441 $this->ImageWrite($blurTextImg, $fileMask); // dump to temporary file 01442 ImageDestroy($blurTextImg); // destroy 01443 01444 01445 $command = ''; 01446 $command .= $this->maskNegate; 01447 01448 if ($this->V5_EFFECTS) { 01449 $command .= $this->v5_blur($blurRate + 1); 01450 } else { 01451 // Blurring of the mask 01452 $times = ceil($blurRate / 10); // How many blur-commands that is executed. Min = 1; 01453 $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. 01454 $newBlurRate = t3lib_div::intInRange($newBlurRate, 1, 99); 01455 for ($a = 0; $a < $times; $a++) { // Building blur-command 01456 $command .= ' -blur ' . $blurRate; 01457 } 01458 } 01459 01460 $this->imageMagickExec($fileMask, $fileMask, $command . ' +matte'); 01461 01462 $blurTextImg_tmp = $this->imageCreateFromFile($fileMask); // the mask is loaded again 01463 if ($blurTextImg_tmp) { // if nothing went wrong we continue with the blurred mask 01464 01465 // cropping the border from the mask 01466 $blurTextImg = imagecreatetruecolor($w, $h); 01467 $this->imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, $w, $h, $w, $h); 01468 ImageDestroy($blurTextImg_tmp); // Destroy the temporary mask 01469 01470 // adjust the mask 01471 $intensity = 40; 01472 if ($conf['intensity']) { 01473 $intensity = t3lib_div::intInRange($conf['intensity'], 0, 100); 01474 } 01475 $intensity = ceil(255 - ($intensity / 100 * 255)); 01476 $this->inputLevels($blurTextImg, 0, $intensity, $this->maskNegate); 01477 01478 $opacity = t3lib_div::intInRange(intval($conf['opacity']), 0, 100); 01479 if ($opacity && $opacity < 100) { 01480 $high = ceil(255 * $opacity / 100); 01481 $this->outputLevels($blurTextImg, 0, $high, $this->maskNegate); // reducing levels as the opacity demands 01482 } 01483 01484 $this->ImageWrite($blurTextImg, $fileMask); // Dump the mask again 01485 ImageDestroy($blurTextImg); // Destroy the mask 01486 01487 // The pictures are combined 01488 $this->ImageWrite($im, $fileMenu); // The main pictures is saved temporarily 01489 01490 $this->combineExec($fileMenu, $fileColor, $fileMask, $fileMenu); 01491 01492 $backIm = $this->imageCreateFromFile($fileMenu); // The main image is loaded again... 01493 if ($backIm) { // ... and if nothing went wrong we load it onto the old one. 01494 ImageColorTransparent($backIm, -1); 01495 $im = $backIm; 01496 } 01497 } 01498 // Deleting temporary files; 01499 if (!$this->dontUnlinkTempFiles) { 01500 unlink($fileMenu); 01501 unlink($fileColor); 01502 unlink($fileMask); 01503 } 01504 } 01505 } 01506 01507 01508 /**************************** 01509 * 01510 * Other GIFBUILDER objects 01511 * 01512 ****************************/ 01513 01514 /** 01515 * Implements the "BOX" GIFBUILDER object 01516 * 01517 * @param pointer GDlib image pointer 01518 * @param array TypoScript array with configuration for the GIFBUILDER object. 01519 * @param array The current working area coordinates. 01520 * @return void 01521 * @see tslib_gifBuilder::make() 01522 */ 01523 function makeBox(&$im, $conf, $workArea) { 01524 $cords = t3lib_div::intExplode(',', $conf['dimensions'] . ',,,'); 01525 $conf['offset'] = $cords[0] . ',' . $cords[1]; 01526 $cords = $this->objPosition($conf, $workArea, array($cords[2], $cords[3])); 01527 $cols = $this->convertColor($conf['color']); 01528 01529 $opacity = 0; 01530 if (isset($conf['opacity'])) { 01531 // conversion: 01532 // PHP 0 = opaque, 127 = transparent 01533 // TYPO3 100 = opaque, 0 = transparent 01534 $opacity = t3lib_div::intInRange(intval($conf['opacity']), 1, 100, 1); 01535 $opacity = abs($opacity - 100); 01536 $opacity = round((127 * $opacity) / 100); 01537 } 01538 01539 $tmpColor = ImageColorAllocateAlpha($im, $cols[0], $cols[1], $cols[2], $opacity); 01540 imagefilledrectangle($im, $cords[0], $cords[1], $cords[0] + $cords[2] - 1, $cords[1] + $cords[3] - 1, $tmpColor); 01541 } 01542 01543 /** 01544 * Implements the "Ellipse" GIFBUILDER object 01545 * Example Typoscript: 01546 * file = GIFBUILDER 01547 * file { 01548 * XY = 200,200 01549 * format = jpg 01550 * quality = 100 01551 * 10 = ELLIPSE 01552 * 10.dimensions = 100,100,50,50 01553 * 10.color = red 01554 * 01555 * $workArea = X,Y 01556 * $conf['dimensions'] = offset x, offset y, width of ellipse, height of ellipse 01557 * 01558 * @param pointer GDlib image pointer 01559 * @param array $conf TypoScript array with configuration for the GIFBUILDER object. 01560 * @param array $workArea The current working area coordinates. 01561 * @return void 01562 * @see tslib_gifBuilder::make() 01563 */ 01564 public function makeEllipse(&$im, array $conf, array $workArea) { 01565 $ellipseConfiguration = t3lib_div::intExplode(',', $conf['dimensions'] . ',,,'); 01566 $conf['offset'] = $ellipseConfiguration[0] . ',' . $ellipseConfiguration[1]; // ellipse offset inside workArea (x/y) 01567 01568 // @see objPosition 01569 $imageCoordinates = $this->objPosition($conf, $workArea, array($ellipseConfiguration[2], $ellipseConfiguration[3])); 01570 01571 $color = $this->convertColor($conf['color']); 01572 $fillingColor = imagecolorallocate($im, $color[0], $color[1], $color[2]); 01573 imagefilledellipse($im, $imageCoordinates[0], $imageCoordinates[1], $imageCoordinates[2], $imageCoordinates[3], $fillingColor); 01574 } 01575 01576 /** 01577 * Implements the "EFFECT" GIFBUILDER object 01578 * The operation involves ImageMagick for applying effects 01579 * 01580 * @param pointer GDlib image pointer 01581 * @param array TypoScript array with configuration for the GIFBUILDER object. 01582 * @return void 01583 * @see tslib_gifBuilder::make(), applyImageMagickToPHPGif() 01584 */ 01585 function makeEffect(&$im, $conf) { 01586 $commands = $this->IMparams($conf['value']); 01587 if ($commands) { 01588 $this->applyImageMagickToPHPGif($im, $commands); 01589 } 01590 } 01591 01592 /** 01593 * Creating ImageMagick paramters from TypoScript property 01594 * 01595 * @param string A string with effect keywords=value pairs separated by "|" 01596 * @return string ImageMagick prepared parameters. 01597 * @access private 01598 * @see makeEffect() 01599 */ 01600 function IMparams($setup) { 01601 if (!trim($setup)) { 01602 return ''; 01603 } 01604 $effects = explode('|', $setup); 01605 $commands = ''; 01606 foreach ($effects as $val) { 01607 $pairs = explode('=', $val, 2); 01608 $value = trim($pairs[1]); 01609 $effect = strtolower(trim($pairs[0])); 01610 switch ($effect) { 01611 case 'gamma': 01612 $commands .= ' -gamma ' . doubleval($value); 01613 break; 01614 case 'blur': 01615 if (!$this->NO_IM_EFFECTS) { 01616 if ($this->V5_EFFECTS) { 01617 $commands .= $this->v5_blur($value); 01618 } else { 01619 $commands .= ' -blur ' . t3lib_div::intInRange($value, 1, 99); 01620 } 01621 } 01622 break; 01623 case 'sharpen': 01624 if (!$this->NO_IM_EFFECTS) { 01625 if ($this->V5_EFFECTS) { 01626 $commands .= $this->v5_sharpen($value); 01627 } else { 01628 $commands .= ' -sharpen ' . t3lib_div::intInRange($value, 1, 99); 01629 } 01630 } 01631 break; 01632 case 'rotate': 01633 $commands .= ' -rotate ' . t3lib_div::intInRange($value, 0, 360); 01634 break; 01635 case 'solarize': 01636 $commands .= ' -solarize ' . t3lib_div::intInRange($value, 0, 99); 01637 break; 01638 case 'swirl': 01639 $commands .= ' -swirl ' . t3lib_div::intInRange($value, 0, 1000); 01640 break; 01641 case 'wave': 01642 $params = t3lib_div::intExplode(',', $value); 01643 $commands .= ' -wave ' . t3lib_div::intInRange($params[0], 0, 99) . 'x' . t3lib_div::intInRange($params[1], 0, 99); 01644 break; 01645 case 'charcoal': 01646 $commands .= ' -charcoal ' . t3lib_div::intInRange($value, 0, 100); 01647 break; 01648 case 'gray': 01649 $commands .= ' -colorspace GRAY'; 01650 break; 01651 case 'edge': 01652 $commands .= ' -edge ' . t3lib_div::intInRange($value, 0, 99); 01653 break; 01654 case 'emboss': 01655 $commands .= ' -emboss'; 01656 break; 01657 case 'flip': 01658 $commands .= ' -flip'; 01659 break; 01660 case 'flop': 01661 $commands .= ' -flop'; 01662 break; 01663 case 'colors': 01664 $commands .= ' -colors ' . t3lib_div::intInRange($value, 2, 255); 01665 break; 01666 case 'shear': 01667 $commands .= ' -shear ' . t3lib_div::intInRange($value, -90, 90); 01668 break; 01669 case 'invert': 01670 $commands .= ' -negate'; 01671 break; 01672 } 01673 } 01674 return $commands; 01675 } 01676 01677 /** 01678 * Implements the "ADJUST" GIFBUILDER object 01679 * 01680 * @param pointer GDlib image pointer 01681 * @param array TypoScript array with configuration for the GIFBUILDER object. 01682 * @return void 01683 * @see tslib_gifBuilder::make(), autoLevels(), outputLevels(), inputLevels() 01684 */ 01685 function adjust(&$im, $conf) { 01686 $setup = $conf['value']; 01687 if (!trim($setup)) { 01688 return ''; 01689 } 01690 $effects = explode('|', $setup); 01691 foreach ($effects as $val) { 01692 $pairs = explode('=', $val, 2); 01693 $value = trim($pairs[1]); 01694 $effect = strtolower(trim($pairs[0])); 01695 switch ($effect) { 01696 case 'inputlevels': // low,high 01697 $params = t3lib_div::intExplode(',', $value); 01698 $this->inputLevels($im, $params[0], $params[1]); 01699 break; 01700 case 'outputlevels': 01701 $params = t3lib_div::intExplode(',', $value); 01702 $this->outputLevels($im, $params[0], $params[1]); 01703 break; 01704 case 'autolevels': 01705 $this->autoLevels($im); 01706 break; 01707 } 01708 } 01709 } 01710 01711 /** 01712 * Implements the "CROP" GIFBUILDER object 01713 * 01714 * @param pointer GDlib image pointer 01715 * @param array TypoScript array with configuration for the GIFBUILDER object. 01716 * @return void 01717 * @see tslib_gifBuilder::make() 01718 */ 01719 function crop(&$im, $conf) { 01720 $this->setWorkArea(''); // clears workArea to total image 01721 $cords = t3lib_div::intExplode(',', $conf['crop'] . ',,,'); 01722 $conf['offset'] = $cords[0] . ',' . $cords[1]; 01723 $cords = $this->objPosition($conf, $this->workArea, array($cords[2], $cords[3])); 01724 01725 $newIm = imagecreatetruecolor($cords[2], $cords[3]); 01726 $cols = $this->convertColor($conf['backColor'] ? $conf['backColor'] : $this->setup['backColor']); 01727 $Bcolor = ImageColorAllocate($newIm, $cols[0], $cols[1], $cols[2]); 01728 ImageFilledRectangle($newIm, 0, 0, $cords[2], $cords[3], $Bcolor); 01729 01730 $newConf = array(); 01731 $workArea = array(0, 0, $cords[2], $cords[3]); 01732 if ($cords[0] < 0) { 01733 $workArea[0] = abs($cords[0]); 01734 } else { 01735 $newConf['offset'] = -$cords[0]; 01736 } 01737 if ($cords[1] < 0) { 01738 $workArea[1] = abs($cords[1]); 01739 } else { 01740 $newConf['offset'] .= ',' . -$cords[1]; 01741 } 01742 01743 $this->copyGifOntoGif($newIm, $im, $newConf, $workArea); 01744 $im = $newIm; 01745 $this->w = imagesx($im); 01746 $this->h = imagesy($im); 01747 $this->setWorkArea(''); // clears workArea to total image 01748 } 01749 01750 /** 01751 * Implements the "SCALE" GIFBUILDER object 01752 * 01753 * @param pointer GDlib image pointer 01754 * @param array TypoScript array with configuration for the GIFBUILDER object. 01755 * @return void 01756 * @see tslib_gifBuilder::make() 01757 */ 01758 function scale(&$im, $conf) { 01759 if ($conf['width'] || $conf['height'] || $conf['params']) { 01760 $tmpStr = $this->randomName(); 01761 $theFile = $tmpStr . '.' . $this->gifExtension; 01762 $this->ImageWrite($im, $theFile); 01763 $theNewFile = $this->imageMagickConvert($theFile, $this->gifExtension, $conf['width'], $conf['height'], $conf['params'], '', ''); 01764 $tmpImg = $this->imageCreateFromFile($theNewFile[3]); 01765 if ($tmpImg) { 01766 ImageDestroy($im); 01767 $im = $tmpImg; 01768 $this->w = imagesx($im); 01769 $this->h = imagesy($im); 01770 $this->setWorkArea(''); // clears workArea to total image 01771 } 01772 if (!$this->dontUnlinkTempFiles) { 01773 unlink($theFile); 01774 if ($theNewFile[3] && $theNewFile[3] != $theFile) { 01775 unlink($theNewFile[3]); 01776 } 01777 } 01778 } 01779 } 01780 01781 /** 01782 * Implements the "WORKAREA" GIFBUILDER object when setting it 01783 * Setting internal working area boundaries (->workArea) 01784 * 01785 * @param string Working area dimensions, comma separated 01786 * @return void 01787 * @access private 01788 * @see tslib_gifBuilder::make() 01789 */ 01790 function setWorkArea($workArea) { 01791 $this->workArea = t3lib_div::intExplode(',', $workArea); 01792 $this->workArea = $this->applyOffset($this->workArea, $this->OFFSET); 01793 if (!$this->workArea[2]) { 01794 $this->workArea[2] = $this->w; 01795 } 01796 if (!$this->workArea[3]) { 01797 $this->workArea[3] = $this->h; 01798 } 01799 } 01800 01801 01802 /************************* 01803 * 01804 * Adjustment functions 01805 * 01806 ************************/ 01807 01808 /** 01809 * Apply auto-levels to input image pointer 01810 * 01811 * @param integer GDlib Image Pointer 01812 * @return void 01813 */ 01814 function autolevels(&$im) { 01815 $totalCols = ImageColorsTotal($im); 01816 $min = 255; 01817 $max = 0; 01818 for ($c = 0; $c < $totalCols; $c++) { 01819 $cols = ImageColorsForIndex($im, $c); 01820 $grayArr[] = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3); 01821 } 01822 $min = min($grayArr); 01823 $max = max($grayArr); 01824 $delta = $max - $min; 01825 if ($delta) { 01826 for ($c = 0; $c < $totalCols; $c++) { 01827 $cols = ImageColorsForIndex($im, $c); 01828 $cols['red'] = floor(($cols['red'] - $min) / $delta * 255); 01829 $cols['green'] = floor(($cols['green'] - $min) / $delta * 255); 01830 $cols['blue'] = floor(($cols['blue'] - $min) / $delta * 255); 01831 ImageColorSet($im, $c, $cols['red'], $cols['green'], $cols['blue']); 01832 } 01833 } 01834 } 01835 01836 /** 01837 * Apply output levels to input image pointer (decreasing contrast) 01838 * 01839 * @param integer GDlib Image Pointer 01840 * @param integer The "low" value (close to 0) 01841 * @param integer The "high" value (close to 255) 01842 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...) 01843 * @return void 01844 */ 01845 function outputLevels(&$im, $low, $high, $swap = '') { 01846 if ($low < $high) { 01847 $low = t3lib_div::intInRange($low, 0, 255); 01848 $high = t3lib_div::intInRange($high, 0, 255); 01849 01850 if ($swap) { 01851 $temp = $low; 01852 $low = 255 - $high; 01853 $high = 255 - $temp; 01854 } 01855 01856 $delta = $high - $low; 01857 $totalCols = ImageColorsTotal($im); 01858 for ($c = 0; $c < $totalCols; $c++) { 01859 $cols = ImageColorsForIndex($im, $c); 01860 $cols['red'] = $low + floor($cols['red'] / 255 * $delta); 01861 $cols['green'] = $low + floor($cols['green'] / 255 * $delta); 01862 $cols['blue'] = $low + floor($cols['blue'] / 255 * $delta); 01863 ImageColorSet($im, $c, $cols['red'], $cols['green'], $cols['blue']); 01864 } 01865 } 01866 } 01867 01868 /** 01869 * Apply input levels to input image pointer (increasing contrast) 01870 * 01871 * @param integer GDlib Image Pointer 01872 * @param integer The "low" value (close to 0) 01873 * @param integer The "high" value (close to 255) 01874 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...) 01875 * @return void 01876 */ 01877 function inputLevels(&$im, $low, $high, $swap = '') { 01878 if ($low < $high) { 01879 $low = t3lib_div::intInRange($low, 0, 255); 01880 $high = t3lib_div::intInRange($high, 0, 255); 01881 01882 if ($swap) { 01883 $temp = $low; 01884 $low = 255 - $high; 01885 $high = 255 - $temp; 01886 } 01887 01888 $delta = $high - $low; 01889 $totalCols = ImageColorsTotal($im); 01890 for ($c = 0; $c < $totalCols; $c++) { 01891 $cols = ImageColorsForIndex($im, $c); 01892 $cols['red'] = t3lib_div::intInRange(($cols['red'] - $low) / $delta * 255, 0, 255); 01893 $cols['green'] = t3lib_div::intInRange(($cols['green'] - $low) / $delta * 255, 0, 255); 01894 $cols['blue'] = t3lib_div::intInRange(($cols['blue'] - $low) / $delta * 255, 0, 255); 01895 ImageColorSet($im, $c, $cols['red'], $cols['green'], $cols['blue']); 01896 } 01897 } 01898 } 01899 01900 /** 01901 * Reduce colors in image using IM and create a palette based image if possible (<=256 colors) 01902 * 01903 * @param string Image file to reduce 01904 * @param integer Number of colors to reduce the image to. 01905 * @return string Reduced file 01906 */ 01907 function IMreduceColors($file, $cols) { 01908 $fI = t3lib_div::split_fileref($file); 01909 $ext = strtolower($fI['fileext']); 01910 $result = $this->randomName() . '.' . $ext; 01911 if (($reduce = t3lib_div::intInRange($cols, 0, ($ext == 'gif' ? 256 : $this->truecolorColors), 0)) > 0) { 01912 $params = ' -colors ' . $reduce; 01913 if (!$this->im_version_4) { 01914 // IM4 doesn't have this options but forces them automatically if applicaple (<256 colors in image) 01915 if ($reduce <= 256) { 01916 $params .= ' -type Palette'; 01917 } 01918 if ($ext == 'png' && $reduce <= 256) { 01919 $prefix = 'png8:'; 01920 } 01921 } 01922 $this->imageMagickExec($file, $prefix . $result, $params); 01923 if ($result) { 01924 return $result; 01925 } 01926 } 01927 return ''; 01928 } 01929 01930 01931 /********************************* 01932 * 01933 * GIFBUILDER Helper functions 01934 * 01935 *********************************/ 01936 01937 /** 01938 * Checks if the $fontFile is already at an absolute path and if not, prepends the correct path. 01939 * Use PATH_site unless we are in the backend. 01940 * Call it by t3lib_stdGraphic::prependAbsolutePath() 01941 * 01942 * @param string The font file 01943 * @return string The font file with absolute path. 01944 */ 01945 function prependAbsolutePath($fontFile) { 01946 $absPath = defined('PATH_typo3') ? dirname(PATH_thisScript) . '/' : PATH_site; 01947 $fontFile = t3lib_div::isAbsPath($fontFile) ? $fontFile : t3lib_div::resolveBackPath($absPath . $fontFile); 01948 return $fontFile; 01949 } 01950 01951 /** 01952 * Returns the IM command for sharpening with ImageMagick 5 (when $this->V5_EFFECTS is set). 01953 * Uses $this->im5fx_sharpenSteps for translation of the factor to an actual command. 01954 * 01955 * @param integer The sharpening factor, 0-100 (effectively in 10 steps) 01956 * @return string The sharpening command, eg. " -sharpen 3x4" 01957 * @see makeText(), IMparams(), v5_blur() 01958 */ 01959 function v5_sharpen($factor) { 01960 $factor = t3lib_div::intInRange(ceil($factor / 10), 0, 10); 01961 01962 $sharpenArr = explode(',', ',' . $this->im5fx_sharpenSteps); 01963 $sharpenF = trim($sharpenArr[$factor]); 01964 if ($sharpenF) { 01965 $cmd = ' -sharpen ' . $sharpenF; 01966 return $cmd; 01967 } 01968 } 01969 01970 /** 01971 * Returns the IM command for blurring with ImageMagick 5 (when $this->V5_EFFECTS is set). 01972 * Uses $this->im5fx_blurSteps for translation of the factor to an actual command. 01973 * 01974 * @param integer The blurring factor, 0-100 (effectively in 10 steps) 01975 * @return string The blurring command, eg. " -blur 3x4" 01976 * @see makeText(), IMparams(), v5_sharpen() 01977 */ 01978 function v5_blur($factor) { 01979 $factor = t3lib_div::intInRange(ceil($factor / 10), 0, 10); 01980 01981 $blurArr = explode(',', ',' . $this->im5fx_blurSteps); 01982 $blurF = trim($blurArr[$factor]); 01983 if ($blurF) { 01984 $cmd = ' -blur ' . $blurF; 01985 return $cmd; 01986 } 01987 } 01988 01989 /** 01990 * Returns a random filename prefixed with "temp_" and then 32 char md5 hash (without extension) from $this->tempPath. 01991 * 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. 01992 * 01993 * @return string 01994 */ 01995 function randomName() { 01996 $this->createTempSubDir('temp/'); 01997 return $this->tempPath . 'temp/' . md5(uniqid('')); 01998 } 01999 02000 /** 02001 * Applies offset value to coordinated in $cords. 02002 * Basically the value of key 0/1 of $OFFSET is added to keys 0/1 of $cords 02003 * 02004 * @param array Integer coordinates in key 0/1 02005 * @param array Offset values in key 0/1 02006 * @return array Modified $cords array 02007 */ 02008 function applyOffset($cords, $OFFSET) { 02009 $cords[0] = intval($cords[0]) + intval($OFFSET[0]); 02010 $cords[1] = intval($cords[1]) + intval($OFFSET[1]); 02011 return $cords; 02012 } 02013 02014 /** 02015 * Converts a "HTML-color" TypoScript datatype to RGB-values. 02016 * Default is 0,0,0 02017 * 02018 * @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 02019 * @return array RGB values in key 0/1/2 of the array 02020 */ 02021 function convertColor($string) { 02022 $col = array(); 02023 $cParts = explode(':', $string, 2); 02024 02025 // Finding the RGB definitions of the color: 02026 $string = $cParts[0]; 02027 if (strstr($string, '#')) { 02028 $string = preg_replace('/[^A-Fa-f0-9]*/', '', $string); 02029 $col[] = HexDec(substr($string, 0, 2)); 02030 $col[] = HexDec(substr($string, 2, 2)); 02031 $col[] = HexDec(substr($string, 4, 2)); 02032 } elseif (strstr($string, ',')) { 02033 $string = preg_replace('/[^,0-9]*/', '', $string); 02034 $strArr = explode(',', $string); 02035 $col[] = intval($strArr[0]); 02036 $col[] = intval($strArr[1]); 02037 $col[] = intval($strArr[2]); 02038 } else { 02039 $string = strtolower(trim($string)); 02040 if ($this->colMap[$string]) { 02041 $col = $this->colMap[$string]; 02042 } else { 02043 $col = array(0, 0, 0); 02044 } 02045 } 02046 // ... and possibly recalculating the value 02047 if (trim($cParts[1])) { 02048 $cParts[1] = trim($cParts[1]); 02049 if (substr($cParts[1], 0, 1) == '*') { 02050 $val = doubleval(substr($cParts[1], 1)); 02051 $col[0] = t3lib_div::intInRange($col[0] * $val, 0, 255); 02052 $col[1] = t3lib_div::intInRange($col[1] * $val, 0, 255); 02053 $col[2] = t3lib_div::intInRange($col[2] * $val, 0, 255); 02054 } else { 02055 $val = intval($cParts[1]); 02056 $col[0] = t3lib_div::intInRange($col[0] + $val, 0, 255); 02057 $col[1] = t3lib_div::intInRange($col[1] + $val, 0, 255); 02058 $col[2] = t3lib_div::intInRange($col[2] + $val, 0, 255); 02059 } 02060 } 02061 return $col; 02062 } 02063 02064 /** 02065 * Recode string 02066 * Used with text strings for fonts when languages has other character sets. 02067 * 02068 * @param string The text to recode 02069 * @return string The recoded string. Should be UTF-8 output. MAY contain entities (eg. { or &#quot; which should render as real chars). 02070 */ 02071 function recodeString($string) { 02072 // Recode string to UTF-8 from $this->nativeCharset: 02073 if ($this->nativeCharset && $this->nativeCharset != 'utf-8') { 02074 $string = $this->csConvObj->utf8_encode($string, $this->nativeCharset); // Convert to UTF-8 02075 } 02076 02077 return $string; 02078 } 02079 02080 /** 02081 * Split a string into an array of individual characters 02082 * 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. 02083 * 02084 * @param string The text string to split 02085 * @param boolean Return Unicode numbers instead of chars. 02086 * @return array Numerical array with a char as each value. 02087 */ 02088 function singleChars($theText, $returnUnicodeNumber = FALSE) { 02089 if ($this->nativeCharset) { 02090 return $this->csConvObj->utf8_to_numberarray($theText, 1, $returnUnicodeNumber ? 0 : 1); // Get an array of separated UTF-8 chars 02091 } else { 02092 $output = array(); 02093 $c = strlen($theText); 02094 for ($a = 0; $a < $c; $a++) { 02095 $output[] = substr($theText, $a, 1); 02096 } 02097 return $output; 02098 } 02099 } 02100 02101 /** 02102 * 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 02103 * 02104 * @param array TypoScript configuration for a GIFBUILDER object 02105 * @param array Workarea definition 02106 * @param array BB (Bounding box) array. Not just used for TEXT objects but also for others 02107 * @return array [0]=x, [1]=y, [2]=w, [3]=h 02108 * @access private 02109 * @see copyGifOntoGif(), makeBox(), crop() 02110 */ 02111 function objPosition($conf, $workArea, $BB) { 02112 // offset, align, valign, workarea 02113 $result = array(); 02114 $result[2] = $BB[0]; 02115 $result[3] = $BB[1]; 02116 $w = $workArea[2]; 02117 $h = $workArea[3]; 02118 02119 $align = explode(',', $conf['align']); 02120 $align[0] = strtolower(substr(trim($align[0]), 0, 1)); 02121 $align[1] = strtolower(substr(trim($align[1]), 0, 1)); 02122 02123 switch ($align[0]) { 02124 case 'r': 02125 $result[0] = $w - $result[2]; 02126 break; 02127 case 'c': 02128 $result[0] = round(($w - $result[2]) / 2); 02129 break; 02130 default: 02131 $result[0] = 0; 02132 break; 02133 } 02134 switch ($align[1]) { 02135 case 'b': 02136 $result[1] = $h - $result[3]; // y pos 02137 break; 02138 case 'c': 02139 $result[1] = round(($h - $result[3]) / 2); 02140 break; 02141 default: 02142 $result[1] = 0; 02143 break; 02144 } 02145 $result = $this->applyOffset($result, t3lib_div::intExplode(',', $conf['offset'])); 02146 $result = $this->applyOffset($result, $workArea); 02147 return $result; 02148 } 02149 02150 02151 /*********************************** 02152 * 02153 * Scaling, Dimensions of images 02154 * 02155 ***********************************/ 02156 02157 /** 02158 * Converts $imagefile to another file in temp-dir of type $newExt (extension). 02159 * 02160 * @param string The image filepath 02161 * @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. 02162 * @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 02163 * @param string Height. See $w 02164 * @param string Additional ImageMagick parameters. 02165 * @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... 02166 * @param array An array with options passed to getImageScale (see this function). 02167 * @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. 02168 * @return array [0]/[1] is w/h, [2] is file extension and [3] is the filename. 02169 * @see getImageScale(), typo3/show_item.php, fileList_ext::renderImage(), tslib_cObj::getImgResource(), SC_tslib_showpic::show(), maskImageOntoImage(), copyImageOntoImage(), scale() 02170 */ 02171 function imageMagickConvert($imagefile, $newExt = '', $w = '', $h = '', $params = '', $frame = '', $options = '', $mustCreate = 0) { 02172 if ($this->NO_IMAGE_MAGICK) { 02173 // Returning file info right away 02174 return $this->getImageDimensions($imagefile); 02175 } 02176 02177 if ($info = $this->getImageDimensions($imagefile)) { 02178 $newExt = strtolower(trim($newExt)); 02179 if (!$newExt) { // If no extension is given the original extension is used 02180 $newExt = $info[2]; 02181 } 02182 if ($newExt == 'web') { 02183 if (t3lib_div::inList($this->webImageExt, $info[2])) { 02184 $newExt = $info[2]; 02185 } else { 02186 $newExt = $this->gif_or_jpg($info[2], $info[0], $info[1]); 02187 if (!$params) { 02188 $params = $this->cmds[$newExt]; 02189 } 02190 } 02191 } 02192 if (t3lib_div::inList($this->imageFileExt, $newExt)) { 02193 if (strstr($w . $h, 'm')) { 02194 $max = 1; 02195 } else { 02196 $max = 0; 02197 } 02198 02199 $data = $this->getImageScale($info, $w, $h, $options); 02200 $w = $data['origW']; 02201 $h = $data['origH']; 02202 02203 // if no conversion should be performed 02204 // this flag is true if the width / height does NOT dictate 02205 // the image to be scaled!! (that is if no width / height is 02206 // given or if the destination w/h matches the original image 02207 // dimensions or if the option to not scale the image is set) 02208 $noScale = (!$w && !$h) || ($data[0] == $info[0] && $data[1] == $info[1]) || $options['noScale']; 02209 02210 if ($noScale && !$data['crs'] && !$params && !$frame && $newExt == $info[2] && !$mustCreate) { 02211 // set the new width and height before returning, 02212 // if the noScale option is set 02213 if ($options['noScale']) { 02214 $info[0] = $data[0]; 02215 $info[1] = $data[1]; 02216 } 02217 $info[3] = $imagefile; 02218 return $info; 02219 } 02220 $info[0] = $data[0]; 02221 $info[1] = $data[1]; 02222 02223 $frame = $this->noFramePrepended ? '' : intval($frame); 02224 02225 if (!$params) { 02226 $params = $this->cmds[$newExt]; 02227 } 02228 02229 // Cropscaling: 02230 if ($data['crs']) { 02231 if (!$data['origW']) { 02232 $data['origW'] = $data[0]; 02233 } 02234 if (!$data['origH']) { 02235 $data['origH'] = $data[1]; 02236 } 02237 $offsetX = intval(($data[0] - $data['origW']) * ($data['cropH'] + 100) / 200); 02238 $offsetY = intval(($data[1] - $data['origH']) * ($data['cropV'] + 100) / 200); 02239 $params .= ' -crop ' . $data['origW'] . 'x' . $data['origH'] . '+' . $offsetX . '+' . $offsetY . ' '; 02240 } 02241 02242 $command = $this->scalecmd . ' ' . $info[0] . 'x' . $info[1] . '! ' . $params . ' '; 02243 $cropscale = ($data['crs'] ? 'crs-V' . $data['cropV'] . 'H' . $data['cropH'] : ''); 02244 02245 if ($this->alternativeOutputKey) { 02246 $theOutputName = t3lib_div::shortMD5($command . $cropscale . basename($imagefile) . $this->alternativeOutputKey . '[' . $frame . ']'); 02247 } else { 02248 $theOutputName = t3lib_div::shortMD5($command . $cropscale . $imagefile . filemtime($imagefile) . '[' . $frame . ']'); 02249 } 02250 if ($this->imageMagickConvert_forceFileNameBody) { 02251 $theOutputName = $this->imageMagickConvert_forceFileNameBody; 02252 $this->imageMagickConvert_forceFileNameBody = ''; 02253 } 02254 02255 // Making the temporary filename: 02256 $this->createTempSubDir('pics/'); 02257 $output = $this->absPrefix . $this->tempPath . 'pics/' . $this->filenamePrefix . $theOutputName . '.' . $newExt; 02258 02259 // Register temporary filename: 02260 $GLOBALS['TEMP_IMAGES_ON_PAGE'][] = $output; 02261 02262 if ($this->dontCheckForExistingTempFile || !$this->file_exists_typo3temp_file($output, $imagefile)) { 02263 $this->imageMagickExec($imagefile, $output, $command, $frame); 02264 } 02265 if (file_exists($output)) { 02266 $info[3] = $output; 02267 $info[2] = $newExt; 02268 if ($params) { // params could realisticly change some imagedata! 02269 $info = $this->getImageDimensions($info[3]); 02270 } 02271 if ($info[2] == $this->gifExtension && !$this->dontCompress) { 02272 t3lib_div::gif_compress($info[3], ''); // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD) 02273 } 02274 return $info; 02275 } 02276 } 02277 } 02278 } 02279 02280 /** 02281 * Gets the input image dimensions. 02282 * 02283 * @param string The image filepath 02284 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 02285 * @see imageMagickConvert(), tslib_cObj::getImgResource() 02286 */ 02287 function getImageDimensions($imageFile) { 02288 preg_match('/([^\.]*)$/', $imageFile, $reg); 02289 if (file_exists($imageFile) && t3lib_div::inList($this->imageFileExt, strtolower($reg[0]))) { 02290 if ($returnArr = $this->getCachedImageDimensions($imageFile)) { 02291 return $returnArr; 02292 } else { 02293 if ($temp = @getImageSize($imageFile)) { 02294 $returnArr = array($temp[0], $temp[1], strtolower($reg[0]), $imageFile); 02295 } else { 02296 $returnArr = $this->imageMagickIdentify($imageFile); 02297 } 02298 if ($returnArr) { 02299 $this->cacheImageDimensions($returnArr); 02300 return $returnArr; 02301 } 02302 } 02303 } 02304 return FALSE; 02305 } 02306 02307 /** 02308 * Cache the result of the getImageDimensions function into the database. Does not check if the 02309 * file exists! 02310 * 02311 * @param array $identifyResult: Result of the getImageDimensions function 02312 * @return boolean True if operation was successful 02313 * @author Michael Stucki <michael@typo3.org> / Robert Lemke <rl@robertlemke.de> 02314 */ 02315 function cacheImageDimensions($identifyResult) { 02316 // Create md5 hash of filemtime and filesize 02317 $md5Hash = md5(filemtime($identifyResult[3]) . filesize($identifyResult[3])); 02318 02319 $result = FALSE; 02320 if ($md5Hash) { 02321 $fieldArray = array( 02322 'md5hash' => $md5Hash, 02323 'md5filename' => md5($identifyResult[3]), 02324 'tstamp' => $GLOBALS['EXEC_TIME'], 02325 'filename' => $identifyResult[3], 02326 'imagewidth' => $identifyResult[0], 02327 'imageheight' => $identifyResult[1], 02328 ); 02329 02330 $GLOBALS['TYPO3_DB']->exec_INSERTquery( 02331 'cache_imagesizes', 02332 $fieldArray 02333 ); 02334 02335 if (!$err = $GLOBALS['TYPO3_DB']->sql_error()) { 02336 $result = TRUE; 02337 } 02338 } 02339 02340 return $result; 02341 } 02342 02343 /** 02344 * Fetch the cached imageDimensions from the MySQL database. Does not check if the image file exists! 02345 * 02346 * @param string The image filepath 02347 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 02348 * @author Michael Stucki <michael@typo3.org> 02349 * @author Robert Lemke <rl@robertlemke.de> 02350 */ 02351 function getCachedImageDimensions($imageFile) { 02352 // Create md5 hash of filemtime and filesize 02353 $md5Hash = md5(filemtime($imageFile) . filesize($imageFile)); 02354 02355 $cachedImageDimensions = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow( 02356 'md5hash, md5filename, imagewidth, imageheight', 02357 'cache_imagesizes', 02358 'md5filename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr(md5($imageFile), 'cache_imagesizes') 02359 ); 02360 02361 $result = FALSE; 02362 if (is_array($cachedImageDimensions)) { 02363 if ($cachedImageDimensions['md5hash'] != $md5Hash) { 02364 // File has changed, delete the row 02365 $GLOBALS['TYPO3_DB']->exec_DELETEquery( 02366 'cache_imagesizes', 02367 'md5filename=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($cachedImageDimensions['md5filename'], 'cache_imagesizes') 02368 ); 02369 } else { 02370 preg_match('/([^\.]*)$/', $imageFile, $imageExtension); 02371 $result = array( 02372 (int)$cachedImageDimensions['imagewidth'], 02373 (int)$cachedImageDimensions['imageheight'], 02374 strtolower($imageExtension[0]), 02375 $imageFile, 02376 ); 02377 } 02378 } 02379 02380 return $result; 02381 } 02382 02383 /** 02384 * Get numbers for scaling the image based on input 02385 * 02386 * @param array Current image information: Width, Height etc. 02387 * @param integer "required" width 02388 * @param integer "required" height 02389 * @param array Options: Keys are like "maxW", "maxH", "minW", "minH" 02390 * @return array 02391 * @access private 02392 * @see imageMagickConvert() 02393 */ 02394 function getImageScale($info, $w, $h, $options) { 02395 if (strstr($w . $h, 'm')) { 02396 $max = 1; 02397 } else { 02398 $max = 0; 02399 } 02400 02401 if (strstr($w . $h, 'c')) { 02402 $out['cropH'] = intval(substr(strstr($w, 'c'), 1)); 02403 $out['cropV'] = intval(substr(strstr($h, 'c'), 1)); 02404 $crs = TRUE; 02405 } else { 02406 $crs = FALSE; 02407 } 02408 $out['crs'] = $crs; 02409 02410 $w = intval($w); 02411 $h = intval($h); 02412 // if there are max-values... 02413 if ($options['maxW']) { 02414 if ($w) { // if width is given... 02415 if ($w > $options['maxW']) { 02416 $w = $options['maxW']; 02417 $max = 1; // height should follow 02418 } 02419 } else { 02420 if ($info[0] > $options['maxW']) { 02421 $w = $options['maxW']; 02422 $max = 1; // height should follow 02423 } 02424 } 02425 } 02426 if ($options['maxH']) { 02427 if ($h) { // if height is given... 02428 if ($h > $options['maxH']) { 02429 $h = $options['maxH']; 02430 $max = 1; // height should follow 02431 } 02432 } else { 02433 if ($info[1] > $options['maxH']) { // Changed [0] to [1] 290801 02434 $h = $options['maxH']; 02435 $max = 1; // height should follow 02436 } 02437 } 02438 } 02439 $out['origW'] = $w; 02440 $out['origH'] = $h; 02441 $out['max'] = $max; 02442 02443 if (!$this->mayScaleUp) { 02444 if ($w > $info[0]) { 02445 $w = $info[0]; 02446 } 02447 if ($h > $info[1]) { 02448 $h = $info[1]; 02449 } 02450 } 02451 if ($w || $h) { // if scaling should be performed 02452 if ($w && !$h) { 02453 $info[1] = ceil($info[1] * ($w / $info[0])); 02454 $info[0] = $w; 02455 } 02456 if (!$w && $h) { 02457 $info[0] = ceil($info[0] * ($h / $info[1])); 02458 $info[1] = $h; 02459 } 02460 if ($w && $h) { 02461 if ($max) { 02462 $ratio = $info[0] / $info[1]; 02463 if ($h * $ratio > $w) { 02464 $h = round($w / $ratio); 02465 } else { 02466 $w = round($h * $ratio); 02467 } 02468 } 02469 if ($crs) { 02470 $ratio = $info[0] / $info[1]; 02471 if ($h * $ratio < $w) { 02472 $h = round($w / $ratio); 02473 } else { 02474 $w = round($h * $ratio); 02475 } 02476 } 02477 $info[0] = $w; 02478 $info[1] = $h; 02479 } 02480 } 02481 $out[0] = $info[0]; 02482 $out[1] = $info[1]; 02483 // Set minimum-measures! 02484 if ($options['minW'] && $out[0] < $options['minW']) { 02485 if (($max || $crs) && $out[0]) { 02486 $out[1] = round($out[1] * $options['minW'] / $out[0]); 02487 } 02488 $out[0] = $options['minW']; 02489 } 02490 if ($options['minH'] && $out[1] < $options['minH']) { 02491 if (($max || $crs) && $out[1]) { 02492 $out[0] = round($out[0] * $options['minH'] / $out[1]); 02493 } 02494 $out[1] = $options['minH']; 02495 } 02496 02497 return $out; 02498 } 02499 02500 /** 02501 * Used to check if a certain process of scaling an image is already being carried out (can be logged in the SQL database) 02502 * 02503 * @param string Output imagefile 02504 * @param string Original basis file 02505 * @return boolean Returns true if the file is already being made; thus "true" means "Don't render the image again" 02506 * @access private 02507 */ 02508 function file_exists_typo3temp_file($output, $orig = '') { 02509 if ($this->enable_typo3temp_db_tracking) { 02510 if (file_exists($output)) { // If file exists, then we return immediately 02511 return 1; 02512 } else { // If not, we look up in the cache_typo3temp_log table to see if there is a image being rendered right now. 02513 $md5Hash = md5($output); 02514 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery( 02515 'md5hash', 02516 'cache_typo3temp_log', 02517 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log') . ' AND tstamp>' . ($GLOBALS['EXEC_TIME'] - 30) 02518 ); 02519 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // If there was a record, the image is being generated by another proces (we assume) 02520 if (is_object($GLOBALS['TSFE'])) { 02521 $GLOBALS['TSFE']->set_no_cache(); 02522 } // ...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...) 02523 if (is_object($GLOBALS['TT'])) { 02524 $GLOBALS['TT']->setTSlogMessage('typo3temp_log: Assume this file is being rendered now: ' . $output); 02525 } 02526 return 2; // Return 'success - 2' 02527 } 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. 02528 02529 $insertFields = array( 02530 'md5hash' => $md5Hash, 02531 'tstamp' => $GLOBALS['EXEC_TIME'], 02532 'filename' => $output, 02533 'orig_filename' => $orig 02534 ); 02535 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_typo3temp_log', 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log')); 02536 $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_typo3temp_log', $insertFields); 02537 02538 if (is_object($GLOBALS['TT'])) { 02539 $GLOBALS['TT']->setTSlogMessage('typo3temp_log: The row did not exist, so a new is written and file is being processed: ' . $output); 02540 } 02541 return 0; 02542 } 02543 } 02544 } else { 02545 return file_exists($output); 02546 } 02547 } 02548 02549 02550 /*********************************** 02551 * 02552 * ImageMagick API functions 02553 * 02554 ***********************************/ 02555 02556 /** 02557 * Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename. 02558 * Using ImageMagick 02559 * 02560 * @param string The relative (to PATH_site) image filepath 02561 * @return array 02562 */ 02563 function imageMagickIdentify($imagefile) { 02564 if (!$this->NO_IMAGE_MAGICK) { 02565 $frame = $this->noFramePrepended ? '' : '[0]'; 02566 $cmd = t3lib_div::imageMagickCommand('identify', $this->wrapFileName($imagefile) . $frame); 02567 $returnVal = array(); 02568 t3lib_utility_Command::exec($cmd, $returnVal); 02569 $splitstring = $returnVal[0]; 02570 $this->IM_commands[] = array('identify', $cmd, $returnVal[0]); 02571 if ($splitstring) { 02572 preg_match('/([^\.]*)$/', $imagefile, $reg); 02573 $splitinfo = explode(' ', $splitstring); 02574 foreach ($splitinfo as $key => $val) { 02575 $temp = ''; 02576 if ($val) { 02577 $temp = explode('x', $val); 02578 } 02579 if (intval($temp[0]) && intval($temp[1])) { 02580 $dim = $temp; 02581 break; 02582 } 02583 } 02584 if ($dim[0] && $dim[1]) { 02585 return array($dim[0], $dim[1], strtolower($reg[0]), $imagefile); 02586 } 02587 } 02588 } 02589 } 02590 02591 /** 02592 * Executes a ImageMagick "convert" on two filenames, $input and $output using $params before them. 02593 * Can be used for many things, mostly scaling and effects. 02594 * 02595 * @param string The relative (to PATH_site) image filepath, input file (read from) 02596 * @param string The relative (to PATH_site) image filepath, output filename (written to) 02597 * @param string ImageMagick parameters 02598 * @param integer Optional, refers to which frame-number to select in the image. '' or 0 02599 * will select the first frame, 1 will select the next and so on... 02600 * @return string The result of a call to PHP function "exec()" 02601 */ 02602 function imageMagickExec($input, $output, $params, $frame = 0) { 02603 if (!$this->NO_IMAGE_MAGICK) { 02604 02605 // Unless noFramePrepended is set in the Install Tool, a frame number is added to 02606 // select a specific page of the image (by default this will be the first page) 02607 if (!$this->noFramePrepended) { 02608 $frame = '[' . intval($frame) . ']'; 02609 } else { 02610 $frame = ''; 02611 } 02612 02613 $cmd = t3lib_div::imageMagickCommand('convert', $params . ' ' . $this->wrapFileName($input) . $frame . ' ' . $this->wrapFileName($output)); 02614 $this->IM_commands[] = array($output, $cmd); 02615 02616 $ret = t3lib_utility_Command::exec($cmd); 02617 t3lib_div::fixPermissions($output); // Change the permissions of the file 02618 02619 return $ret; 02620 } 02621 } 02622 02623 /** 02624 * 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) 02625 * Can be used for many things, mostly scaling and effects. 02626 * 02627 * @param string The relative (to PATH_site) image filepath, bottom file 02628 * @param string The relative (to PATH_site) image filepath, overlay file (top) 02629 * @param string The relative (to PATH_site) image filepath, the mask file (grayscale) 02630 * @param string The relative (to PATH_site) image filepath, output filename (written to) 02631 * @param [type] $handleNegation: ... 02632 * @return void 02633 */ 02634 function combineExec($input, $overlay, $mask, $output, $handleNegation = FALSE) { 02635 if (!$this->NO_IMAGE_MAGICK) { 02636 $params = '-colorspace GRAY +matte'; 02637 if ($handleNegation) { 02638 if ($this->maskNegate) { 02639 $params .= ' ' . $this->maskNegate; 02640 } 02641 } 02642 $theMask = $this->randomName() . '.' . $this->gifExtension; 02643 $this->imageMagickExec($mask, $theMask, $params); 02644 $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 02645 $this->IM_commands[] = array($output, $cmd); 02646 02647 $ret = t3lib_utility_Command::exec($cmd); 02648 t3lib_div::fixPermissions($output); // Change the permissions of the file 02649 02650 if (is_file($theMask)) { 02651 @unlink($theMask); 02652 } 02653 02654 return $ret; 02655 } 02656 } 02657 02658 /** 02659 * Escapes a file name so it can safely be used on the command line. 02660 * 02661 * @param string $inputName filename to safeguard, must not be empty 02662 * 02663 * @return string $inputName escaped as needed 02664 */ 02665 protected function wrapFileName($inputName) { 02666 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) { 02667 $currentLocale = setlocale(LC_CTYPE, 0); 02668 setlocale(LC_CTYPE, $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLocale']); 02669 } 02670 $escapedInputName = escapeshellarg($inputName); 02671 if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['UTF8filesystem']) { 02672 setlocale(LC_CTYPE, $currentLocale); 02673 } 02674 return $escapedInputName; 02675 } 02676 02677 02678 /*********************************** 02679 * 02680 * Various IO functions 02681 * 02682 ***********************************/ 02683 02684 /** 02685 * Returns true if the input file existed 02686 * 02687 * @param string Input file to check 02688 * @return string Returns the filename if the file existed, otherwise empty. 02689 */ 02690 function checkFile($file) { 02691 if (@is_file($file)) { 02692 return $file; 02693 } else { 02694 return ''; 02695 } 02696 } 02697 02698 /** 02699 * Creates subdirectory in typo3temp/ if not already found. 02700 * 02701 * @param string Name of sub directory 02702 * @return boolean Result of t3lib_div::mkdir(), true if it went well. 02703 */ 02704 function createTempSubDir($dirName) { 02705 02706 // Checking if the this->tempPath is already prefixed with PATH_site and if not, prefix it with that constant. 02707 if (t3lib_div::isFirstPartOfStr($this->tempPath, PATH_site)) { 02708 $tmpPath = $this->tempPath; 02709 } else { 02710 $tmpPath = PATH_site . $this->tempPath; 02711 } 02712 02713 // Making the temporary filename: 02714 if (!@is_dir($tmpPath . $dirName)) { 02715 return t3lib_div::mkdir($tmpPath . $dirName); 02716 } 02717 } 02718 02719 /** 02720 * 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. 02721 * 02722 * @param pointer The image pointer (reference) 02723 * @param string The ImageMagick parameters. Like effects, scaling etc. 02724 * @return void 02725 */ 02726 function applyImageMagickToPHPGif(&$im, $command) { 02727 $tmpStr = $this->randomName(); 02728 $theFile = $tmpStr . '.' . $this->gifExtension; 02729 $this->ImageWrite($im, $theFile); 02730 $this->imageMagickExec($theFile, $theFile, $command); 02731 $tmpImg = $this->imageCreateFromFile($theFile); 02732 if ($tmpImg) { 02733 ImageDestroy($im); 02734 $im = $tmpImg; 02735 $this->w = imagesx($im); 02736 $this->h = imagesy($im); 02737 } 02738 if (!$this->dontUnlinkTempFiles) { 02739 unlink($theFile); 02740 } 02741 } 02742 02743 /** 02744 * 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. 02745 * For example: If the number of pixels exceeds $this->pixelLimitGif (normally 10000) then it will be a "jpg" string in return. 02746 * 02747 * @param string The file extension, lowercase. 02748 * @param integer The width of the output image. 02749 * @param integer The height of the output image. 02750 * @return string The filename, either "jpg" or "gif"/"png" (whatever $this->gifExtension is set to.) 02751 */ 02752 function gif_or_jpg($type, $w, $h) { 02753 if ($type == 'ai' || $w * $h < $this->pixelLimitGif) { 02754 return $this->gifExtension; 02755 } else { 02756 return 'jpg'; 02757 } 02758 } 02759 02760 /** 02761 * Writing the internal image pointer, $this->im, to file based on the extension of the input filename 02762 * Used in GIFBUILDER 02763 * Uses $this->setup['reduceColors'] for gif/png images and $this->setup['quality'] for jpg images to reduce size/quality if needed. 02764 * 02765 * @param string The filename to write to. 02766 * @return string Returns input filename 02767 * @see tslib_gifBuilder::gifBuild() 02768 */ 02769 function output($file) { 02770 if ($file) { 02771 $reg = array(); 02772 preg_match('/([^\.]*)$/', $file, $reg); 02773 $ext = strtolower($reg[0]); 02774 switch ($ext) { 02775 case 'gif': 02776 case 'png': 02777 if ($this->ImageWrite($this->im, $file)) { 02778 // ImageMagick operations 02779 if ($this->setup['reduceColors'] || !$this->png_truecolor) { 02780 $reduced = $this->IMreduceColors($file, t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256)); 02781 if ($reduced) { 02782 @copy($reduced, $file); 02783 @unlink($reduced); 02784 } 02785 } 02786 t3lib_div::gif_compress($file, 'IM'); // Compress with IM! (adds extra compression, LZW from ImageMagick) (Workaround for the absence of lzw-compression in GD) 02787 } 02788 break; 02789 case 'jpg': 02790 case 'jpeg': 02791 $quality = 0; // Use the default 02792 if ($this->setup['quality']) { 02793 $quality = t3lib_div::intInRange($this->setup['quality'], 10, 100); 02794 } 02795 if ($this->ImageWrite($this->im, $file, $quality)) { 02796 ; 02797 } 02798 break; 02799 } 02800 $GLOBALS['TEMP_IMAGES_ON_PAGE'][] = $file; 02801 } 02802 return $file; 02803 } 02804 02805 /** 02806 * Destroy internal image pointer, $this->im 02807 * 02808 * @return void 02809 * @see tslib_gifBuilder::gifBuild() 02810 */ 02811 function destroy() { 02812 ImageDestroy($this->im); 02813 } 02814 02815 /** 02816 * Returns Image Tag for input image information array. 02817 * 02818 * @param array Image information array, key 0/1 is width/height and key 3 is the src value 02819 * @return string Image tag for the input image information array. 02820 */ 02821 function imgTag($imgInfo) { 02822 return '<img src="' . $imgInfo[3] . '" width="' . $imgInfo[0] . '" height="' . $imgInfo[1] . '" border="0" alt="" />'; 02823 } 02824 02825 /** 02826 * Writes the input GDlib image pointer to file 02827 * 02828 * @param pointer The GDlib image resource pointer 02829 * @param string The filename to write to 02830 * @param integer The image quality (for JPEGs) 02831 * @return boolean The output of either imageGif, imagePng or imageJpeg based on the filename to write 02832 * @see maskImageOntoImage(), scale(), output() 02833 */ 02834 function ImageWrite($destImg, $theImage, $quality = 0) { 02835 imageinterlace($destImg, 0); 02836 $ext = strtolower(substr($theImage, strrpos($theImage, '.') + 1)); 02837 $result = FALSE; 02838 switch ($ext) { 02839 case 'jpg': 02840 case 'jpeg': 02841 if (function_exists('imageJpeg')) { 02842 if ($quality == 0) { 02843 $quality = $this->jpegQuality; 02844 } 02845 $result = imageJpeg($destImg, $theImage, $quality); 02846 } 02847 break; 02848 case 'gif': 02849 if (function_exists('imageGif')) { 02850 imagetruecolortopalette($destImg, TRUE, 256); 02851 $result = imageGif($destImg, $theImage); 02852 } 02853 break; 02854 case 'png': 02855 if (function_exists('imagePng')) { 02856 $result = ImagePng($destImg, $theImage); 02857 } 02858 break; 02859 } 02860 if ($result) { 02861 t3lib_div::fixPermissions($theImage); 02862 } 02863 return $result; 02864 } 02865 02866 /** 02867 * Creates a new GDlib image resource based on the input image filename. 02868 * 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. 02869 * 02870 * @param string Image filename 02871 * @return pointer Image Resource pointer 02872 */ 02873 function imageCreateFromFile($sourceImg) { 02874 $imgInf = pathinfo($sourceImg); 02875 $ext = strtolower($imgInf['extension']); 02876 02877 switch ($ext) { 02878 case 'gif': 02879 if (function_exists('imagecreatefromgif')) { 02880 return imageCreateFromGif($sourceImg); 02881 } 02882 break; 02883 case 'png': 02884 if (function_exists('imagecreatefrompng')) { 02885 return imageCreateFromPng($sourceImg); 02886 } 02887 break; 02888 case 'jpg': 02889 case 'jpeg': 02890 if (function_exists('imagecreatefromjpeg')) { 02891 return imageCreateFromJpeg($sourceImg); 02892 } 02893 break; 02894 } 02895 02896 // If non of the above: 02897 $i = @getimagesize($sourceImg); 02898 $im = imagecreatetruecolor($i[0], $i[1]); 02899 $Bcolor = ImageColorAllocate($im, 128, 128, 128); 02900 ImageFilledRectangle($im, 0, 0, $i[0], $i[1], $Bcolor); 02901 return $im; 02902 } 02903 02904 /** 02905 * Returns the HEX color value for an RGB color array 02906 * 02907 * @param array RGB color array 02908 * @return string HEX color value 02909 */ 02910 function hexColor($col) { 02911 $r = dechex($col[0]); 02912 if (strlen($r) < 2) { 02913 $r = '0' . $r; 02914 } 02915 $g = dechex($col[1]); 02916 if (strlen($g) < 2) { 02917 $g = '0' . $g; 02918 } 02919 $b = dechex($col[2]); 02920 if (strlen($b) < 2) { 02921 $b = '0' . $b; 02922 } 02923 return '#' . $r . $g . $b; 02924 } 02925 02926 /** 02927 * Unifies all colors given in the colArr color array to the first color in the array. 02928 * 02929 * @param pointer Image resource 02930 * @param array Array containing RGB color arrays 02931 * @param [type] $closest: ... 02932 * @return integer The index of the unified color 02933 */ 02934 function unifyColors(&$img, $colArr, $closest = FALSE) { 02935 $retCol = -1; 02936 if (is_array($colArr) && count($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) { 02937 $firstCol = array_shift($colArr); 02938 $firstColArr = $this->convertColor($firstCol); 02939 if (count($colArr) > 1) { 02940 $origName = $preName = $this->randomName() . '.png'; 02941 $postName = $this->randomName() . '.png'; 02942 $this->imageWrite($img, $preName); 02943 $firstCol = $this->hexColor($firstColArr); 02944 foreach ($colArr as $transparentColor) { 02945 $transparentColor = $this->convertColor($transparentColor); 02946 $transparentColor = $this->hexColor($transparentColor); 02947 $cmd = '-fill "' . $firstCol . '" -opaque "' . $transparentColor . '"'; 02948 $this->imageMagickExec($preName, $postName, $cmd); 02949 $preName = $postName; 02950 } 02951 $this->imageMagickExec($postName, $origName, ''); 02952 if (@is_file($origName)) { 02953 $tmpImg = $this->imageCreateFromFile($origName); 02954 } 02955 } else { 02956 $tmpImg = $img; 02957 } 02958 if ($tmpImg) { 02959 $img = $tmpImg; 02960 if ($closest) { 02961 $retCol = ImageColorClosest($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]); 02962 } else { 02963 $retCol = ImageColorExact($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]); 02964 } 02965 } 02966 // unlink files from process 02967 if (!$this->dontUnlinkTempFiles) { 02968 if ($origName) { 02969 @unlink($origName); 02970 } 02971 if ($postName) { 02972 @unlink($postName); 02973 } 02974 } 02975 } 02976 return $retCol; 02977 } 02978 02979 02980 } 02981 02982 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php'])) { 02983 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php']); 02984 } 02985 02986 ?>
1.8.0