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