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