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