ttimpe

Patched class.t3lib_stdgraphic.php which generates 2x-images

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