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