TYPO3 API  SVNRelease
class.t3lib_stdgraphic.php
Go to the documentation of this file.
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. &#123; 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 ?>