Done various changes.
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_stdgraphic.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2003 Kasper Skaarhoj (kasper@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 <kasper@typo3.com>
34 */
35 /**
36 * [CLASS/FUNCTION INDEX of SCRIPT]
37 *
38 *
39 *
40 * 141: class t3lib_stdGraphic
41 * 216: function init()
42 *
43 * SECTION: Layering images / "IMAGE" GIFBUILDER object
44 * 315: function maskImageOntoImage(&$im,$conf,$workArea)
45 * 375: function copyImageOntoImage(&$im,$conf,$workArea)
46 * 397: function copyGifOntoGif(&$im,$cpImg,$conf,$workArea)
47 * 476: function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h)
48 *
49 * SECTION: Text / "TEXT" GIFBUILDER object
50 * 525: function makeText(&$im,$conf,$workArea)
51 * 641: function txtPosition($conf,$workArea,$BB)
52 * 695: function calcBBox($conf)
53 * 764: function addToMap($cords,$conf)
54 * 779: function calcTextCordsForMap($cords,$offset, $conf)
55 * 812: function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing)
56 * 845: function fontResize($conf)
57 *
58 * SECTION: Other GIFBUILDER objects related to TEXT
59 * 907: function makeOutline(&$im,$conf,$workArea,$txtConf)
60 * 936: function circleOffset($distance, $iterations)
61 * 960: function makeEmboss(&$im,$conf,$workArea,$txtConf)
62 * 982: function makeShadow(&$im,$conf,$workArea,$txtConf)
63 *
64 * SECTION: Other GIFBUILDER objects
65 * 1112: function makeBox(&$im,$conf,$workArea)
66 * 1131: function makeEffect(&$im, $conf)
67 * 1146: function IMparams($setup)
68 * 1229: function adjust(&$im, $conf)
69 * 1261: function crop(&$im,$conf)
70 * 1291: function scale(&$im,$conf)
71 * 1323: function setWorkArea($workArea)
72 *
73 * SECTION: Adjustment functions
74 * 1364: function autolevels(&$im)
75 * 1395: function outputLevels(&$im,$low,$high,$swap='')
76 * 1427: function inputLevels(&$im,$low,$high,$swap='')
77 * 1458: function reduceColors(&$im,$limit, $cols)
78 *
79 * SECTION: GIFBUILDER Helper functions
80 * 1496: function prependAbsolutePath($fontFile)
81 * 1510: function v5_sharpen($factor)
82 * 1529: function v5_blur($factor)
83 * 1546: function randomName()
84 * 1558: function applyOffset($cords,$OFFSET)
85 * 1571: function convertColor($string)
86 * 1621: function recodeString($string)
87 * 1642: function singleChars($theText)
88 * 1665: function objPosition($conf,$workArea,$BB)
89 *
90 * SECTION: Scaling, Dimensions of images
91 * 1744: function imageMagickConvert($imagefile,$newExt='',$w='',$h='',$params='',$frame='',$options='',$mustCreate=0)
92 * 1827: function getImageDimensions($imagefile)
93 * 1849: function getImageScale($info,$w,$h,$options)
94 * 1937: function file_exists_typo3temp_file($output,$orig='')
95 *
96 * SECTION: ImageMagick API functions
97 * 1994: function imageMagickIdentify($imagefile)
98 * 2027: function imageMagickExec($input,$output,$params)
99 * 2045: function combineExec($input,$overlay,$mask,$output)
100 * 2060: function wrapFileName($inputName)
101 *
102 * SECTION: Various IO functions
103 * 2101: function checkFile($file)
104 * 2116: function applyImageMagickToPHPGif(&$im, $command)
105 * 2142: function gif_or_jpg($type,$w,$h)
106 * 2159: function output($file)
107 * 2203: function destroy()
108 * 2213: function imgTag ($imgInfo)
109 * 2225: function ImageGif($destImg, $theImage)
110 * 2242: function imageCreateFromGif($sourceImg)
111 *
112 * TOTAL FUNCTIONS: 52
113 * (This index is automatically created/updated by the extension "extdeveval")
114 *
115 */
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 /**
133 * Class contains a bunch of cool functions for manipulating graphics with GDlib/Freetype and ImageMagick
134 * VERY OFTEN used with gifbuilder that extends this class and provides a TypoScript API to using these functions
135 *
136 * @author Kasper Skaarhoj <kasper@typo3.com>
137 * @package TYPO3
138 * @subpackage t3lib
139 * @see tslib_gifBuilder
140 */
141 class t3lib_stdGraphic {
142
143 // Internal configuration, set in init()
144 var $combineScript = 'combine'; // The ImageMagick filename used for combining two images. This name changed during the versions.
145 var $noFramePrepended=0; // If set, there is no frame pointer prepended to the filenames.
146 var $GD2=0; // Set, if the GDlib used is version 2.
147 var $gifExtension = 'gif'; // This should be changed to 'png' if you want this class to read/make PNG-files instead!
148 var $TTFLocaleConv = ''; // Used to recode input to TTF-functions for other charsets.
149 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.
150 var $imageMagickPath = ''; // path to imageMagick, eg: /usr/lib/
151 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!
152 var $webImageExt = 'gif,jpg,jpeg,png'; // Commalist of web image extensions (can be shown by a webbrowser)
153 var $maskNegate = ''; // Will be ' -negate' if ImageMagick ver 5.2+. See init();
154 var $NO_IM_EFFECTS = '';
155 var $cmds = Array (
156 'jpg' => '-colorspace RGB -sharpen 50 -quality 60',
157 'jpeg' => '-colorspace RGB -sharpen 50 -quality 60',
158 'gif' => '-colors 64',
159 'png' => '-colors 64'
160 );
161 var $NO_IMAGE_MAGICK = '';
162 var $V5_EFFECTS = 0;
163 var $mayScaleUp = 1;
164
165 // Variables for testing, alternative usage etc.
166 var $filenamePrefix=''; // Filename prefix for images scaled in imageMagickConvert()
167 var $imageMagickConvert_forceFileNameBody=''; // Forcing the output filename of imageMagickConvert() to this value. However after calling imageMagickConvert() it will be set blank again.
168 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.
169 var $dontCompress=0; // Prevents imageMagickConvert() from compressing the gif-files with t3lib_div::gif_compress()
170 var $dontUnlinkTempFiles=0; // For debugging ONLY!
171 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...
172
173 // Internal:
174 var $IM_commands = Array(); // All ImageMagick commands executed is stored in this array for tracking. Used by the Install Tools Image section
175 var $workArea = Array();
176
177 // Constants:
178 var $tempPath = 'typo3temp/'; // The temp-directory where to store the files. Relative to PATH_site.
179 var $scalecmd = '-geometry'; // ImageMagick scaling command; "-geometry" eller "-sample". Used in makeText() and imageMagickConvert()
180 var $im5fx_blurSteps='1x2,2x2,3x2,4x3,5x3,5x4,6x4,7x5,8x5,9x5'; // Used by v5_blur() to simulate 10 continuous steps of blurring
181 var $im5fx_sharpenSteps='1x2,2x2,3x2,2x3,3x3,4x3,3x4,4x4,4x5,5x5'; // Used by v5_sharpen() to simulate 10 continuous steps of sharpening.
182 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
183 var $colMap = Array ( // Array mapping HTML color names to RGB values.
184 'aqua' => Array(0,255,255),
185 'black' => Array(0,0,0),
186 'blue' => Array(0,0,255),
187 'fuchsia' => Array(255,0,255),
188 'gray' => Array(128,128,128),
189 'green' => Array(0,128,0),
190 'lime' => Array(0,255,0),
191 'maroon' => Array(128,0,0),
192 'navy' => Array(0,0,128),
193 'olive' => Array(128,128,0),
194 'purple' => Array(128,0,128),
195 'red' => Array(255,0,0),
196 'silver' => Array(192,192,192),
197 'teal' => Array(0,128,128),
198 'yellow' => Array(255,255,0),
199 'white' => Array(255,255,255)
200 );
201
202 // Charset conversion object:
203 var $csConvObj;
204 var $nativeCharset=''; // Is set to the native character set of the input strings.
205
206
207
208
209
210 /**
211 * Init function. Must always call this when using the class.
212 * This function will read the configuration information from $GLOBALS['TYPO3_CONF_VARS']['GFX'] can set some values in internal variables.
213 *
214 * @return void
215 */
216 function init() {
217 $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
218
219 if ($gfxConf['im_combine_filename']) $this->combineScript=$gfxConf['im_combine_filename'];
220 if ($gfxConf['im_noFramePrepended']) $this->noFramePrepended=1;
221
222 if ($gfxConf['gdlib_2']) {
223 $this->GD2=1;
224 }
225 if ($gfxConf['gdlib_png']) {
226 $this->gifExtension='png';
227 }
228 if ($gfxConf['TTFLocaleConv']) {
229 $this->TTFLocaleConv = $gfxConf['TTFLocaleConv'];
230 }
231 if ($gfxConf['enable_typo3temp_db_tracking']) {
232 $this->enable_typo3temp_db_tracking = $gfxConf['enable_typo3temp_db_tracking'];
233 }
234
235 $this->imageMagickPath = $gfxConf['im_path'];
236 $this->imageFileExt = $gfxConf['imagefile_ext'];
237
238 // This should be set if ImageMagick ver. 5+ is used.
239 if ($gfxConf['im_negate_mask']) {
240 // Boolean. Indicates if the mask images should be inverted first.
241 // This depends of the ImageMagick version. Below ver. 5.1 this should be false.
242 // Above ImageMagick version 5.2+ it should be true.
243 // Just set the flag if the masks works opposite the intension!
244 $this->maskNegate = ' -negate';
245 }
246 if ($gfxConf['im_no_effects']) {
247 // Boolean. This is necessary if using ImageMagick 5+.
248 // Approved version for using effects is version 4.2.9.
249 // Effects in Imagemagick 5+ tends to render very slowly!!
250 // - therefore must be disabled in order not to perform sharpen, blurring and such.
251 $this->NO_IM_EFFECTS = 1;
252
253 $this->cmds['jpg'] = '-colorspace RGB -quality 60';
254 $this->cmds['jpeg'] = '-colorspace RGB -quality 60';
255 }
256 // ... but if 'im_v5effects' is set, dont care about 'im_no_effects'
257 if ($gfxConf['im_v5effects']) {
258 $this->NO_IM_EFFECTS = 0;
259 $this->V5_EFFECTS = 1;
260
261 if ($gfxConf['im_v5effects']>0) {
262 $this->cmds['jpg'] = '-colorspace RGB -quality 60'.$this->v5_sharpen(10);
263 $this->cmds['jpeg'] = '-colorspace RGB -quality 60'.$this->v5_sharpen(10);
264 }
265 }
266
267 if (!$gfxConf['im']) {
268 $this->NO_IMAGE_MAGICK = 1;
269 }
270 // Secures that images are not scaled up.
271 if ($gfxConf['im_noScaleUp']) {
272 $this->mayScaleUp=0;
273 }
274
275 if (TYPO3_MODE=='FE') {
276 $this->csConvObj = &$GLOBALS['TSFE']->csConvObj;
277 } else { // BE assumed:
278 $this->csConvObj = &$GLOBALS['LANG']->csConvObj;
279 }
280 $this->nativeCharset = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'];
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 /*************************************************
299 *
300 * Layering images / "IMAGE" GIFBUILDER object
301 *
302 *************************************************/
303
304 /**
305 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is true.
306 * 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
307 * The operation involves ImageMagick for combining.
308 *
309 * @param pointer GDlib image pointer
310 * @param array TypoScript array with configuration for the GIFBUILDER object.
311 * @param array The current working area coordinates.
312 * @return void
313 * @see tslib_gifBuilder::make()
314 */
315 function maskImageOntoImage(&$im,$conf,$workArea) {
316 if ($conf['file'] && $conf['mask']) {
317 $BBimage = $this->imageMagickConvert($conf['file'],$this->gifExtension,'','','','','');
318 $BBmask = $this->imageMagickConvert($conf['mask'],$this->gifExtension,'','','','','');
319 if ($BBimage && $BBmask) {
320 $w = imagesx($im);
321 $h = imagesy($im);
322 $tmpStr = $this->randomName();
323 $theImage = $tmpStr.'_img.'.$this->gifExtension;
324 $theDest = $tmpStr.'_dest.'.$this->gifExtension;
325 $theMask = $tmpStr.'_mask.'.$this->gifExtension;
326 $theMask2 = $tmpStr.'_mask2.'.trim($GLOBALS['TYPO3_CONF_VARS']['GFX']['im_mask_temp_ext_noloss']);
327 // prepare overlay image
328 $cpImg = $this->imageCreateFromGif($BBimage[3]);
329 $destImg = imagecreate($w,$h);
330 ImageColorAllocate($destImg, 0,0,0);
331 $this->copyGifOntoGif($destImg,$cpImg,$conf,$workArea);
332 $this->ImageGif($destImg, $theImage);
333 imageDestroy($cpImg);
334 imageDestroy($destImg);
335 // prepare mask image
336 $cpImg = $this->imageCreateFromGif($BBmask[3]);
337 $destImg = imagecreate($w,$h);
338 ImageColorAllocate($destImg, 0,0,0);
339 $this->copyGifOntoGif($destImg,$cpImg,$conf,$workArea);
340 $this->ImageGif($destImg, $theMask);
341 imageDestroy($cpImg);
342 imageDestroy($destImg);
343 // treat the mask
344 $this->imageMagickExec($theMask,$theMask2,'-colorspace GRAY'.$this->maskNegate);
345 // mask the images
346 $this->ImageGif($im, $theDest);
347
348 $this->combineExec($theDest,$theImage,$theMask2,$theDest);
349
350 $backIm = $this->imageCreateFromGif($theDest); // The main image is loaded again...
351 if ($backIm) { // ... and if nothing went wrong we load it onto the old one.
352 ImageColorTransparent($backIm,-1);
353 $im = $backIm;
354 }
355 // unlink files from process
356 if (!$this->dontUnlinkTempFiles) {
357 unlink($theDest);
358 unlink($theImage);
359 unlink($theMask);
360 unlink($theMask2);
361 }
362 }
363 }
364 }
365
366 /**
367 * Implements the "IMAGE" GIFBUILDER object, when the "mask" property is false (using only $conf['file'])
368 *
369 * @param pointer GDlib image pointer
370 * @param array TypoScript array with configuration for the GIFBUILDER object.
371 * @param array The current working area coordinates.
372 * @return void
373 * @see tslib_gifBuilder::make(), maskImageOntoImage()
374 */
375 function copyImageOntoImage(&$im,$conf,$workArea) {
376 if ($conf['file']) {
377 if ($conf['BBOX'][2]!=$this->gifExtension) {
378 $conf['BBOX']=$this->imageMagickConvert($conf['BBOX'][3],$this->gifExtension,'','','','','');
379 $conf['file']=$conf['BBOX'][3];
380 }
381 $cpImg = $this->imageCreateFromGif($conf['file']);
382 $this->copyGifOntoGif($im,$cpImg,$conf,$workArea);
383 imageDestroy($cpImg);
384 }
385 }
386
387 /**
388 * Copies two GDlib image pointers onto each other, using TypoScript configuration from $conf and the input $workArea definition.
389 *
390 * @param pointer GDlib image pointer, destination (bottom image)
391 * @param pointer GDlib image pointer, source (top image)
392 * @param array TypoScript array with the properties for the IMAGE GIFBUILDER object. Only used for the "tile" property value.
393 * @param array Work area
394 * @return void Works on the $im image pointer
395 * @access private
396 */
397 function copyGifOntoGif(&$im,$cpImg,$conf,$workArea) {
398 $cpW = imagesx($cpImg);
399 $cpH = imagesy($cpImg);
400 $tile = t3lib_div::intExplode(',',$conf['tile']);
401 $tile[0] = t3lib_div::intInRange($tile[0],1,20);
402 $tile[1] = t3lib_div::intInRange($tile[1],1,20);
403 $cpOff = $this->objPosition($conf,$workArea,Array($cpW*$tile[0],$cpH*$tile[1]));
404
405 for ($xt=0;$xt<$tile[0];$xt++) {
406 $Xstart=$cpOff[0]+$cpW*$xt;
407 if ($Xstart+$cpW > $workArea[0]) { // if this image is inside of the workArea, then go on
408 // X:
409 if ($Xstart < $workArea[0]) {
410 $cpImgCutX = $workArea[0]-$Xstart;
411 $Xstart = $workArea[0];
412 } else {
413 $cpImgCutX = 0;
414 }
415 $w = $cpW-$cpImgCutX;
416 if ($Xstart > $workArea[0]+$workArea[2]-$w) {
417 $w = $workArea[0]+$workArea[2]-$Xstart;
418 }
419 if ($Xstart < $workArea[0]+$workArea[2]) { // if this image is inside of the workArea, then go on
420 // Y:
421 for ($yt=0;$yt<$tile[1];$yt++) {
422 $Ystart=$cpOff[1]+$cpH*$yt;
423 if ($Ystart+$cpH > $workArea[1]) { // if this image is inside of the workArea, then go on
424 if ($Ystart < $workArea[1]) {
425 $cpImgCutY = $workArea[1]-$Ystart;
426 $Ystart = $workArea[1];
427 } else {
428 $cpImgCutY = 0;
429 }
430 $h = $cpH-$cpImgCutY;
431 if ($Ystart > $workArea[1]+$workArea[3]-$h) {
432 $h = $workArea[1]+$workArea[3]-$Ystart;
433 }
434 if ($Ystart < $workArea[1]+$workArea[3]) { // if this image is inside of the workArea, then go on
435 $this->imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h);
436 }
437 }
438 } // Y:
439 }
440 }
441 }
442 }
443
444 /**
445 * Alternative function for using the similat PHP function imagecopyresized(). Used for GD2 only.
446 *
447 * OK, the reason for this stupid fix is the following story:
448 * GD1.x was capable of copying two images together and combining their palettes! GD2 is apparently not.
449 * With GD2 only the palette of the dest-image is used which mostly results in totally black images when trying to
450 * copy a color-ful image onto the destination.
451 * The GD2-fix is to
452 * 1) Create a blank TRUE-COLOR image
453 * 2) Copy the destination image onto that one
454 * 3) Then do the actual operation; Copying the source (top image) onto that
455 * 4) ... and return the result pointer.
456 * 5) Reduce colors (if we do not, the result may become strange!)
457 * It works, but the resulting images is now a true-color PNG which may be very large.
458 * So, why not use 'imagetruecolortopalette ($im, TRUE, 256)' - well because it does NOT WORK! So simple is that.
459 *
460 * For parameters, see PHP function "imagecopyresized()"
461 *
462 * @param pointer see PHP function "imagecopyresized()"
463 * @param pointer see PHP function "imagecopyresized()"
464 * @param integer see PHP function "imagecopyresized()"
465 * @param integer see PHP function "imagecopyresized()"
466 * @param integer see PHP function "imagecopyresized()"
467 * @param integer see PHP function "imagecopyresized()"
468 * @param integer see PHP function "imagecopyresized()"
469 * @param integer see PHP function "imagecopyresized()"
470 * @param integer see PHP function "imagecopyresized()"
471 * @param integer see PHP function "imagecopyresized()"
472 * @return void
473 * @access private
474 * @see t3lib_iconWorks::imagecopyresized()
475 */
476 function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) {
477 if ($this->GD2) {
478 $im_base = imagecreatetruecolor(imagesx($im), imagesy($im)); // Make true color image
479 imagecopyresized($im_base, $im, 0,0,0,0, imagesx($im),imagesy($im),imagesx($im),imagesy($im)); // Copy the source image onto that
480 imagecopyresized($im_base, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h); // Then copy the $cpImg onto that (the actual operation!)
481 $im = $im_base; // Set pointer
482 $this->makeEffect($im, Array('value'=>'colors=256')); // Reduce colors to 256 - make SURE that IM is working then!
483 } else {
484 imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h);
485 }
486 }
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510 /********************************
511 *
512 * Text / "TEXT" GIFBUILDER object
513 *
514 ********************************/
515
516 /**
517 * Implements the "TEXT" GIFBUILDER object
518 *
519 * @param pointer GDlib image pointer
520 * @param array TypoScript array with configuration for the GIFBUILDER object.
521 * @param array The current working area coordinates.
522 * @return void
523 * @see tslib_gifBuilder::make()
524 */
525 function makeText(&$im,$conf,$workArea) {
526 // Spacing
527 $spacing = intval($conf['spacing']);
528 $wordSpacing = intval($conf['wordSpacing']);
529 $wordSpacing = $wordSpacing?$wordSpacing:$spacing*2;
530 // Position
531 $txtPos = $this->txtPosition($conf,$workArea,$conf['BBOX']);
532 $theText = $this->recodeString($conf['text']);
533
534 if ($conf['imgMap'] && is_array($conf['imgMap.'])) {
535 $this->addToMap($this->calcTextCordsForMap($conf['BBOX'][2],$txtPos, $conf['imgMap.']), $conf['imgMap.']);
536 }
537 if (!$conf['hideButCreateMap']) {
538 // Font Color:
539 $cols=$this->convertColor($conf['fontColor']);
540 // NiceText is calculated
541 if (!$conf['niceText']) {
542 // Font Color is reserved:
543 $this->reduceColors($im,256, 200);
544 $Fcolor = ImageColorAllocate($im, $cols[0],$cols[1],$cols[2]);
545 // antiAliasing is setup:
546 $Fcolor = ($conf['antiAlias']) ? $Fcolor : -$Fcolor;
547
548 for ($a=0; $a<$conf['iterations']; $a++) {
549 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function:
550 $this->SpacedImageTTFText($im, $conf['fontSize'], $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, $spacing, $wordSpacing);
551 } else {
552 ImageTTFText($im, t3lib_div::freetypeDpiComp($conf['fontSize']), $conf['angle'], $txtPos[0], $txtPos[1], $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText);
553 }
554 }
555 } else { // NICETEXT::
556 // options anti_aliased and iterations is NOT available when doing this!!
557 $w = imagesx($im);
558 $h = imagesy($im);
559 $tmpStr = $this->randomName();
560
561 $fileMenu = $tmpStr.'_menuNT.'.$this->gifExtension;
562 $fileColor = $tmpStr.'_colorNT.'.$this->gifExtension;
563 $fileMask = $tmpStr.'_maskNT.'.$this->gifExtension;
564 // Scalefactor
565 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'],2,5);
566 $newW = ceil($sF*imagesx($im));
567 $newH = ceil($sF*imagesy($im));
568
569 // Make mask
570 $maskImg = imagecreate($newW, $newH);
571 ImageColorAllocate($maskImg, 255,255,255);
572 $Fcolor = ImageColorAllocate($maskImg, 0,0,0);
573 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function:
574 $this->SpacedImageTTFText($maskImg, ceil($sF*$conf['fontSize']), $conf['angle'], ceil($sF*$txtPos[0]), ceil($sF*$txtPos[1]), $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText, ceil($sF*$spacing), ceil($sF*$wordSpacing));
575 } else {
576 ImageTTFText($maskImg, t3lib_div::freetypeDpiComp(ceil($sF*$conf['fontSize'])), $conf['angle'], ceil($sF*$txtPos[0]), ceil($sF*$txtPos[1]), $Fcolor, t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText);
577 }
578 $this->ImageGif($maskImg, $fileMask);
579 ImageDestroy($maskImg);
580
581 // Downscales the mask
582 if ($this->NO_IM_EFFECTS) {
583 if ($this->maskNegate) {
584 $command = trim($this->scalecmd.' '.$w.'x'.$h.'!'); // Negate 2 times makes no negate...
585 } else {
586 $command = trim($this->scalecmd.' '.$w.'x'.$h.'! -negate');
587 }
588 } else {
589 if ($this->maskNegate) {
590 $command = trim($conf['niceText.']['before'].' '.$this->scalecmd.' '.$w.'x'.$h.'! '.$conf['niceText.']['after']);
591 } else {
592 $command = trim($conf['niceText.']['before'].' '.$this->scalecmd.' '.$w.'x'.$h.'! '.$conf['niceText.']['after'].' -negate');
593 }
594 if ($conf['niceText.']['sharpen']) {
595 if ($this->V5_EFFECTS) {
596 $command.=$this->v5_sharpen($conf['niceText.']['sharpen']);
597 } else {
598 $command.=' -sharpen '.t3lib_div::intInRange($conf['niceText.']['sharpen'],1,99);
599 }
600 }
601 }
602 $this->imageMagickExec($fileMask,$fileMask,$command);
603
604 // Make the color-file
605 $colorImg = imagecreate($w,$h);
606 ImageColorAllocate($colorImg, $cols[0],$cols[1],$cols[2]);
607 $this->ImageGif($colorImg, $fileColor);
608 ImageDestroy($colorImg);
609
610 // The mask is applied
611 $this->ImageGif($im, $fileMenu); // The main pictures is saved temporarily
612
613 $this->combineExec($fileMenu,$fileColor,$fileMask,$fileMenu);
614
615 $backIm = $this->imageCreateFromGif($fileMenu); // The main image is loaded again...
616 if ($backIm) { // ... and if nothing went wrong we load it onto the old one.
617 ImageColorTransparent($backIm,-1);
618 $im = $backIm;
619 }
620
621 // Deleting temporary files;
622 if (!$this->dontUnlinkTempFiles) {
623 unlink($fileMenu);
624 unlink($fileColor);
625 unlink($fileMask);
626 }
627 }
628 }
629 }
630
631 /**
632 * Calculates text position for printing the text onto the image based on configuration like alignment and workarea.
633 *
634 * @param array TypoScript array for the TEXT GIFBUILDER object
635 * @param array Workarea definition
636 * @param array Bounding box information, was set in tslib_gifBuilder::start()
637 * @return array [0]=x, [1]=y, [2]=w, [3]=h
638 * @access private
639 * @see makeText()
640 */
641 function txtPosition($conf,$workArea,$BB) {
642 $bbox = $BB[2];
643 $angle=intval($conf['angle'])/180*pi();
644 $conf['angle']=0;
645 $straightBB = $this->calcBBox($conf);
646
647 // offset, align, valign, workarea
648 $result=Array(); // [0]=x, [1]=y, [2]=w, [3]=h
649 $result[2] = $BB[0];
650 $result[3] = $BB[1];
651 $w=$workArea[2];
652 $h=$workArea[3];
653
654 switch($conf['align']) {
655 case 'right':
656 case 'center':
657 $factor=abs(cos($angle));
658 $sign=(cos($angle)<0)?-1:1;
659 $len1 = $sign*$factor*$straightBB[0];
660 $len2= $sign*$BB[0];
661 $result[0] = $w-ceil($len2*$factor+(1-$factor)*$len1);
662
663 $factor=abs(sin($angle));
664 $sign=(sin($angle)<0)?-1:1;
665 $len1= $sign*$factor*$straightBB[0];
666 $len2= $sign*$BB[1];
667 $result[1]=ceil($len2*$factor+(1-$factor)*$len1);
668 break;
669 }
670 switch($conf['align']) {
671 case 'right':
672 break;
673 case 'center':
674 $result[0] = round(($result[0])/2);
675 $result[1] = round(($result[1])/2);
676 break;
677 default:
678 $result[0]=0;
679 $result[1]=0;
680 break;
681 }
682 $result = $this->applyOffset($result,t3lib_div::intExplode(',',$conf['offset']));
683 $result = $this->applyOffset($result,$workArea);
684 return $result;
685 }
686
687 /**
688 * Calculates bounding box information for the TEXT GIFBUILDER object.
689 *
690 * @param array TypoScript array for the TEXT GIFBUILDER object
691 * @return array Array with three keys [0]/[1] being x/y and [2] being the bounding box array
692 * @access private
693 * @see txtPosition(), tslib_gifBuilder::start()
694 */
695 function calcBBox($conf) {
696 if (!$conf['niceText']) {
697 $sF = 1;
698 } else { // NICETEXT::
699 $sF = t3lib_div::intInRange($conf['niceText.']['scaleFactor'],2,5);
700 }
701
702 $spacing = intval($conf['spacing']);
703 $wordSpacing = intval($conf['wordSpacing']);
704 $wordSpacing = $wordSpacing?$wordSpacing:$spacing*2;
705
706 $spacing*=$sF;
707 $wordSpacing*=$sF;
708 $theText = $this->recodeString($conf['text']);
709
710 $charInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF*$conf['fontSize']), $conf['angle'], t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $theText);
711 $theBBoxInfo = $charInf;
712 if ($conf['angle']) {
713 $xArr = Array($charInf[0],$charInf[2],$charInf[4],$charInf[6]);
714 $yArr = Array($charInf[1],$charInf[3],$charInf[5],$charInf[7]);
715 $x=max($xArr)-min($xArr);
716 $y=max($yArr)-min($yArr);
717 } else {
718 $x = ($charInf[2]-$charInf[0]);
719 $y = ($charInf[1]-$charInf[7]);
720 }
721 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function:
722 $x=0;
723 if (!$spacing && $wordSpacing) {
724 $bits = explode(' ',$theText);
725 while(list(,$word)=each($bits)) {
726 $word.=' ';
727 $wordInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF*$conf['fontSize']), $conf['angle'], t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $word);
728 $wordW = ($wordInf[2]-$wordInf[0]);
729 $x+=$wordW+$wordSpacing;
730 }
731 } else {
732 $utf8Chars = $this->singleChars($theText);
733 // For each UTF-8 char, do:
734 foreach($utf8Chars as $char) {
735 $charInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($sF*$conf['fontSize']), $conf['angle'], t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $char);
736 $charW = ($charInf[2]-$charInf[0]);
737 $x+=$charW+(($char==' ')?$wordSpacing:$spacing);
738 }
739 }
740 }
741
742 if ($sF>1) {
743 $x = ceil($x/$sF);
744 $y = ceil($y/$sF);
745 if (is_array($theBBoxInfo)) {
746 reset($theBBoxInfo);
747 while(list($key,$val)=each($theBBoxInfo)) {
748 $theBBoxInfo[$key]=ceil($theBBoxInfo[$key]/$sF);
749 }
750 }
751 }
752 return Array($x,$y,$theBBoxInfo);
753 }
754
755 /**
756 * Adds an <area> tag to the internal variable $this->map which is used to accumulate the content for an ImageMap
757 *
758 * @param array Coordinates for a polygon image map as created by ->calcTextCordsForMap()
759 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object.
760 * @return void
761 * @access private
762 * @see makeText(), calcTextCordsForMap()
763 */
764 function addToMap($cords,$conf) {
765 $JS = $conf['noBlur'] ? '' : ' onfocus="blurLink(this);"';
766 $this->map.='<area'.
767 ' shape="poly"'.
768 ' coords="'.implode($cords,',').'"'.
769 ' href="'.htmlspecialchars($conf['url']).'"'.
770 ($conf['target'] ? ' target="'.$conf['target'].'"' : '').
771 $JS.
772 ' alt="" />';
773 }
774
775 /**
776 * Calculating the coordinates for a TEXT string on an image map. Used in an <area> tag
777 *
778 * @param array Coordinates (from BBOX array)
779 * @param array Offset array
780 * @param array Configuration for "imgMap." property of a TEXT GIFBUILDER object.
781 * @return array
782 * @access private
783 * @see makeText(), calcTextCordsForMap()
784 */
785 function calcTextCordsForMap($cords,$offset, $conf) {
786 $pars = t3lib_div::intExplode(',',$conf['explode'].',');
787
788 $newCords[0] = $cords[0]+$offset[0]-$pars[0];
789 $newCords[1] = $cords[1]+$offset[1]+$pars[1];
790 $newCords[2] = $cords[2]+$offset[0]+$pars[0];
791 $newCords[3] = $cords[3]+$offset[1]+$pars[1];
792 $newCords[4] = $cords[4]+$offset[0]+$pars[0];
793 $newCords[5] = $cords[5]+$offset[1]-$pars[1];
794 $newCords[6] = $cords[6]+$offset[0]-$pars[0];
795 $newCords[7] = $cords[7]+$offset[1]-$pars[1];
796
797 return $newCords;
798 }
799
800 /**
801 * Printing text onto an image like the PHP function imageTTFText does but in addition it offers options for spacing of letters and words.
802 * Spacing is done by printing one char at a time and this means that the spacing is rather uneven and probably not very nice.
803 * See
804 *
805 * @param pointer (See argument for PHP function imageTTFtext())
806 * @param integer (See argument for PHP function imageTTFtext())
807 * @param integer (See argument for PHP function imageTTFtext())
808 * @param integer (See argument for PHP function imageTTFtext())
809 * @param integer (See argument for PHP function imageTTFtext())
810 * @param integer (See argument for PHP function imageTTFtext())
811 * @param string (See argument for PHP function imageTTFtext())
812 * @param string (See argument for PHP function imageTTFtext()). UTF-8 string, possibly with entities in.
813 * @param integer The spacing of letters in pixels
814 * @param integer The spacing of words in pixels
815 * @return void
816 * @access private
817 */
818 function SpacedImageTTFText(&$im, $fontSize, $angle, $x, $y, $Fcolor, $fontFile, $text, $spacing, $wordSpacing) {
819 if (!$spacing && $wordSpacing) {
820 $bits = explode(' ',$text);
821 reset($bits);
822 while(list(,$word)=each($bits)) {
823 $word.=' ';
824 $word = $word;
825 $wordInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($fontSize), $angle, t3lib_stdGraphic::prependAbsolutePath($fontFile), $word);
826 $wordW = ($wordInf[2]-$wordInf[0]);
827 ImageTTFText($im, t3lib_div::freetypeDpiComp($fontSize), $angle, $x, $y, $Fcolor, t3lib_stdGraphic::prependAbsolutePath($fontFile), $word);
828 $x+=$wordW+$wordSpacing;
829 }
830 } else {
831 $utf8Chars = $this->singleChars($text);
832 // For each UTF-8 char, do:
833 foreach($utf8Chars as $char) {
834 $charInf = ImageTTFBBox(t3lib_div::freetypeDpiComp($fontSize), $angle, t3lib_stdGraphic::prependAbsolutePath($fontFile), $char);
835 $charW = ($charInf[2]-$charInf[0]);
836 ImageTTFText($im, t3lib_div::freetypeDpiComp($fontSize), $angle, $x, $y, $Fcolor, t3lib_stdGraphic::prependAbsolutePath($fontFile), $char);
837 $x+=$charW+(($char==' ')?$wordSpacing:$spacing);
838 }
839 }
840 }
841
842 /**
843 * Function that finds the right fontsize that will render the textstring within a certain width
844 *
845 * @param array The TypoScript properties of the TEXT GIFBUILDER object
846 * @return integer The new fontSize
847 * @access private
848 * @author Rene Fritz <r.fritz@colorcube.de>
849 * @see tslib_gifBuilder::start()
850 */
851 function fontResize($conf) {
852 // 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!!!!
853 $maxWidth = intval($conf['maxWidth']);
854 if ($maxWidth) {
855 if ($spacing || $wordSpacing) { // If any kind of spacing applys, we use this function:
856 return $conf['fontSize'];
857 // ################ no calc for spacing yet !!!!!!
858 } else {
859 $fontSize = $conf['fontSize'];
860 do {
861 $conf['fontSize'] = $fontSize;
862 // determine bounding box.
863 $bounds = ImageTTFBBox(t3lib_div::freetypeDpiComp($conf['fontSize']), $conf['angle'], t3lib_stdGraphic::prependAbsolutePath($conf['fontFile']), $this->recodeString($conf['text']));
864 if ($conf['angle']< 0) {
865 $pixelWidth = abs($bounds[4]-$bounds[0]);
866 } elseif ($conf['angle'] > 0) {
867 $pixelWidth = abs($bounds[2]-$bounds[6]);
868 } else {
869 $pixelWidth = abs($bounds[4]-$bounds[6]);
870 }
871 // This is a very raw calculation but it makes it in one step
872 $fontSize=(int)($maxWidth*$fontSize/$pixelWidth);
873 if ($fontSize >= $conf['fontSize']) {
874 $fontSize = $conf['fontSize']-1;
875 }
876 } while ($pixelWidth > $maxWidth);
877 }//if spacing
878 }
879 return $conf['fontSize'];
880 }
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897 /*********************************************
898 *
899 * Other GIFBUILDER objects related to TEXT
900 *
901 *********************************************/
902
903 /**
904 * Implements the "OUTLINE" GIFBUILDER object / property for the TEXT object
905 *
906 * @param pointer GDlib image pointer
907 * @param array TypoScript array with configuration for the GIFBUILDER object.
908 * @param array The current working area coordinates.
909 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object.
910 * @return void
911 * @see tslib_gifBuilder::make(), makeText()
912 */
913 function makeOutline(&$im,$conf,$workArea,$txtConf) {
914 $thickness = intval($conf['thickness']);
915 if ($thickness) {
916 $txtConf['fontColor'] = $conf['color'];
917 $outLineDist = t3lib_div::intInRange($thickness,1,2);
918 for ($b=1;$b<=$outLineDist;$b++) {
919 if ($b==1) {
920 $it = 8;
921 } else {
922 $it = 16;
923 }
924 $outL = $this->circleOffset($b, $it);
925 for ($a=0;$a<$it;$a++) {
926 $this->makeText($im,$txtConf,$this->applyOffset($workArea,$outL[$a]));
927 }
928 }
929 }
930 }
931
932 /**
933 * Creates some offset values in an array used to simulate a circularly applied outline around TEXT
934 *
935 * access private
936 *
937 * @param integer Distance
938 * @param integer Iterations.
939 * @return array
940 * @see makeOutline()
941 */
942 function circleOffset($distance, $iterations) {
943 $res = Array();
944 if ($distance && $iterations) {
945 for ($a=0;$a<$iterations;$a++) {
946 $yOff = round(sin(2*pi()/$iterations*($a+1))*100*$distance);
947 if ($yOff) {$yOff = intval(ceil(abs($yOff/100))*($yOff/abs($yOff)));}
948 $xOff = round(cos(2*pi()/$iterations*($a+1))*100*$distance);
949 if ($xOff) {$xOff = intval(ceil(abs($xOff/100))*($xOff/abs($xOff)));}
950 $res[$a] = Array($xOff,$yOff);
951 }
952 }
953 return $res;
954 }
955
956 /**
957 * Implements the "EMBOSS" GIFBUILDER object / property for the TEXT object
958 *
959 * @param pointer GDlib image pointer
960 * @param array TypoScript array with configuration for the GIFBUILDER object.
961 * @param array The current working area coordinates.
962 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object.
963 * @return void
964 * @see tslib_gifBuilder::make(), makeShadow()
965 */
966 function makeEmboss(&$im,$conf,$workArea,$txtConf) {
967 $conf['color']=$conf['highColor'];
968 $this->makeShadow($im,$conf,$workArea,$txtConf);
969 $newOffset = t3lib_div::intExplode(',',$conf['offset']);
970 $newOffset[0]*=-1;
971 $newOffset[1]*=-1;
972 $conf['offset']=implode($newOffset,',');
973 $conf['color']=$conf['lowColor'];
974 $this->makeShadow($im,$conf,$workArea,$txtConf);
975 }
976
977 /**
978 * Implements the "SHADOW" GIFBUILDER object / property for the TEXT object
979 * The operation involves ImageMagick for combining.
980 *
981 * @param pointer GDlib image pointer
982 * @param array TypoScript array with configuration for the GIFBUILDER object.
983 * @param array The current working area coordinates.
984 * @param array TypoScript array with configuration for the associated TEXT GIFBUILDER object.
985 * @return void
986 * @see tslib_gifBuilder::make(), makeText(), makeEmboss()
987 */
988 function makeShadow(&$im,$conf,$workArea,$txtConf) {
989 $workArea = $this->applyOffset($workArea,t3lib_div::intExplode(',',$conf['offset']));
990 $blurRate = t3lib_div::intInRange(intval($conf['blur']),0,99);
991
992 if (!$blurRate || $this->NO_IM_EFFECTS) { // No effects if ImageMagick ver. 5+
993 $txtConf['fontColor'] = $conf['color'];
994 $this->makeText($im,$txtConf,$workArea);
995 } else {
996 $w = imagesx($im);
997 $h = imagesy($im);
998 $blurBorder= 3; // area around the blur used for cropping something
999 $tmpStr = $this->randomName();
1000 $fileMenu = $tmpStr.'_menu.'.$this->gifExtension;
1001 $fileColor = $tmpStr.'_color.'.$this->gifExtension;
1002 $fileMask = $tmpStr.'_mask.'.$this->gifExtension;
1003
1004 // BlurColor Image laves
1005 $blurColImg = imagecreate($w,$h);
1006 $bcols=$this->convertColor($conf['color']);
1007 ImageColorAllocate($blurColImg, $bcols[0],$bcols[1],$bcols[2]);
1008 $this->ImageGif($blurColImg, $fileColor);
1009 ImageDestroy($blurColImg);
1010
1011 // The mask is made: BlurTextImage
1012 $blurTextImg = imagecreate($w+$blurBorder*2,$h+$blurBorder*2);
1013 ImageColorAllocate($blurTextImg, 0,0,0); // black background
1014 $txtConf['fontColor'] = 'white';
1015 $blurBordArr = Array($blurBorder,$blurBorder);
1016 $this->makeText($blurTextImg,$txtConf, $this->applyOffset($workArea,$blurBordArr));
1017 $this->ImageGif($blurTextImg, $fileMask); // dump to temporary file
1018 ImageDestroy($blurTextImg); // destroy
1019
1020
1021 $command='';
1022 $command.=$this->maskNegate;
1023
1024 if ($this->V5_EFFECTS) {
1025 $command.=$this->v5_blur($blurRate+1);
1026 } else {
1027 // Blurring of the mask
1028 $times = ceil($blurRate/10); // How many blur-commands that is executed. Min = 1;
1029 $newBlurRate = $blurRate*4; // Her booster vi blur-rate, så at den allerede ved 25 er på 100. Resten op til 99 går på iterationer af blur-kommandoen
1030 $newBlurRate = t3lib_div::intInRange($newBlurRate,1,99);
1031 for ($a=0;$a<$times;$a++) { // Building blur-command
1032 $command.=' -blur '.$blurRate;
1033 }
1034 }
1035
1036 $this->imageMagickExec($fileMask,$fileMask,$command);
1037
1038 $blurTextImg_tmp = $this->imageCreateFromGif($fileMask); // the mask is loaded again
1039 if ($blurTextImg_tmp) { // if nothing went wrong we continue with the blurred mask
1040
1041 // cropping the border from the mask
1042 $blurTextImg = imagecreate($w,$h);
1043 $this->imagecopyresized($blurTextImg, $blurTextImg_tmp, 0, 0, $blurBorder, $blurBorder, $w, $h, $w, $h);
1044 ImageDestroy($blurTextImg_tmp); // Destroy the temporary mask
1045
1046 // adjust the mask
1047 $intensity = 40;
1048 if ($conf['intensity']) {
1049 $intensity = t3lib_div::intInRange($conf['intensity'],0,100);
1050 }
1051 $intensity = ceil(255-($intensity/100*255));
1052 $this->inputLevels($blurTextImg,0,$intensity,$this->maskNegate);
1053
1054 $opacity = t3lib_div::intInRange(intval($conf['opacity']),0,100);
1055 if ($opacity && $opacity<100) {
1056 $high = ceil(255*$opacity/100);
1057 $this->outputLevels($blurTextImg,0,$high,$this->maskNegate); // reducing levels as the opacity demands
1058 }
1059
1060 $this->ImageGif($blurTextImg, $fileMask); // Dump the mask again
1061 ImageDestroy($blurTextImg); // Destroy the mask
1062
1063 // The pictures are combined
1064 $this->ImageGif($im, $fileMenu); // The main pictures is saved temporarily
1065
1066 $this->combineExec($fileMenu,$fileColor,$fileMask,$fileMenu);
1067
1068 $backIm = $this->imageCreateFromGif($fileMenu); // The main image is loaded again...
1069 if ($backIm) { // ... and if nothing went wrong we load it onto the old one.
1070 ImageColorTransparent($backIm,-1);
1071 $im = $backIm;
1072 }
1073 }
1074 // Deleting temporary files;
1075 if (!$this->dontUnlinkTempFiles) {
1076 unlink($fileMenu);
1077 unlink($fileColor);
1078 unlink($fileMask);
1079 }
1080 }
1081 }
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103 /****************************
1104 *
1105 * Other GIFBUILDER objects
1106 *
1107 ****************************/
1108
1109 /**
1110 * Implements the "BOX" GIFBUILDER object
1111 *
1112 * @param pointer GDlib image pointer
1113 * @param array TypoScript array with configuration for the GIFBUILDER object.
1114 * @param array The current working area coordinates.
1115 * @return void
1116 * @see tslib_gifBuilder::make()
1117 */
1118 function makeBox(&$im,$conf,$workArea) {
1119 $cords = t3lib_div::intExplode(',',$conf['dimensions'].',,,');
1120 $conf['offset']=$cords[0].','.$cords[1];
1121 $cords = $this->objPosition($conf,$workArea,Array($cords[2],$cords[3]));
1122 $cols=$this->convertColor($conf['color']);
1123 $this->reduceColors($im,256, 255);
1124 $tmpColor = ImageColorAllocate($im, $cols[0],$cols[1],$cols[2]);
1125 imagefilledrectangle($im, $cords[0], $cords[1], $cords[0]+$cords[2]-1, $cords[1]+$cords[3]-1, $tmpColor);
1126 }
1127
1128 /**
1129 * Implements the "EFFECT" GIFBUILDER object
1130 * The operation involves ImageMagick for applying effects
1131 *
1132 * @param pointer GDlib image pointer
1133 * @param array TypoScript array with configuration for the GIFBUILDER object.
1134 * @return void
1135 * @see tslib_gifBuilder::make(), applyImageMagickToPHPGif()
1136 */
1137 function makeEffect(&$im, $conf) {
1138 $commands = $this->IMparams($conf['value']);
1139 if ($commands) {
1140 $this->applyImageMagickToPHPGif($im, $commands);
1141 }
1142 }
1143
1144 /**
1145 * Creating ImageMagick paramters from TypoScript property
1146 *
1147 * @param string A string with effect keywords=value pairs separated by "|"
1148 * @return string ImageMagick prepared parameters.
1149 * @access private
1150 * @see makeEffect()
1151 */
1152 function IMparams($setup) {
1153 if (!trim($setup)){return '';}
1154 $effects = explode('|', $setup);
1155 $commands = '';
1156 while(list(,$val)=each($effects)) {
1157 $pairs=explode('=',$val,2);
1158 $value = trim($pairs[1]);
1159 $effect = strtolower(trim($pairs[0]));
1160 switch($effect) {
1161 case 'gamma':
1162 $commands.=' -gamma '.doubleval($value);
1163 break;
1164 case 'blur':
1165 if (!$this->NO_IM_EFFECTS) {
1166 if ($this->V5_EFFECTS) {
1167 $commands.=$this->v5_blur($value);
1168 } else {
1169 $commands.=' -blur '.t3lib_div::intInRange($value,1,99);
1170 }
1171 }
1172 break;
1173 case 'sharpen':
1174 if (!$this->NO_IM_EFFECTS) {
1175 if ($this->V5_EFFECTS) {
1176 $commands.=$this->v5_sharpen($value);
1177 } else {
1178 $commands.=' -sharpen '.t3lib_div::intInRange($value,1,99);
1179 }
1180 }
1181 break;
1182 case 'rotate':
1183 $commands.=' -rotate '.t3lib_div::intInRange($value,0,360);
1184 break;
1185 case 'solarize':
1186 $commands.=' -solarize '.t3lib_div::intInRange($value,0,99);
1187 break;
1188 case 'swirl':
1189 $commands.=' -swirl '.t3lib_div::intInRange($value,0,1000);
1190 break;
1191 case 'wave':
1192 $params = t3lib_div::intExplode(',',$value);
1193 $commands.=' -wave '.t3lib_div::intInRange($params[0],0,99).'x'.t3lib_div::intInRange($params[1],0,99);
1194 break;
1195 case 'charcoal':
1196 $commands.=' -charcoal '.t3lib_div::intInRange($value,0,100);
1197 break;
1198 case 'gray':
1199 $commands.=' -colorspace GRAY';
1200 break;
1201 case 'edge':
1202 $commands.=' -edge '.t3lib_div::intInRange($value,0,99);
1203 break;
1204 case 'emboss':
1205 $commands.=' -emboss';
1206 break;
1207 case 'flip':
1208 $commands.=' -flip';
1209 break;
1210 case 'flop':
1211 $commands.=' -flop';
1212 break;
1213 case 'colors':
1214 $commands.=' -colors '.t3lib_div::intInRange($value,2,255);
1215 break;
1216 case 'shear':
1217 $commands.=' -shear '.t3lib_div::intInRange($value,-90,90);
1218 break;
1219 case 'invert':
1220 $commands.=' -negate';
1221 break;
1222 }
1223 }
1224 return $commands;
1225 }
1226
1227 /**
1228 * Implements the "ADJUST" GIFBUILDER object
1229 *
1230 * @param pointer GDlib image pointer
1231 * @param array TypoScript array with configuration for the GIFBUILDER object.
1232 * @return void
1233 * @see tslib_gifBuilder::make(), autoLevels(), outputLevels(), inputLevels()
1234 */
1235 function adjust(&$im, $conf) {
1236 $setup = $conf['value'];
1237 if (!trim($setup)){return '';}
1238 $effects = explode('|', $setup);
1239 while(list(,$val)=each($effects)) {
1240 $pairs=explode('=',$val,2);
1241 $value = trim($pairs[1]);
1242 $effect = strtolower(trim($pairs[0]));
1243 switch($effect) {
1244 case 'inputlevels': // low,high
1245 $params = t3lib_div::intExplode(',',$value);
1246 $this->inputLevels($im,$params[0],$params[1]);
1247 break;
1248 case 'outputlevels':
1249 $params = t3lib_div::intExplode(',',$value);
1250 $this->outputLevels($im,$params[0],$params[1]);
1251 break;
1252 case 'autolevels':
1253 $this->autoLevels($im);
1254 break;
1255 }
1256 }
1257 }
1258
1259 /**
1260 * Implements the "CROP" GIFBUILDER object
1261 *
1262 * @param pointer GDlib image pointer
1263 * @param array TypoScript array with configuration for the GIFBUILDER object.
1264 * @return void
1265 * @see tslib_gifBuilder::make()
1266 */
1267 function crop(&$im,$conf) {
1268 $this->setWorkArea(''); // clears workArea to total image
1269 $cords = t3lib_div::intExplode(',',$conf['crop'].',,,');
1270 $conf['offset']=$cords[0].','.$cords[1];
1271 $cords = $this->objPosition($conf,$this->workArea,Array($cords[2],$cords[3]));
1272
1273 $newIm = imagecreate($cords[2],$cords[3]);
1274 $cols=$this->convertColor($conf['backColor']?$conf['backColor']:$this->setup['backColor']);
1275 ImageColorAllocate($newIm, $cols[0],$cols[1],$cols[2]);
1276
1277 $newConf = Array();
1278 $workArea = Array(0,0,$cords[2],$cords[3]);
1279 if ($cords[0]<0) {$workArea[0]=abs($cords[0]);} else {$newConf['offset']=-$cords[0];}
1280 if ($cords[1]<0) {$workArea[1]=abs($cords[1]);} else {$newConf['offset'].=','.-$cords[1];}
1281
1282 $this->copyGifOntoGif($newIm,$im,$newConf,$workArea);
1283 $im = $newIm;
1284 $this->w = imagesx($im);
1285 $this->h = imagesy($im);
1286 $this->setWorkArea(''); // clears workArea to total image
1287 }
1288
1289 /**
1290 * Implements the "SCALE" GIFBUILDER object
1291 *
1292 * @param pointer GDlib image pointer
1293 * @param array TypoScript array with configuration for the GIFBUILDER object.
1294 * @return void
1295 * @see tslib_gifBuilder::make()
1296 */
1297 function scale(&$im,$conf) {
1298 if ($conf['width'] || $conf['height'] || $conf['params']) {
1299 $tmpStr = $this->randomName();
1300 $theFile = $tmpStr.'.'.$this->gifExtension;
1301 $this->ImageGif($im, $theFile);
1302 $theNewFile = $this->imageMagickConvert($theFile,$this->gifExtension,$conf['width'],$conf['height'],$conf['params'],'','');
1303 $tmpImg = $this->imageCreateFromGif($theNewFile[3]);
1304 if ($tmpImg) {
1305 ImageDestroy($im);
1306 $im = $tmpImg;
1307 $this->w = imagesx($im);
1308 $this->h = imagesy($im);
1309 $this->setWorkArea(''); // clears workArea to total image
1310 }
1311 if (!$this->dontUnlinkTempFiles) {
1312 unlink($theFile);
1313 if ($theNewFile[3] && $theNewFile[3]!=$theFile) {
1314 unlink($theNewFile[3]);
1315 }
1316 }
1317 }
1318 }
1319
1320 /**
1321 * Implements the "WORKAREA" GIFBUILDER object when setting it
1322 * Setting internal working area boundaries (->workArea)
1323 *
1324 * @param string Working area dimensions, comma separated
1325 * @return void
1326 * @access private
1327 * @see tslib_gifBuilder::make()
1328 */
1329 function setWorkArea($workArea) {
1330 $this->workArea = t3lib_div::intExplode(',',$workArea);
1331 $this->workArea = $this->applyOffset($this->workArea,$this->OFFSET);
1332 if (!$this->workArea[2]) {$this->workArea[2]=$this->w;}
1333 if (!$this->workArea[3]) {$this->workArea[3]=$this->h;}
1334 }
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358 /*************************
1359 *
1360 * Adjustment functions
1361 *
1362 ************************/
1363
1364 /**
1365 * Apply auto-levels to input image pointer
1366 *
1367 * @param integer GDlib Image Pointer
1368 * @return void
1369 */
1370 function autolevels(&$im) {
1371 $totalCols = ImageColorsTotal($im);
1372 $min=255;
1373 $max=0;
1374 for ($c=0; $c<$totalCols; $c++) {
1375 $cols = ImageColorsForIndex($im,$c);
1376 $grayArr[] = round(($cols['red']+$cols['green']+$cols['blue'])/3);
1377 }
1378 $min=min($grayArr);
1379 $max=max($grayArr);
1380 $delta = $max-$min;
1381 if ($delta) {
1382 for ($c=0; $c<$totalCols; $c++) {
1383 $cols = ImageColorsForIndex($im,$c);
1384 $cols['red'] = floor(($cols['red']-$min)/$delta*255);
1385 $cols['green'] = floor(($cols['green']-$min)/$delta*255);
1386 $cols['blue'] = floor(($cols['blue']-$min)/$delta*255);
1387 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']);
1388 }
1389 }
1390 }
1391
1392 /**
1393 * Apply output levels to input image pointer (decreasing contrast)
1394 *
1395 * @param integer GDlib Image Pointer
1396 * @param integer The "low" value (close to 0)
1397 * @param integer The "high" value (close to 255)
1398 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...)
1399 * @return void
1400 */
1401 function outputLevels(&$im,$low,$high,$swap='') {
1402 if ($low<$high){
1403 $low = t3lib_div::intInRange($low,0,255);
1404 $high = t3lib_div::intInRange($high,0,255);
1405
1406 if ($swap) {
1407 $temp = $low;
1408 $low = 255-$high;
1409 $high = 255-$temp;
1410 }
1411
1412 $delta = $high-$low;
1413 $totalCols = ImageColorsTotal($im);
1414 for ($c=0; $c<$totalCols; $c++) {
1415 $cols = ImageColorsForIndex($im,$c);
1416 $cols['red'] = $low+floor($cols['red']/255*$delta);
1417 $cols['green'] = $low+floor($cols['green']/255*$delta);
1418 $cols['blue'] = $low+floor($cols['blue']/255*$delta);
1419 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']);
1420 }
1421 }
1422 }
1423
1424 /**
1425 * Apply input levels to input image pointer (increasing contrast)
1426 *
1427 * @param integer GDlib Image Pointer
1428 * @param integer The "low" value (close to 0)
1429 * @param integer The "high" value (close to 255)
1430 * @param boolean If swap, then low and high are swapped. (Useful for negated masks...)
1431 * @return void
1432 */
1433 function inputLevels(&$im,$low,$high,$swap='') {
1434 if ($low<$high){
1435 $low = t3lib_div::intInRange($low,0,255);
1436 $high = t3lib_div::intInRange($high,0,255);
1437
1438 if ($swap) {
1439 $temp = $low;
1440 $low = 255-$high;
1441 $high = 255-$temp;
1442 }
1443
1444 $delta = $high-$low;
1445 $totalCols = ImageColorsTotal($im);
1446 for ($c=0; $c<$totalCols; $c++) {
1447 $cols = ImageColorsForIndex($im,$c);
1448 $cols['red'] = t3lib_div::intInRange(($cols['red']-$low)/$delta*255, 0,255);
1449 $cols['green'] = t3lib_div::intInRange(($cols['green']-$low)/$delta*255, 0,255);
1450 $cols['blue'] = t3lib_div::intInRange(($cols['blue']-$low)/$delta*255, 0,255);
1451 ImageColorSet($im,$c,$cols['red'],$cols['green'],$cols['blue']);
1452 }
1453 }
1454 }
1455
1456 /**
1457 * Reduce colors in image
1458 *
1459 * @param integer GDlib Image Pointer
1460 * @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.
1461 * @param integer Number of colors to reduce the image to.
1462 * @return void
1463 */
1464 function reduceColors(&$im,$limit, $cols) {
1465 if (ImageColorsTotal($im)>=$limit) {
1466 $this->makeEffect($im, Array('value'=>'colors='.$cols) );
1467 }
1468 }
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488 /*********************************
1489 *
1490 * GIFBUILDER Helper functions
1491 *
1492 *********************************/
1493
1494 /**
1495 * Checks if the $fontFile is already at an absolute path and if not, prepends the correct path.
1496 * Use PATH_site unless we are in the backend.
1497 * Call it by t3lib_stdGraphic::prependAbsolutePath()
1498 *
1499 * @param string The font file
1500 * @return string The font file with absolute path.
1501 */
1502 function prependAbsolutePath($fontFile) {
1503 $absPath = defined('PATH_typo3') ? dirname(PATH_thisScript).'/' :PATH_site;
1504 $fontFile = t3lib_div::isAbsPath($fontFile) ? $fontFile : $absPath.$fontFile;
1505 return $fontFile;
1506 }
1507
1508 /**
1509 * Returns the IM command for sharpening with ImageMagick 5 (when $this->V5_EFFECTS is set).
1510 * Uses $this->im5fx_sharpenSteps for translation of the factor to an actual command.
1511 *
1512 * @param integer The sharpening factor, 0-100 (effectively in 10 steps)
1513 * @return string The sharpening command, eg. " -sharpen 3x4"
1514 * @see makeText(), IMparams(), v5_blur()
1515 */
1516 function v5_sharpen($factor) {
1517 $factor = t3lib_div::intInRange(ceil($factor/10),0,10);
1518
1519 $sharpenArr=explode(',',','.$this->im5fx_sharpenSteps);
1520 $sharpenF= trim($sharpenArr[$factor]);
1521 if ($sharpenF) {
1522 $cmd = ' -sharpen '.$sharpenF;
1523 return $cmd;
1524 }
1525 }
1526
1527 /**
1528 * Returns the IM command for blurring with ImageMagick 5 (when $this->V5_EFFECTS is set).
1529 * Uses $this->im5fx_blurSteps for translation of the factor to an actual command.
1530 *
1531 * @param integer The blurring factor, 0-100 (effectively in 10 steps)
1532 * @return string The blurring command, eg. " -blur 3x4"
1533 * @see makeText(), IMparams(), v5_sharpen()
1534 */
1535 function v5_blur($factor) {
1536 $factor = t3lib_div::intInRange(ceil($factor/10),0,10);
1537
1538 $blurArr=explode(',',','.$this->im5fx_blurSteps);
1539 $blurF= trim($blurArr[$factor]);
1540 if ($blurF) {
1541 $cmd=' -blur '.$blurF;
1542 return $cmd;
1543 }
1544 }
1545
1546 /**
1547 * Returns a random filename prefixed with "temp_" and then 32 char md5 hash (without extension) from $this->tempPath.
1548 * 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.
1549 *
1550 * @return string
1551 */
1552 function randomName() {
1553 return $this->tempPath.'temp_'.md5(uniqid(''));
1554 }
1555
1556 /**
1557 * Applies offset value to coordinated in $cords.
1558 * Basically the value of key 0/1 of $OFFSET is added to keys 0/1 of $cords
1559 *
1560 * @param array Integer coordinates in key 0/1
1561 * @param array Offset values in key 0/1
1562 * @return array Modified $cords array
1563 */
1564 function applyOffset($cords,$OFFSET) {
1565 $cords[0] = intval($cords[0])+intval($OFFSET[0]);
1566 $cords[1] = intval($cords[1])+intval($OFFSET[1]);
1567 return $cords;
1568 }
1569
1570 /**
1571 * Converts a "HTML-color" TypoScript datatype to RGB-values.
1572 * Default is 0,0,0
1573 *
1574 * @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
1575 * @return array RGB values in key 0/1/2 of the array
1576 */
1577 function convertColor($string) {
1578 $col=array();
1579 $cParts = explode(':',$string,2);
1580
1581 // Finding the RGB definitions of the color:
1582 $string=$cParts[0];
1583 if (strstr($string,'#')) {
1584 $string = ereg_replace('[^A-Fa-f0-9]*','',$string);
1585 $col[]=HexDec(substr($string,0,2));
1586 $col[]=HexDec(substr($string,2,2));
1587 $col[]=HexDec(substr($string,4,2));
1588 } elseif (strstr($string,',')) {
1589 $string = ereg_replace('[^,0-9]*','',$string);
1590 $strArr = explode(',',$string);
1591 $col[]=intval($strArr[0]);
1592 $col[]=intval($strArr[1]);
1593 $col[]=intval($strArr[2]);
1594 } else {
1595 $string = strtolower(trim($string));
1596 if ($this->colMap[$string]) {
1597 $col = $this->colMap[$string];
1598 } else {
1599 $col = Array(0,0,0);
1600 }
1601 }
1602 // ... and possibly recalculating the value
1603 if (trim($cParts[1])) {
1604 $cParts[1]=trim($cParts[1]);
1605 if (substr($cParts[1],0,1)=='*') {
1606 $val=doubleval(substr($cParts[1],1));
1607 $col[0]=t3lib_div::intInRange($col[0]*$val,0,255);
1608 $col[1]=t3lib_div::intInRange($col[1]*$val,0,255);
1609 $col[2]=t3lib_div::intInRange($col[2]*$val,0,255);
1610 } else {
1611 $val=intval($cParts[1]);
1612 $col[0]=t3lib_div::intInRange($col[0]+$val,0,255);
1613 $col[1]=t3lib_div::intInRange($col[1]+$val,0,255);
1614 $col[2]=t3lib_div::intInRange($col[2]+$val,0,255);
1615 }
1616 }
1617 return $col;
1618 }
1619
1620 /**
1621 * Recode string
1622 * Used with text strings for fonts when languages has other character sets.
1623 *
1624 * @param string The text to recode
1625 * @return string The recoded string. Should be UTF-8 output. MAY contain entities (eg. &#123; or &#quot; which should render as real chars).
1626 */
1627 function recodeString($string) {
1628 // Recode string to UTF-8 from $this->nativeCharset:
1629 if ($this->nativeCharset && $this->nativeCharset!='utf-8') {
1630 $string = $this->csConvObj->utf8_encode($string,$this->nativeCharset); // Convert to UTF-8
1631 }
1632
1633 // Recode string accoding to TTFLocaleConv. Depreciated.
1634 if ($this->TTFLocaleConv) {
1635 $string = recode_string($this->TTFLocaleConv,$string);
1636 }
1637
1638 return $string;
1639 }
1640
1641 /**
1642 * Split a string into an array of individual characters
1643 * 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.
1644 *
1645 * @param string The text string to spli
1646 * @return array Numerical array with a char as each value.
1647 */
1648 function singleChars($theText) {
1649 if ($this->nativeCharset) {
1650 return $this->csConvObj->utf8_to_numberarray($theText,1,1); // Get an array of separated UTF-8 chars
1651 } else {
1652 $output=array();
1653 $c=strlen($theText);
1654 for($a=0;$a<$c;$a++) {
1655 $output[]=substr($theText,$a,1);
1656 }
1657 return $output;
1658 }
1659 }
1660
1661 /**
1662 * 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
1663 *
1664 * @param array TypoScript configuration for a GIFBUILDER object
1665 * @param array Workarea definition
1666 * @param array BB (Bounding box) array. Not just used for TEXT objects but also for others
1667 * @return array [0]=x, [1]=y, [2]=w, [3]=h
1668 * @access private
1669 * @see copyGifOntoGif(), makeBox(), crop()
1670 */
1671 function objPosition($conf,$workArea,$BB) {
1672 // offset, align, valign, workarea
1673 $result=Array();
1674 $result[2] = $BB[0];
1675 $result[3] = $BB[1];
1676 $w=$workArea[2];
1677 $h=$workArea[3];
1678
1679 $align = explode(',',$conf['align']);
1680 $align[0] = strtolower(substr(trim($align[0]),0,1));
1681 $align[1] = strtolower(substr(trim($align[1]),0,1));
1682
1683 switch($align[0]) {
1684 case 'r':
1685 $result[0]=$w-$result[2];
1686 break;
1687 case 'c':
1688 $result[0] = round(($w-$result[2])/2);
1689 break;
1690 default:
1691 $result[0] = 0;
1692 break;
1693 }
1694 switch($align[1]) {
1695 case 'b':
1696 $result[1] = $h-$result[3]; // y pos
1697 break;
1698 case 'c':
1699 $result[1] = round(($h-$result[3])/2);
1700 break;
1701 default:
1702 $result[1]=0;
1703 break;
1704 }
1705 $result = $this->applyOffset($result,t3lib_div::intExplode(',',$conf['offset']));
1706 $result = $this->applyOffset($result,$workArea);
1707 return $result;
1708 }
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730 /***********************************
1731 *
1732 * Scaling, Dimensions of images
1733 *
1734 ***********************************/
1735
1736 /**
1737 * Converts $imagefile to another file in temp-dir of type $newExt (extension).
1738 *
1739 * @param string The image filepath
1740 * @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.
1741 * @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
1742 * @param string Height. See $w
1743 * @param string Additional ImageMagick parameters.
1744 * @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...
1745 * @param array An array with options passed to getImageScale (see this function).
1746 * @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.
1747 * @return array [0]/[1] is w/h, [2] is file extension and [3] is the filename.
1748 * @see getImageScale(), typo3/show_item.php, fileList_ext::renderImage(), tslib_cObj::getImgResource(), SC_tslib_showpic::show(), maskImageOntoImage(), copyImageOntoImage(), scale()
1749 */
1750 function imageMagickConvert($imagefile,$newExt='',$w='',$h='',$params='',$frame='',$options='',$mustCreate=0) {
1751 if ($this->NO_IMAGE_MAGICK) {
1752 // Returning file info right away
1753 return $this->getImageDimensions($imagefile);
1754 }
1755
1756 if($info=$this->getImageDimensions($imagefile)) {
1757 $newExt=strtolower(trim($newExt));
1758 if (!$newExt) { // If no extension is given the original extension is used
1759 $newExt = $info[2];
1760 }
1761 if ($newExt=='web') {
1762 if (t3lib_div::inList($this->webImageExt,$info[2])) {
1763 $newExt = $info[2];
1764 } else {
1765 $newExt = $this->gif_or_jpg($info[2],$info[0],$info[1]);
1766 if (!$params) {
1767 $params = $this->cmds[$newExt];
1768 }
1769 }
1770 }
1771 if (t3lib_div::inList($this->imageFileExt,$newExt)) {
1772 if (strstr($w.$h, 'm')) {$max=1;} else {$max=0;}
1773
1774 $data = $this->getImageScale($info,$w,$h,$options);
1775 $w=$data['origW'];
1776 $h=$data['origH'];
1777
1778 // if no convertion should be performed
1779 $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....
1780
1781 if ($wh_noscale && !$params && !$frame && $newExt==$info[2] && !$mustCreate) {
1782 $info[3] = $imagefile;
1783 return $info;
1784 }
1785 $info[0]=$data[0];
1786 $info[1]=$data[1];
1787
1788 $frame = $this->noFramePrepended ? '' : '['.intval($frame).']';
1789
1790 if (!$params) {
1791 $params = $this->cmds[$newExt];
1792 }
1793
1794 $command = $this->scalecmd.' '.$info[0].'x'.$info[1].'! '.$params.' ';
1795
1796 if ($this->alternativeOutputKey) {
1797 $theOutputName = t3lib_div::shortMD5($command.basename($imagefile).$this->alternativeOutputKey.$frame);
1798 } else {
1799 $theOutputName = t3lib_div::shortMD5($command.$imagefile.filemtime($imagefile).$frame);
1800 }
1801 if ($this->imageMagickConvert_forceFileNameBody) {
1802 $theOutputName = $this->imageMagickConvert_forceFileNameBody;
1803 $this->imageMagickConvert_forceFileNameBody='';
1804 }
1805 $output = $this->tempPath.$this->filenamePrefix.$theOutputName.'.'.$newExt;
1806 $GLOBALS['TEMP_IMAGES_ON_PAGE'][]=$output;
1807
1808 if (!$this->file_exists_typo3temp_file($output,$imagefile) || $this->dontCheckForExistingTempFile) {
1809 $this->imageMagickExec($imagefile.$frame,$output,$command);
1810 }
1811 if (@file_exists($output)) {
1812 $info[3] = $output;
1813 $info[2] = $newExt;
1814 if ($params) { // params could realisticly change som imagedata!
1815 $info=$this->getImageDimensions($info[3]);
1816 }
1817 if ($info[2]==$this->gifExtension && !$this->dontCompress) {
1818 t3lib_div::gif_compress($info[3],''); // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD)
1819 }
1820 return $info;
1821 }
1822 }
1823 }
1824 }
1825
1826 /**
1827 * Gets the input image dimensions.
1828 *
1829 * @param string The image filepath
1830 * @return array Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
1831 * @see imageMagickConvert(), tslib_cObj::getImgResource()
1832 */
1833 function getImageDimensions($imagefile) {
1834 ereg('([^\.]*)$',$imagefile,$reg);
1835 if (@file_exists($imagefile) && t3lib_div::inList($this->imageFileExt,strtolower($reg[0]))) {
1836 if ($temp = @getImageSize($imagefile)) {
1837 return Array($temp[0], $temp[1], strtolower($reg[0]), $imagefile);
1838 } else {
1839 return $this->imageMagickIdentify($imagefile);
1840 }
1841 }
1842 }
1843
1844 /**
1845 * Get numbers for scaling the image based on input
1846 *
1847 * @param array Current image information: Width, Height etc.
1848 * @param integer "required" width
1849 * @param integer "required" height
1850 * @param array Options: Keys are like "maxW", "maxH", "minW", "minH"
1851 * @return array
1852 * @access private
1853 * @see imageMagickConvert()
1854 */
1855 function getImageScale($info,$w,$h,$options) {
1856 if (strstr($w.$h, 'm')) {$max=1;} else {$max=0;}
1857 $w=intval($w);
1858 $h=intval($h);
1859 // if there are max-values...
1860 if ($options['maxW']) {
1861 if ($w) { // if width is given...
1862 if ($w>$options['maxW']) {
1863 $w=$options['maxW'];
1864 $max=1; // height should follow
1865 }
1866 } else {
1867 if ($info[0]>$options['maxW']) {
1868 $w=$options['maxW'];
1869 $max=1; // height should follow
1870 }
1871 }
1872 }
1873 if ($options['maxH']) {
1874 if ($h) { // if height is given...
1875 if ($h>$options['maxH']) {
1876 $h=$options['maxH'];
1877 $max=1; // height should follow
1878 }
1879 } else {
1880 if ($info[1]>$options['maxH']) { // Changed [0] to [1] 290801
1881 $h=$options['maxH'];
1882 $max=1; // height should follow
1883 }
1884 }
1885 }
1886 $out['origW']=$w;
1887 $out['origH']=$h;
1888 $out['max'] = $max;
1889
1890 if (!$this->mayScaleUp) {
1891 if ($w>$info[0]){$w=$info[0];}
1892 if ($h>$info[1]){$h=$info[1];}
1893 }
1894 if ($w || $h) { // if scaling should be performed
1895 if ($w && !$h) {
1896 $info[1] = ceil($info[1]*($w/$info[0]));
1897 $info[0] = $w;
1898 }
1899 if (!$w && $h) {
1900 $info[0] = ceil($info[0]*($h/$info[1]));
1901 $info[1] = $h;
1902 }
1903 if ($w && $h) {
1904 if ($max) {
1905 $ratio = $info[0]/$info[1];
1906 if ($h*$ratio > $w) {
1907 $h = round($w/$ratio);
1908 } else {
1909 $w = round($h*$ratio);
1910 }
1911 }
1912 $info[0] = $w;
1913 $info[1] = $h;
1914 }
1915 }
1916 $out[0]=$info[0];
1917 $out[1]=$info[1];
1918 // Set minimum-measures!
1919 if ($options['minW'] && $out[0]<$options['minW']) {
1920 if ($max && $out[0]) {
1921 $out[1]= round($out[1]*$options['minW']/$out[0]);
1922 }
1923 $out[0]=$options['minW'];
1924 }
1925 if ($options['minH'] && $out[1]<$options['minH']) {
1926 if ($max && $out[1]) {
1927 $out[0]= round($out[0]*$options['minH']/$out[1]);
1928 }
1929 $out[1]=$options['minH'];
1930 }
1931
1932 return $out;
1933 }
1934
1935 /**
1936 * Used to check if a certain process of scaling an image is already being carried out (can be logged in the MySQL database)
1937 *
1938 * @param string Output imagefile
1939 * @param string Original basis file
1940 * @return boolean Returns true if the file is already being made; thus "true" means "Don't render the image again"
1941 * @access private
1942 */
1943 function file_exists_typo3temp_file($output,$orig='') {
1944 if ($this->enable_typo3temp_db_tracking) {
1945 if (@file_exists($output)) { // If file exists, then we return immediately
1946 return 1;
1947 } else { // If not, we look up in the cache_typo3temp_log table to see if there is a image being rendered right now.
1948 $md5Hash=md5($output);
1949 $query='SELECT md5hash FROM cache_typo3temp_log WHERE md5hash="'.$md5Hash.'" AND tstamp>'.(time()-30);
1950 $res=mysql(TYPO3_db,$query);
1951 echo mysql_error();
1952 if ($row=mysql_fetch_assoc($res)) { // If there was a record, the image is being generated by another proces (we assume)
1953 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...)
1954 if (is_object($GLOBALS['TT'])) $GLOBALS['TT']->setTSlogMessage('typo3temp_log: Assume this file is being rendered now: '.$output);
1955 return 2; // Return 'success - 2'
1956 } 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.
1957 $query='DELETE FROM cache_typo3temp_log WHERE md5hash="'.$md5Hash.'"';
1958 $res=mysql(TYPO3_db,$query);
1959 $query='INSERT INTO cache_typo3temp_log (md5hash,tstamp,filename,orig_filename) VALUES ("'.$md5Hash.'",'.time().',"'.addslashes($output).'","'.addslashes($orig).'")';
1960 $res=mysql(TYPO3_db,$query);
1961 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);
1962 return 0;
1963 }
1964 }
1965 } else {
1966 return @file_exists($output);
1967 }
1968 }
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987 /***********************************
1988 *
1989 * ImageMagick API functions
1990 *
1991 ***********************************/
1992
1993 /**
1994 * Returns an array where [0]/[1] is w/h, [2] is extension and [3] is the filename.
1995 * Using ImageMagick
1996 *
1997 * @param string The absolute image filepath
1998 * @return array
1999 */
2000 function imageMagickIdentify($imagefile) {
2001 if (!$this->NO_IMAGE_MAGICK) {
2002 $cmd = $this->imageMagickPath.'identify '.$this->wrapFileName($imagefile);
2003 exec($cmd, $returnVal);
2004 $splitstring=$returnVal[0];
2005 $this->IM_commands[] = Array ('identify',$cmd,$returnVal[0]);
2006 if ($splitstring) {
2007 ereg('([^\.]*)$',$imagefile,$reg);
2008 $splitinfo = explode(' ', $splitstring);
2009 while (list($key,$val) = each($splitinfo)) {
2010 $temp = '';
2011 if ($val) {$temp = explode('x', $val);}
2012 if (intval($temp[0]) && intval($temp[1])) {
2013 $dim=$temp;
2014 break;
2015 }
2016 }
2017 if ($dim[0] && $dim[1]) {
2018 return Array($dim[0], $dim[1], strtolower($reg[0]), $imagefile);
2019 }
2020 }
2021 }
2022 }
2023
2024 /**
2025 * Executes a ImageMagick "convert" on two filenames, $input and $output using $params before them.
2026 * Can be used for many things, mostly scaling and effects.
2027 *
2028 * @param string The absolute image filepath, input file (read from)
2029 * @param string The absolute image filepath, output filename (written to)
2030 * @param string ImageMagick parameters
2031 * @return string The result of a call to PHP function "exec()"
2032 */
2033 function imageMagickExec($input,$output,$params) {
2034 if (!$this->NO_IMAGE_MAGICK) {
2035 $cmd = $this->imageMagickPath.'convert '.$params.' '.$this->wrapFileName($input).' '.$this->wrapFileName($output);
2036 $this->IM_commands[] = Array ($output,$cmd);
2037 return exec($cmd);
2038 }
2039 }
2040
2041 /**
2042 * 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)
2043 * Can be used for many things, mostly scaling and effects.
2044 *
2045 * @param string The absolute image filepath, bottom file
2046 * @param string The absolute image filepath, overlay file (top)
2047 * @param string The absolute image filepath, the mask file (grayscale)
2048 * @param string The absolute image filepath, output filename (written to)
2049 * @return void
2050 */
2051 function combineExec($input,$overlay,$mask,$output) {
2052 if (!$this->NO_IMAGE_MAGICK) {
2053 $cmd = $this->imageMagickPath.$this->combineScript.' -compose over '.$this->wrapFileName($input).' '.$this->wrapFileName($overlay).' '.$this->wrapFileName($mask).' '.$this->wrapFileName($output);
2054 $this->IM_commands[] = Array ($output,$cmd);
2055 exec($cmd);
2056 }
2057 }
2058
2059 /**
2060 * Wrapping the input filename in double-quotes
2061 *
2062 * @param string Input filename
2063 * @return string The outpute wrapped in ""
2064 * @access private
2065 */
2066 function wrapFileName($inputName) {
2067 if (strstr($inputName,' ')) {
2068 $inputName='"'.$inputName.'"';
2069 }
2070 return $inputName;
2071 }
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095 /***********************************
2096 *
2097 * Various IO functions
2098 *
2099 ***********************************/
2100
2101 /**
2102 * Returns true if the input file existed
2103 *
2104 * @param string Input file to check
2105 * @return string Returns the filename if the file existed, otherwise empty.
2106 */
2107 function checkFile($file) {
2108 if (@is_file($file)) {
2109 return $file;
2110 } else {
2111 return '';
2112 }
2113 }
2114
2115 /**
2116 * 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.
2117 *
2118 * @param pointer The image pointer (reference)
2119 * @param string The ImageMagick parameters. Like effects, scaling etc.
2120 * @return void
2121 */
2122 function applyImageMagickToPHPGif(&$im, $command) {
2123 $tmpStr = $this->randomName();
2124 $theFile = $tmpStr.'.'.$this->gifExtension;
2125 $this->ImageGif($im, $theFile);
2126 $this->imageMagickExec($theFile,$theFile,$command);
2127 $tmpImg = $this->imageCreateFromGif($theFile);
2128 if ($tmpImg) {
2129 ImageDestroy($im);
2130 $im = $tmpImg;
2131 $this->w = imagesx($im);
2132 $this->h = imagesy($im);
2133 }
2134 if (!$this->dontUnlinkTempFiles) {
2135 unlink($theFile);
2136 }
2137 }
2138
2139 /**
2140 * 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.
2141 * For example: If the number of pixels exceeds $this->pixelLimitGif (normally 10000) then it will be a "jpg" string in return.
2142 *
2143 * @param string The file extension, lowercase.
2144 * @param integer The width of the output image.
2145 * @param integer The height of the output image.
2146 * @return string The filename, either "jpg" or "gif"/"png" (whatever $this->gifExtension is set to.)
2147 */
2148 function gif_or_jpg($type,$w,$h) {
2149 if ($type=='ai' || $w*$h < $this->pixelLimitGif) {
2150 return $this->gifExtension;
2151 } else {
2152 return 'jpg';
2153 }
2154 }
2155
2156 /**
2157 * Writing the internal image pointer, $this->im, to file based on the extension of the input filename
2158 * Used in GIFBUILDER
2159 * Uses $this->setup['reduceColors'] for gif/png images and $this->setup['quality'] for jpg images to reduce size/quality if needed.
2160 *
2161 * @param string The filename to write to.
2162 * @return string Returns input filename
2163 * @see tslib_gifBuilder::gifBuild()
2164 */
2165 function output($file) {
2166 if ($file) {
2167 ereg('([^\.]*)$',$file,$reg);
2168 $ext=strtolower($reg[0]);
2169 switch($ext) {
2170 case $this->gifExtension:
2171 if ($this->ImageGif($this->im, $file)) {
2172 // ImageMagick operations
2173 if($this->setup['reduceColors']) {
2174 $this->imageMagickExec($file,$file,' -colors '.t3lib_div::intInRange($this->setup['reduceColors'],2,255));
2175 t3lib_div::gif_compress($file,''); // Compress with IM (lzw) or GD (rle) (Workaround for the absence of lzw-compression in GD)
2176 } else {
2177 t3lib_div::gif_compress($file, 'IM'); // Compress with IM! (adds extra compression, LZW from ImageMagick) (Workaround for the absence of lzw-compression in GD)
2178 }
2179 }
2180 break;
2181 case 'jpg':
2182 case 'jpeg':
2183 $tmpStr = $this->randomName();
2184 $theFile = $tmpStr.'.'.$this->gifExtension;
2185 if ($this->ImageGif($this->im, $theFile)) {
2186 // ImageMagick operations
2187 $operations='';
2188 if($this->setup['quality']) {
2189 $operations.=' -quality '.t3lib_div::intInRange($this->setup['quality'],10,100);
2190 }
2191 $this->imageMagickExec($theFile,$file,$operations);
2192 if (!$this->dontUnlinkTempFiles) {
2193 unlink($theFile);
2194 }
2195 }
2196 break;
2197 }
2198 $GLOBALS['TEMP_IMAGES_ON_PAGE'][]=$file;
2199 }
2200 return $file;
2201 }
2202
2203 /**
2204 * Destroy internal image pointer, $this->im
2205 *
2206 * @return void
2207 * @see tslib_gifBuilder::gifBuild()
2208 */
2209 function destroy() {
2210 ImageDestroy($this->im);
2211 }
2212
2213 /**
2214 * Returns Image Tag for input image information array.
2215 *
2216 * @param array Image information array, key 0/1 is width/height and key 3 is the src value
2217 * @return string Image tag for the input image information array.
2218 */
2219 function imgTag ($imgInfo) {
2220 return '<img src="'.$imgInfo[3].'" width="'.$imgInfo[0].'" height="'.$imgInfo[1].'" border="0" alt="" />';
2221 }
2222
2223 /**
2224 * Writes the input GDlib image pointer to file
2225 *
2226 * @param pointer The GDlib image resource pointer
2227 * @param string The filename to write to
2228 * @return mixed The output of either imageGif or imagePng based on whether the $this->gifExtension was set to "gif" or "png"
2229 * @see maskImageOntoImage(), scale(), output()
2230 */
2231 function ImageGif($destImg, $theImage) {
2232 imageinterlace ($destImg,0);
2233 if ($this->gifExtension=='gif') {
2234 return ImageGif($destImg, $theImage);
2235 }
2236 if ($this->gifExtension=='png') {
2237 return ImagePng($destImg, $theImage);
2238 }
2239 }
2240
2241 /**
2242 * Creates a new GDlib image resource based on the input image filename.
2243 * If it fails creating a image from the input file a blank gray image with the dimensions of the input image will be created instead.
2244 *
2245 * @param string Image filename
2246 * @return pointer Image Resource pointer
2247 */
2248 function imageCreateFromGif($sourceImg) {
2249 $imgInf = pathinfo($sourceImg);
2250 $ext = strtolower($imgInf['extension']);
2251
2252 // if ($ext=='gif' && (ImageTypes() & IMG_GIF)) {
2253 if ($ext=='gif' && function_exists('imagecreatefromgif')) {
2254 return imageCreateFromGif($sourceImg);
2255 }
2256 // if ($ext=='png' && (ImageTypes() & IMG_PNG)) {
2257 if ($ext=='png' && function_exists('imagecreatefrompng')) {
2258 return imageCreateFromPng($sourceImg);
2259 }
2260 // if (($ext=='jpg' || $ext=='jpeg') && (ImageTypes() & IMG_JPG)) {
2261 if (($ext=='jpg' || $ext=='jpeg') && function_exists('imagecreatefromjpeg')) {
2262 return imageCreateFromJpeg($sourceImg);
2263 }
2264
2265 // If non of the above:
2266 $i = @getimagesize($sourceImg);
2267 $im = imagecreate($i[0],$i[1]);
2268 ImageColorAllocate($im, 128,128,128);
2269 return $im;
2270 }
2271 }
2272
2273
2274 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php']) {
2275 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_stdgraphic.php']);
2276 }
2277 ?>