* Fix bug #3308: Check for deleted records when displaying language overlays
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_stdgraphic.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2006 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, dont 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 if ($data['crs']) {
2190 if ($this->dontCheckForExistingTempFile || !$this->file_exists_typo3temp_file($output, $imagefile)) {
2191 $crsOutput = str_replace('pics/', 'pics/crs-', $output);
2192 $this->imageMagickExec($imagefile.$frame, $crsOutput, $command);
2193 $gifCreator = t3lib_div::makeInstance('tslib_gifbuilder');
2194 $gifCreator->init();
2195 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib'] !== 0) {
2196 if (!$data['origW']) { $data['origW'] = $data[0]; }
2197 if (!$data['origH']) { $data['origH'] = $data[1]; }
2198 $ofX = intval(($data['origW'] - $data[0]) * ($data['cropH']+100)/200);
2199 $ofY = intval(($data['origH'] - $data[1]) * ($data['cropV']+100)/200);
2200 $tmpParm = Array('XY' => intval($data['origW']).','.intval($data['origH']),
2201 '10' => 'IMAGE',
2202 '10.' => array('file'=> $crsOutput, 'offset'=> $ofX.','.$ofY),
2203 );
2204 $gifCreator->start($tmpParm, array());
2205 $newoutput = $gifCreator->gifBuild();
2206 if (!copy($newoutput,$output)) {
2207 $output = $newoutput;
2208 }
2209 } else {
2210 $output = $crsOutput;
2211 }
2212 }
2213 } elseif ($this->dontCheckForExistingTempFile || !$this->file_exists_typo3temp_file($output,$imagefile)) {
2214 $this->imageMagickExec($imagefile.$frame,$output,$command);
2215 }
2216 if (@file_exists($output)) {
2217 $info[3] = $output;
2218 $info[2] = $newExt;
2219 if ($params) { // params could realisticly change some imagedata!
2220 $info=$this->getImageDimensions($info[3]);
2221 }
2222 if ($info[2]==$this->gifExtension && !$this->dontCompress) {
2223 t3lib_div::gif_compress($info[3],''); // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD)
2224 }
2225 return $info;
2226 }
2227 }
2228 }
2229 }
2230
2231 /**
2232 * Gets the input image dimensions.
2233 *
2234 * @param string The image filepath
2235 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
2236 * @see imageMagickConvert(), tslib_cObj::getImgResource()
2237 */
2238 function getImageDimensions($imageFile) {
2239 ereg('([^\.]*)$',$imageFile,$reg);
2240 if (@file_exists($imageFile) && t3lib_div::inList($this->imageFileExt,strtolower($reg[0]))) {
2241 if ($returnArr = $this->getCachedImageDimensions($imageFile)) {
2242 return $returnArr;
2243 } else {
2244 if ($temp = @getImageSize($imageFile)) {
2245 $returnArr = Array($temp[0], $temp[1], strtolower($reg[0]), $imageFile);
2246 } else {
2247 $returnArr = $this->imageMagickIdentify($imageFile);
2248 }
2249 if ($returnArr) {
2250 $this->cacheImageDimensions($returnArr);
2251 return $returnArr;
2252 }
2253 }
2254 }
2255 return false;
2256 }
2257
2258 /**
2259 * Cache the result of the getImageDimensions function into the database. Does not check if the
2260 * file exists!
2261 *
2262 * @param array $identifyResult: Result of the getImageDimensions function
2263 * @return boolean True if operation was successful
2264 * @author Michael Stucki <michael@typo3.org> / Robert Lemke <rl@robertlemke.de>
2265 */
2266 function cacheImageDimensions($identifyResult) {
2267 global $TYPO3_DB;
2268 // Create a md5 hash of the filename
2269 if (function_exists('md5_file')) {
2270 $md5Hash = md5_file($identifyResult[3]);
2271 } else {
2272 $md5Hash = md5 (t3lib_div::getURL($identifyResult[3]));
2273 }
2274 if ($md5Hash) {
2275 $fieldArr = array (
2276 'md5hash' => $md5Hash,
2277 'md5filename' => md5($identifyResult[3]),
2278 'tstamp' => time(),
2279 'filename' => $identifyResult[3],
2280 'imagewidth' => $identifyResult[0],
2281 'imageheight' => $identifyResult[1],
2282 );
2283 $TYPO3_DB->exec_INSERTquery('cache_imagesizes', $fieldArr);
2284 if (!$err = $TYPO3_DB->sql_error()) {
2285 return true;
2286 }
2287 }
2288 return false;
2289 }
2290
2291 /**
2292 * Fetch the cached imageDimensions from the MySQL database. Does not check if the image file exists!
2293 *
2294 * @param string The image filepath
2295 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
2296 * @author Michael Stucki <michael@typo3.org> / Robert Lemke <rl@robertlemke.de>
2297 */
2298 function getCachedImageDimensions($imageFile) {
2299 global $TYPO3_DB;
2300 // Create a md5 hash of the filename
2301 if(function_exists('md5_file')) {
2302 $md5Hash = md5_file($imageFile);
2303 } else {
2304 $md5Hash = md5(t3lib_div::getURL ($imageFile));
2305 }
2306 ereg('([^\.]*)$',$imageFile,$reg);
2307 $res = $TYPO3_DB->exec_SELECTquery ('md5hash, imagewidth, imageheight', 'cache_imagesizes', 'md5filename='.$TYPO3_DB->fullQuoteStr(md5($imageFile),'cache_imagesizes'));
2308 if ($res) {
2309 if ($row = $TYPO3_DB->sql_fetch_assoc($res)) {
2310 if ($row['md5hash']!=$md5Hash) {
2311 // file has changed, delete the row
2312 $TYPO3_DB->exec_DELETEquery ('cache_imagesizes', 'md5hash='.$TYPO3_DB->fullQuoteStr($row['md5hash'],'cache_imagesizes'));
2313 } else {
2314 return (array($row['imagewidth'], $row['imageheight'], strtolower($reg[0]), $imageFile));
2315 }
2316 }
2317 }
2318 return false;
2319 }
2320
2321 /**
2322 * Get numbers for scaling the image based on input
2323 *
2324 * @param array Current image information: Width, Height etc.
2325 * @param integer "required" width
2326 * @param integer "required" height
2327 * @param array Options: Keys are like "maxW", "maxH", "minW", "minH"
2328 * @return array
2329 * @access private
2330 * @see imageMagickConvert()
2331 */
2332 function getImageScale($info,$w,$h,$options) {
2333 if (strstr($w.$h, 'm')) {$max=1;} else {$max=0;}
2334
2335 if (strstr($w.$h, 'c')) {
2336 $out['cropH'] = intval(substr(strstr($w, 'c'), 1));
2337 $out['cropV'] = intval(substr(strstr($h, 'c'), 1));
2338 $crs = true;
2339 } else {
2340 $crs = false;
2341 }
2342 $out['crs'] = $crs;
2343
2344 $w=intval($w);
2345 $h=intval($h);
2346 // if there are max-values...
2347 if ($options['maxW']) {
2348 if ($w) { // if width is given...
2349 if ($w>$options['maxW']) {
2350 $w=$options['maxW'];
2351 $max=1; // height should follow
2352 }
2353 } else {
2354 if ($info[0]>$options['maxW']) {
2355 $w=$options['maxW'];
2356 $max=1; // height should follow
2357 }
2358 }
2359 }
2360 if ($options['maxH']) {
2361 if ($h) { // if height is given...
2362 if ($h>$options['maxH']) {
2363 $h=$options['maxH'];
2364 $max=1; // height should follow
2365 }
2366 } else {
2367 if ($info[1]>$options['maxH']) { // Changed [0] to [1] 290801
2368 $h=$options['maxH'];
2369 $max=1; // height should follow
2370 }
2371 }
2372 }
2373 $out['origW']=$w;
2374 $out['origH']=$h;
2375 $out['max'] = $max;
2376
2377 if (!$this->mayScaleUp) {
2378 if ($w>$info[0]){$w=$info[0];}
2379 if ($h>$info[1]){$h=$info[1];}
2380 }
2381 if ($w || $h) { // if scaling should be performed
2382 if ($w && !$h) {
2383 $info[1] = ceil($info[1]*($w/$info[0]));
2384 $info[0] = $w;
2385 }
2386 if (!$w && $h) {
2387 $info[0] = ceil($info[0]*($h/$info[1]));
2388 $info[1] = $h;
2389 }
2390 if ($w && $h) {
2391 if ($max) {
2392 $ratio = $info[0]/$info[1];
2393 if ($h*$ratio > $w) {
2394 $h = round($w/$ratio);
2395 } else {
2396 $w = round($h*$ratio);
2397 }
2398 }
2399 if ($crs) {
2400 $ratio = $info[0] / $info[1];
2401 if ($h * $ratio < $w) {
2402 $h = round($w / $ratio);
2403 } else {
2404 $w = round($h * $ratio);
2405 }
2406 }
2407 $info[0] = $w;
2408 $info[1] = $h;
2409 }
2410 }
2411 $out[0]=$info[0];
2412 $out[1]=$info[1];
2413 // Set minimum-measures!
2414 if ($options['minW'] && $out[0]<$options['minW']) {
2415 if (($max || $crs) && $out[0]) {
2416 $out[1]= round($out[1]*$options['minW']/$out[0]);
2417 }
2418 $out[0]=$options['minW'];
2419 }
2420 if ($options['minH'] && $out[1]<$options['minH']) {
2421 if (($max || $crs) && $out[1]) {
2422 $out[0]= round($out[0]*$options['minH']/$out[1]);
2423 }
2424 $out[1]=$options['minH'];
2425 }
2426
2427 return $out;
2428 }
2429
2430 /**
2431 * Used to check if a certain process of scaling an image is already being carried out (can be logged in the SQL database)
2432 *
2433 * @param string Output imagefile
2434 * @param string Original basis file
2435 * @return boolean Returns true if the file is already being made; thus "true" means "Don't render the image again"
2436 * @access private
2437 */
2438 function file_exists_typo3temp_file($output,$orig='') {
2439 if ($this->enable_typo3temp_db_tracking) {
2440 if (@file_exists($output)) { // If file exists, then we return immediately
2441 return 1;
2442 } else { // If not, we look up in the cache_typo3temp_log table to see if there is a image being rendered right now.
2443 $md5Hash=md5($output);
2444 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('md5hash', 'cache_typo3temp_log', 'md5hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log').' AND tstamp>'.(time()-30));
2445 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { // If there was a record, the image is being generated by another proces (we assume)
2446 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...)
2447 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('typo3temp_log: Assume this file is being rendered now: '.$output);
2448 return 2; // Return 'success - 2'
2449 } 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.
2450
2451 $insertFields = array(
2452 'md5hash' => $md5Hash,
2453 'tstamp' => time(),
2454 'filename' => $output,
2455 'orig_filename' => $orig
2456 );
2457 $GLOBALS['TYPO3_DB']->exec_DELETEquery('cache_typo3temp_log', 'md5hash='.$GLOBALS['TYPO3_DB']->fullQuoteStr($md5Hash, 'cache_typo3temp_log'));
2458 $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_typo3temp_log', $insertFields);
2459
2460 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);
2461 return 0;
2462 }
2463 }
2464 } else {
2465 return @file_exists($output);
2466 }
2467 }
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486 /***********************************
2487 *
2488 * ImageMagick API functions
2489 *
2490 ***********************************/
2491
2492 /**
2493 * Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
2494 * Using ImageMagick
2495 *
2496 * @param string The relative (to PATH_site) image filepath
2497 * @return array
2498 */
2499 function imageMagickIdentify($imagefile) {
2500 if (!$this->NO_IMAGE_MAGICK) {
2501 $frame = $this->noFramePrepended?'':'[0]';
2502 $cmd = t3lib_div::imageMagickCommand('identify', $this->wrapFileName($imagefile).$frame);
2503 $returnVal = array();
2504 exec($cmd, $returnVal);
2505 $splitstring=$returnVal[0];
2506 $this->IM_commands[] = Array ('identify',$cmd,$returnVal[0]);
2507 if ($splitstring) {
2508 ereg('([^\.]*)$',$imagefile,$reg);
2509 $splitinfo = explode(' ', $splitstring);
2510 while (list($key,$val) = each($splitinfo)) {
2511 $temp = '';
2512 if ($val) {$temp = explode('x', $val);}
2513 if (intval($temp[0]) && intval($temp[1])) {
2514 $dim=$temp;
2515 break;
2516 }
2517 }
2518 if ($dim[0] && $dim[1]) {
2519 return Array($dim[0], $dim[1], strtolower($reg[0]), $imagefile);
2520 }
2521 }
2522 }
2523 }
2524
2525 /**
2526 * Executes a ImageMagick "convert" on two filenames, $input and $output using $params before them.
2527 * Can be used for many things, mostly scaling and effects.
2528 *
2529 * @param string The relative (to PATH_site) image filepath, input file (read from)
2530 * @param string The relative (to PATH_site) image filepath, output filename (written to)
2531 * @param string ImageMagick parameters
2532 * @return string The result of a call to PHP function "exec()"
2533 */
2534 function imageMagickExec($input,$output,$params) {
2535 if (!$this->NO_IMAGE_MAGICK) {
2536 $cmd = t3lib_div::imageMagickCommand('convert', $params.' '.$this->wrapFileName($input).' '.$this->wrapFileName($output));
2537 $this->IM_commands[] = array($output,$cmd);
2538
2539 $ret = exec($cmd);
2540 t3lib_div::fixPermissions($this->wrapFileName($output)); // Change the permissions of the file
2541
2542 return $ret;
2543 }
2544 }
2545
2546 /**
2547 * 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)
2548 * Can be used for many things, mostly scaling and effects.
2549 *
2550 * @param string The relative (to PATH_site) image filepath, bottom file
2551 * @param string The relative (to PATH_site) image filepath, overlay file (top)
2552 * @param string The relative (to PATH_site) image filepath, the mask file (grayscale)
2553 * @param string The relative (to PATH_site) image filepath, output filename (written to)
2554 * @param [type] $handleNegation: ...
2555 * @return void
2556 */
2557 function combineExec($input,$overlay,$mask,$output, $handleNegation = false) {
2558 if (!$this->NO_IMAGE_MAGICK) {
2559 $params = '-colorspace GRAY +matte';
2560 if ($handleNegation) {
2561 if ($this->maskNegate) {
2562 $params .= ' '.$this->maskNegate;
2563 }
2564 }
2565 $theMask = $this->randomName().'.'.$this->gifExtension;
2566 $this->imageMagickExec($mask, $theMask, $params);
2567 $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
2568 $this->IM_commands[] = Array ($output,$cmd);
2569
2570 $ret = exec($cmd);
2571 t3lib_div::fixPermissions($this->wrapFileName($output)); // Change the permissions of the file
2572
2573 if (is_file($theMask)) {
2574 @unlink($theMask);
2575 }
2576
2577 return $ret;
2578 }
2579 }
2580
2581 /**
2582 * Wrapping the input filename in double-quotes
2583 *
2584 * @param string Input filename
2585 * @return string The output wrapped in "" (if there are spaces in the filepath)
2586 * @access private
2587 */
2588 function wrapFileName($inputName) {
2589 if (strstr($inputName,' ')) {
2590 $inputName='"'.$inputName.'"';
2591 }
2592 return $inputName;
2593 }
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617 /***********************************
2618 *
2619 * Various IO functions
2620 *
2621 ***********************************/
2622
2623 /**
2624 * Returns true if the input file existed
2625 *
2626 * @param string Input file to check
2627 * @return string Returns the filename if the file existed, otherwise empty.
2628 */
2629 function checkFile($file) {
2630 if (@is_file($file)) {
2631 return $file;
2632 } else {
2633 return '';
2634 }
2635 }
2636
2637 /**
2638 * Creates subdirectory in typo3temp/ if not already found.
2639 *
2640 * @param string Name of sub directory
2641 * @return boolean Result of t3lib_div::mkdir(), true if it went well.
2642 */
2643 function createTempSubDir($dirName) {
2644
2645 // Checking if the this->tempPath is already prefixed with PATH_site and if not, prefix it with that constant.
2646 if (t3lib_div::isFirstPartOfStr($this->tempPath,PATH_site)) {
2647 $tmpPath = $this->tempPath;
2648 } else {
2649 $tmpPath = PATH_site.$this->tempPath;
2650 }
2651
2652 // Making the temporary filename:
2653 if (!@is_dir($tmpPath.$dirName)) {
2654 return t3lib_div::mkdir($tmpPath.$dirName);
2655 }
2656 }
2657
2658 /**
2659 * 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.
2660 *
2661 * @param pointer The image pointer (reference)
2662 * @param string The ImageMagick parameters. Like effects, scaling etc.
2663 * @return void
2664 */
2665 function applyImageMagickToPHPGif(&$im, $command) {
2666 $tmpStr = $this->randomName();
2667 $theFile = $tmpStr.'.'.$this->gifExtension;
2668 $this->ImageWrite($im, $theFile);
2669 $this->imageMagickExec($theFile,$theFile,$command);
2670 $tmpImg = $this->imageCreateFromFile($theFile);
2671 if ($tmpImg) {
2672 ImageDestroy($im);
2673 $im = $tmpImg;
2674 $this->w = imagesx($im);
2675 $this->h = imagesy($im);
2676 }
2677 if (!$this->dontUnlinkTempFiles) {
2678 unlink($theFile);
2679 }
2680 }
2681
2682 /**
2683 * 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.
2684 * For example: If the number of pixels exceeds $this->pixelLimitGif (normally 10000) then it will be a "jpg" string in return.
2685 *
2686 * @param string The file extension, lowercase.
2687 * @param integer The width of the output image.
2688 * @param integer The height of the output image.
2689 * @return string The filename, either "jpg" or "gif"/"png" (whatever $this->gifExtension is set to.)
2690 */
2691 function gif_or_jpg($type,$w,$h) {
2692 if ($type=='ai' || $w*$h < $this->pixelLimitGif) {
2693 return $this->gifExtension;
2694 } else {
2695 return 'jpg';
2696 }
2697 }
2698
2699 /**
2700 * Writing the internal image pointer, $this->im, to file based on the extension of the input filename
2701 * Used in GIFBUILDER
2702 * Uses $this->setup['reduceColors'] for gif/png images and $this->setup['quality'] for jpg images to reduce size/quality if needed.
2703 *
2704 * @param string The filename to write to.
2705 * @return string Returns input filename
2706 * @see tslib_gifBuilder::gifBuild()
2707 */
2708 function output($file) {
2709 if ($file) {
2710 $reg = array();
2711 ereg('([^\.]*)$',$file,$reg);
2712 $ext=strtolower($reg[0]);
2713 switch($ext) {
2714 case 'gif':
2715 case 'png':
2716 if ($this->ImageWrite($this->im, $file)) {
2717 // ImageMagick operations
2718 if ($this->setup['reduceColors'] || (!$this->png_truecolor && $this->truecolor)) {
2719 $reduced = $this->IMreduceColors($file, t3lib_div::intInRange($this->setup['reduceColors'], 256, $this->truecolorColors, 256));
2720 if ($reduced) {
2721 @copy($reduced, $file);
2722 @unlink($reduced);
2723 }
2724 }
2725 t3lib_div::gif_compress($file, 'IM'); // Compress with IM! (adds extra compression, LZW from ImageMagick) (Workaround for the absence of lzw-compression in GD)
2726 }
2727 break;
2728 case 'jpg':
2729 case 'jpeg':
2730 $quality = 0; // Use the default
2731 if($this->setup['quality']) {
2732 $quality = t3lib_div::intInRange($this->setup['quality'],10,100);
2733 }
2734 if ($this->ImageWrite($this->im, $file, $quality));
2735 break;
2736 }
2737 $GLOBALS['TEMP_IMAGES_ON_PAGE'][]=$file;
2738 }
2739 return $file;
2740 }
2741
2742 /**
2743 * Destroy internal image pointer, $this->im
2744 *
2745 * @return void
2746 * @see tslib_gifBuilder::gifBuild()
2747 */
2748 function destroy() {
2749 ImageDestroy($this->im);
2750 }
2751
2752 /**
2753 * Returns Image Tag for input image information array.
2754 *
2755 * @param array Image information array, key 0/1 is width/height and key 3 is the src value
2756 * @return string Image tag for the input image information array.
2757 */
2758 function imgTag ($imgInfo) {
2759 return '<img src="'.$imgInfo[3].'" width="'.$imgInfo[0].'" height="'.$imgInfo[1].'" border="0" alt="" />';
2760 }
2761
2762 /**
2763 * Writes the input GDlib image pointer to file
2764 *
2765 * @param pointer The GDlib image resource pointer
2766 * @param string The filename to write to
2767 * @return mixed The output of either imageGif, imagePng or imageJpeg based on the filename to write
2768 * @see maskImageOntoImage(), scale(), output()
2769 */
2770 function ImageWrite($destImg, $theImage) {
2771 imageinterlace ($destImg,0);
2772 $ext = strtolower(substr($theImage, strrpos($theImage, '.')+1));
2773 switch ($ext) {
2774 case 'jpg':
2775 case 'jpeg':
2776 if (function_exists('imageJpeg')) {
2777 return imageJpeg($destImg, $theImage, $this->jpegQuality);
2778 }
2779 break;
2780 case 'gif':
2781 if (function_exists('imageGif')) {
2782 if ($this->truecolor) {
2783 imagetruecolortopalette($destImg, true, 256);
2784 }
2785 return imageGif($destImg, $theImage);
2786 }
2787 break;
2788 case 'png':
2789 if (function_exists('imagePng')) {
2790 return ImagePng($destImg, $theImage);
2791 }
2792 break;
2793 }
2794 return false; // Extension invalid or write-function does not exist
2795 }
2796
2797
2798
2799 /**
2800 * Writes the input GDlib image pointer to file. Now just a wrapper to ImageWrite.
2801 *
2802 * @param pointer The GDlib image resource pointer
2803 * @param string The filename to write to
2804 * @return mixed The output of either imageGif, imagePng or imageJpeg based on the filename to write
2805 * @see imageWrite()
2806 * @deprecated
2807 */
2808 function imageGif($destImg, $theImage) {
2809 return $this->imageWrite($destImg, $theImage);
2810 }
2811
2812 /**
2813 * This function has been renamed and only exists for providing backwards compatibility.
2814 * Please use $this->imageCreateFromFile() instead.
2815 *
2816 * @param string Image filename
2817 * @return pointer Image Resource pointer
2818 * @deprecated
2819 */
2820 function imageCreateFromGif($sourceImg) {
2821 return $this->imageCreateFromFile($sourceImg);
2822 }
2823
2824 /**
2825 * Creates a new GDlib image resource based on the input image filename.
2826 * 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.
2827 *
2828 * @param string Image filename
2829 * @return pointer Image Resource pointer
2830 */
2831 function imageCreateFromFile($sourceImg) {
2832 $imgInf = pathinfo($sourceImg);
2833 $ext = strtolower($imgInf['extension']);
2834
2835 switch ($ext) {
2836 case 'gif':
2837 if (function_exists('imagecreatefromgif')) {
2838 return imageCreateFromGif($sourceImg);
2839 }
2840 break;
2841 case 'png':
2842 if (function_exists('imagecreatefrompng')) {
2843 return imageCreateFromPng($sourceImg);
2844 }
2845 break;
2846 case 'jpg':
2847 case 'jpeg':
2848 if (function_exists('imagecreatefromjpeg')) {
2849 return imageCreateFromJpeg($sourceImg);
2850 }
2851 break;
2852 }
2853
2854 // If non of the above:
2855 $i = @getimagesize($sourceImg);
2856 $im = $this->imagecreate($i[0],$i[1]);
2857 $Bcolor = ImageColorAllocate($im, 128,128,128);
2858 ImageFilledRectangle($im, 0, 0, $i[0], $i[1], $Bcolor);
2859 return $im;
2860 }
2861
2862
2863 /**
2864 * Creates a new GD image resource. Wrapper for imagecreate(truecolor) depended if GD2 is used.
2865 *
2866 * @param integer Width of image
2867 * @param integer Height of image
2868 * @return pointer Image Resource pointer
2869 */
2870 function imagecreate($w, $h) {
2871 if($this->truecolor && function_exists('imagecreatetruecolor')) {
2872 return imagecreatetruecolor($w, $h);
2873 } else {
2874 return imagecreate($w, $h);
2875 }
2876
2877 }
2878
2879 /**
2880 * Returns the HEX color value for an RGB color array
2881 *
2882 * @param array RGB color array
2883 * @return string HEX color value
2884 */
2885 function hexColor($col) {
2886 $r = dechex($col[0]);
2887 if (strlen($r)<2) { $r = '0'.$r; }
2888 $g = dechex($col[1]);
2889 if (strlen($g)<2) { $g = '0'.$g; }
2890 $b = dechex($col[2]);
2891 if (strlen($b)<2) { $b = '0'.$b; }
2892 return '#'.$r.$g.$b;
2893 }
2894
2895 /**
2896 * Unifies all colors given in the colArr color array to the first color in the array.
2897 *
2898 * @param pointer Image resource
2899 * @param array Array containing RGB color arrays
2900 * @param [type] $closest: ...
2901 * @return integer The index of the unified color
2902 */
2903 function unifyColors(&$img, $colArr, $closest = false) {
2904 $retCol = -1;
2905 if (is_array($colArr) && count($colArr) && function_exists('imagepng') && function_exists('imagecreatefrompng')) {
2906 $firstCol = array_shift($colArr);
2907 $firstColArr = $this->convertColor($firstCol);
2908 if (count($colArr)>1) {
2909 $origName = $preName = $this->randomName().'.png';
2910 $postName = $this->randomName().'.png';
2911 $this->imageWrite($img, $preName);
2912 $firstCol = $this->hexColor($firstColArr);
2913 foreach ($colArr as $transparentColor) {
2914 $transparentColor = $this->convertColor($transparentColor);
2915 $transparentColor = $this->hexColor($transparentColor);
2916 $cmd = '-fill "'.$firstCol.'" -opaque "'.$transparentColor.'"';
2917 $this->imageMagickExec($preName, $postName, $cmd);
2918 $preName = $postName;
2919 }
2920 $this->imageMagickExec($postName, $origName, '');
2921 if (@is_file($origName)) {
2922 $tmpImg = $this->imageCreateFromFile($origName);
2923 }
2924 } else {
2925 $tmpImg = $img;
2926 }
2927 if ($tmpImg) {
2928 $img = $tmpImg;
2929 if ($closest) {
2930 $retCol = ImageColorClosest ($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2931 } else {
2932 $retCol = ImageColorExact ($img, $firstColArr[0], $firstColArr[1], $firstColArr[2]);
2933 }
2934 }
2935 // unlink files from process
2936 if (!$this->dontUnlinkTempFiles) {
2937 if ($origName) {
2938 @unlink($origName);
2939 }
2940 if ($postName) {
2941 @unlink($postName);
2942 }
2943 }
2944 }
2945 return $retCol;
2946 }
2947
2948
2949 }
2950
2951 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS'