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