fixed bug #6692: When letting TYPO3 generate DB table icons it can happen that transp...
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_iconworks.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 1999-2006 Kasper Skaarhoj (kasperYYYY@typo3.com)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Contains class for icon generation in the backend
29 *
30 * $Id$
31 * Revised for TYPO3 3.6 July/2003 by Kasper Skaarhoj
32 * XHTML compliant
33 *
34 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
35 */
36 /**
37 * [CLASS/FUNCTION INDEX of SCRIPT]
38 *
39 *
40 *
41 * 85: class t3lib_iconWorks
42 * 100: function getIconImage($table,$row=array(),$backPath,$params='',$shaded=FALSE)
43 * 118: function getIcon($table,$row=array(),$shaded=FALSE)
44 * 264: function skinImg($backPath,$src,$wHattribs='',$outputMode=0)
45 *
46 * SECTION: Other functions
47 * 353: function makeIcon($iconfile,$mode, $user, $protectSection,$absFile,$iconFileName_stateTagged)
48 * 475: function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h)
49 * 505: function imagecreatefrom($file)
50 * 522: function imagemake($im, $path)
51 *
52 * TOTAL FUNCTIONS: 7
53 * (This index is automatically created/updated by the extension "extdeveval")
54 *
55 */
56
57
58
59
60
61
62
63
64
65
66 /**
67 * Icon generation, backend
68 * This library has functions that returns - and if necessary creates - the icon for an element in TYPO3
69 *
70 * Expects global vars:
71 * - $BACK_PATH
72 * - PATH_typo3
73 * - $TCA, $PAGES_TYPES
74 *
75 *
76 * Notes:
77 * These functions are strongly related to the interface of TYPO3.
78 * The class is included in eg. init.php
79 * ALL functions called without making a class instance, eg. "t3lib_iconWorks::getIconImage()"
80 *
81 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
82 * @package TYPO3
83 * @subpackage t3lib
84 */
85 class t3lib_iconWorks {
86
87 /**
88 * Returns an icon image tag, 18x16 pixels, based on input information.
89 * This function is recommended to use in your backend modules.
90 * Usage: 60
91 *
92 * @param string The table name
93 * @param array The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
94 * @param string The backpath to the main TYPO3 directory (relative path back to PATH_typo3)
95 * @param string Additional attributes for the image tag
96 * @param boolean If set, the icon will be grayed/shaded
97 * @return string <img>-tag
98 * @see getIcon()
99 */
100 function getIconImage($table,$row=array(),$backPath,$params='',$shaded=FALSE) {
101 $str='<img'.t3lib_iconWorks::skinImg($backPath,t3lib_iconWorks::getIcon($table,$row,$shaded),'width="18" height="16"').(trim($params)?' '.trim($params):'');
102 if (!stristr($str,'alt="')) $str.=' alt=""';
103 $str.=' />';
104 return $str;
105 }
106
107 /**
108 * Creates the icon for input table/row
109 * Returns filename for the image icon, relative to PATH_typo3
110 * Usage: 24
111 *
112 * @param string The table name
113 * @param array The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
114 * @param boolean If set, the icon will be grayed/shaded
115 * @return string Icon filename
116 * @see getIconImage()
117 */
118 function getIcon($table,$row=array(),$shaded=FALSE) {
119 global $TCA, $PAGES_TYPES, $ICON_TYPES;
120
121 // Flags:
122 $doNotGenerateIcon = $GLOBALS['TYPO3_CONF_VARS']['GFX']['noIconProc']; // If set, the icon will NOT be generated with GDlib. Rather the icon will be looked for as [iconfilename]_X.[extension]
123 $doNotRenderUserGroupNumber = TRUE; // If set, then the usergroup number will NOT be printed unto the icon. NOTICE. the icon is generated only if a default icon for groups is not found... So effectively this is ineffective...
124
125 // Shadow:
126 if ($TCA[$table]['ctrl']['versioningWS']) {
127 switch((int)$row['t3ver_state']) {
128 case 1:
129 return 'gfx/i/shadow_hide.png';
130 break;
131 case 2:
132 return 'gfx/i/shadow_delete.png';
133 break;
134 case 3:
135 return 'gfx/i/shadow_moveto_plh.png';
136 break;
137 case 4:
138 return 'gfx/i/shadow_moveto_pointer.png';
139 break;
140 }
141 }
142
143 // First, find the icon file name. This can depend on configuration in TCA, field values and more:
144 if ($table=='pages') {
145 if ($row['nav_hide'] && ($row['doktype']==1||$row['doktype']==2)) $row['doktype']=5; // Workaround to change the icon if "Hide in menu" was set
146
147 if (!$iconfile = $PAGES_TYPES[$row['doktype']]['icon']) {
148 $iconfile = $PAGES_TYPES['default']['icon'];
149 }
150 if ($row['module'] && $ICON_TYPES[$row['module']]['icon']) {
151 $iconfile = $ICON_TYPES[$row['module']]['icon'];
152 }
153 } else {
154 if (!$iconfile = $TCA[$table]['ctrl']['typeicons'][$row[$TCA[$table]['ctrl']['typeicon_column']]]) {
155 $iconfile = (($TCA[$table]['ctrl']['iconfile']) ? $TCA[$table]['ctrl']['iconfile'] : $table.'.gif');
156 }
157 }
158
159 // Setting path of iconfile if not already set. Default is "gfx/i/"
160 if (!strstr($iconfile,'/')) {
161 $iconfile = 'gfx/i/'.$iconfile;
162 }
163
164 // Setting the absolute path where the icon should be found as a file:
165 if (substr($iconfile,0,3)=='../') {
166 $absfile=PATH_site.substr($iconfile,3);
167 } else {
168 $absfile=PATH_typo3.$iconfile;
169 }
170
171 // Initializing variables, all booleans except otherwise stated:
172 $hidden = FALSE;
173 $timing = FALSE;
174 $futuretiming = FALSE;
175 $user = FALSE; // In fact an integer value...
176 $deleted = FALSE;
177 $protectSection = FALSE; // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
178 $noIconFound = $row['_NO_ICON_FOUND'] ? TRUE : FALSE;
179 // + $shaded which is also boolean!
180
181 // Icon state based on "enableFields":
182 if (is_array($TCA[$table]['ctrl']['enablecolumns'])) {
183 $enCols = $TCA[$table]['ctrl']['enablecolumns'];
184 // If "hidden" is enabled:
185 if ($enCols['disabled']) { if ($row[$enCols['disabled']]) { $hidden = TRUE; }}
186 // If a "starttime" is set and higher than current time:
187 if ($enCols['starttime']) { if (time() < intval($row[$enCols['starttime']])) { $timing = TRUE; }}
188 // If an "endtime" is set:
189 if ($enCols['endtime']) {
190 if (intval($row[$enCols['endtime']]) > 0) {
191 if (intval($row[$enCols['endtime']]) < time()) {
192 $timing = TRUE; // End-timing applies at this point.
193 } else {
194 $futuretiming = TRUE; // End-timing WILL apply in the future for this element.
195 }
196 }
197 }
198 // If a user-group field is set:
199 if ($enCols['fe_group']) {
200 $user = $row[$enCols['fe_group']];
201 if ($user && $doNotRenderUserGroupNumber) $user=100; // Limit for user number rendering!
202 }
203 }
204
205 // If "deleted" flag is set (only when listing records which are also deleted!)
206 if ($col=$row[$TCA[$table]['ctrl']['delete']]) {
207 $deleted = TRUE;
208 }
209 // Detecting extendToSubpages (for pages only)
210 if ($table=='pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
211 $protectSection = TRUE;
212 }
213
214 // If ANY of the booleans are set it means we have to alter the icon:
215 if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
216 $flags='';
217 $string='';
218 if ($deleted) {
219 $string='deleted';
220 $flags='d';
221 } elseif ($noIconFound) { // This is ONLY for creating icons with "?" on easily...
222 $string='no_icon_found';
223 $flags='x';
224 } else {
225 if ($hidden) $string.='hidden';
226 if ($timing) $string.='timing';
227 if (!$string && $futuretiming) {
228 $string='futuretiming';
229 }
230
231 $flags.=
232 ($hidden ? 'h' : '').
233 ($timing ? 't' : '').
234 ($futuretiming ? 'f' : '').
235 ($user ? 'u' : '').
236 ($protectSection ? 'p' : '').
237 ($shaded ? 's' : '');
238 }
239
240 // Create tagged icon file name:
241 $iconFileName_stateTagged = ereg_replace('.([[:alnum:]]+)$','__'.$flags.'.\1',basename($iconfile));
242
243 // Check if tagged icon file name exists (a tagget icon means the icon base name with the flags added between body and extension of the filename, prefixed with underscore)
244 if (@is_file(dirname($absfile).'/'.$iconFileName_stateTagged)) { // Look for [iconname]_xxxx.[ext]
245 return dirname($iconfile).'/'.$iconFileName_stateTagged;
246 } elseif ($doNotGenerateIcon) { // If no icon generation can be done, try to look for the _X icon:
247 $iconFileName_X = ereg_replace('.([[:alnum:]]+)$','__x.\1',basename($iconfile));
248 if (@is_file(dirname($absfile).'/'.$iconFileName_X)) {
249 return dirname($iconfile).'/'.$iconFileName_X;
250 } else {
251 return 'gfx/i/no_icon_found.gif';
252 }
253 } else { // Otherwise, create the icon:
254 $theRes = t3lib_iconWorks::makeIcon($GLOBALS['BACK_PATH'].$iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
255 return $theRes;
256 }
257 } else {
258 return $iconfile;
259 }
260 }
261
262 /**
263 * Returns the src=... for the input $src value OR any alternative found in $TBE_STYLES['skinImg']
264 * Used for skinning the TYPO3 backend with an alternative set of icons
265 * Usage: 336
266 *
267 * @param string Current backpath to PATH_typo3 folder
268 * @param string Icon file name relative to PATH_typo3 folder
269 * @param string Default width/height, defined like 'width="12" height="14"'
270 * @param integer Mode: 0 (zero) is default and returns src/width/height. 1 returns value of src+backpath, 2 returns value of w/h.
271 * @return string Returns ' src="[backPath][src]" [wHattribs]'
272 * @see skinImgFile()
273 */
274 function skinImg($backPath,$src,$wHattribs='',$outputMode=0) {
275
276 // Setting source key. If the icon is refered to inside an extension, we homogenize the prefix to "ext/":
277 $srcKey = ereg_replace('^(\.\.\/typo3conf\/ext|sysext|ext)\/','ext/',$src);
278 #if ($src!=$srcKey)debug(array($src,$srcKey));
279
280 // LOOKING for alternative icons:
281 if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) { // Slower or faster with is_array()? Could be used.
282 list($src,$wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
283 } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) { // Otherwise, test if auto-detection is enabled:
284
285 // Search for alternative icon automatically:
286 $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
287 $scaleFactor = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ? $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] : 1; // Scaling factor
288 $lookUpName = $fExt ? ereg_replace('\.[[:alnum:]]+$','',$srcKey).'.'.$fExt : $srcKey; // Set filename to look for
289
290 // If file is found:
291 if (@is_file($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'].$lookUpName)) { // If there is a file...
292 $iInfo = @getimagesize($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'].$lookUpName); // Get width/height:
293
294 // Set $src and $wHattribs:
295 $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'].$lookUpName;
296 $wHattribs = 'width="'.round($iInfo[0]*$scaleFactor).'" height="'.round($iInfo[1]*$scaleFactor).'"';
297 }
298
299 // In anycase, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function, regardless of whether it points to a alternative icon or just the current.
300 $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src,$wHattribs); // Set default...
301 }
302
303 // DEBUG: This doubles the size of all icons - for testing/debugging:
304 # if (ereg('^width="([0-9]+)" height="([0-9]+)"$',$wHattribs,$reg)) $wHattribs='width="'.($reg[1]*2).'" height="'.($reg[2]*2).'"';
305
306
307 // rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
308 $matches = array();
309 $srcBasename = basename($src);
310 if (preg_match('/(.*)_i(\....)$/', $srcBasename, $matches)) {
311 $temp_path = dirname(PATH_thisScript).'/';
312 if(!@is_file($temp_path.$backPath.$src)) {
313 $srcOrg = preg_replace('/_i'.preg_quote($matches[2]).'$/', $matches[2], $src);
314 $src = t3lib_iconWorks::makeIcon($backPath.$srcOrg, 'disabled', 0, false, $temp_path.$backPath.$srcOrg, $srcBasename);
315 }
316 }
317
318
319 // Return icon source/wHattributes:
320 $output = '';
321 switch($outputMode) {
322 case 0:
323 $output = ' src="'.$backPath.$src.'" '.$wHattribs;
324 break;
325 case 1:
326 $output = $backPath.$src;
327 break;
328 case 2:
329 $output = $wHattribs;
330 break;
331 }
332 return $output;
333 }
334
335
336
337
338
339
340
341
342
343
344
345 /***********************************
346 *
347 * Other functions
348 *
349 ***********************************/
350
351 /**
352 * Creates the icon file for the function getIcon()
353 *
354 * @param string Original unprocessed Icon file, relative path to PATH_typo3
355 * @param string Mode string, eg. "deleted" or "futuretiming" determining how the icon will look
356 * @param integer The number of the fe_group record uid if applicable
357 * @param boolean Flag determines if the protected-section icon should be applied.
358 * @param string Absolute path to file from which to create the icon.
359 * @param string The filename that this icon should have had, basically [icon base name]_[flags].[extension] - used for part of temporary filename
360 * @return string Filename relative to PATH_typo3
361 * @access private
362 */
363 function makeIcon($iconfile,$mode, $user, $protectSection,$absFile,$iconFileName_stateTagged) {
364 $iconFileName = 'icon_'.t3lib_div::shortMD5($iconfile.'|'.$mode.'|-'.$user.'|'.$protectSection).'_'.$iconFileName_stateTagged.'.'.($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']?'png':'gif');
365 $mainpath = '../typo3temp/'.$iconFileName;
366 $path = PATH_site.'typo3temp/'.$iconFileName;
367
368
369 if (@file_exists(PATH_typo3.'icons/'.$iconFileName)) { // Returns if found in typo3/icons/
370 return 'icons/'.$iconFileName;
371 } elseif (@file_exists($path)) { // Returns if found in ../typo3temp/icons/
372 return $mainpath;
373 } else { // Makes icon:
374 if (@file_exists($absFile)) {
375 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
376
377 // Create image pointer, if possible
378 $im = t3lib_iconworks::imagecreatefrom($absFile);
379 if ($im<0) return $iconfile;
380
381 // Converting to gray scale, dimming the icon:
382 if (($mode=='disabled') OR ($mode!='futuretiming' && $mode!='no_icon_found' && !(!$mode && $user))) {
383 for ($c=0; $c<ImageColorsTotal($im); $c++) {
384 $cols = ImageColorsForIndex($im,$c);
385 $newcol = round(($cols['red']+$cols['green']+$cols['blue'])/3);
386 $lighten = ($mode=='disabled') ? 2.5 : 2;
387 $newcol = round(255-((255-$newcol)/$lighten));
388 ImageColorSet($im,$c,$newcol,$newcol,$newcol);
389 }
390 }
391 // Applying user icon, if there are access control on the item:
392 if ($user) {
393 if ($user < 100) { // Apply user number only if lower than 100
394 $black = ImageColorAllocate($im, 0,0,0);
395 imagefilledrectangle($im, 0,0,(($user>10)?9:5),8,$black);
396
397 $white = ImageColorAllocate($im, 255,255,255);
398 imagestring($im, 1, 1, 1, $user, $white);
399 }
400
401 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_group.gif');
402 if ($ol_im<0) return $iconfile;
403
404 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
405 }
406 // Applying overlay based on mode:
407 if ($mode) {
408 unset($ol_im);
409 switch($mode) {
410 case 'deleted':
411 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_deleted.gif');
412 break;
413 case 'futuretiming':
414 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_timing.gif');
415 break;
416 case 'timing':
417 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_timing.gif');
418 break;
419 case 'hiddentiming':
420 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_hidden_timing.gif');
421 break;
422 case 'no_icon_found':
423 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_no_icon_found.gif');
424 break;
425 case 'disabled':
426 // is already greyed - nothing more
427 $ol_im = 0;
428 break;
429 case 'hidden':
430 default:
431 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_hidden.gif');
432 break;
433 }
434 if ($ol_im<0) return $iconfile;
435 if ($ol_im) {
436 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
437 }
438 }
439 // Protect-section icon:
440 if ($protectSection) {
441 $ol_im = t3lib_iconworks::imagecreatefrom($GLOBALS['BACK_PATH'].'gfx/overlay_sub5.gif');
442 if ($ol_im<0) return $iconfile;
443 t3lib_iconworks::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
444 }
445
446 // Create the image as file, destroy GD image and return:
447 @t3lib_iconWorks::imagemake($im, $path);
448 t3lib_div::gif_compress($path, 'IM');
449 ImageDestroy($im);
450 return $mainpath;
451 } else {
452 return $iconfile;
453 }
454 } else {
455 return $GLOBALS['BACK_PATH'].'gfx/fileicons/default.gif';
456 }
457 }
458 }
459
460 /**
461 * The necessity of using this function for combining two images if GD is version 2 is that
462 * GD2 cannot manage to combine two indexed-color images without totally spoiling everything.
463 * In class.t3lib_stdgraphic this was solved by combining the images onto a first created true color image
464 * However it has turned out that this method will not work if the indexed png-files contains transparency.
465 * So I had to turn my attention to ImageMagick - my 'enemy of death'.
466 * And so it happend - ImageMagick is now used to combine my two indexed-color images with transparency. And that works.
467 * Of course it works only if ImageMagick is able to create valid png-images - which you cannot be sure of with older versions (still 5+)
468 * The only drawback is (apparently) that IM creates true-color png's. The transparency of these will not be shown by MSIE on windows at this time (although it's straight 0%/100% transparency!) and the file size may be larger.
469 *
470 * For parameters, see PHP function "imagecopyresized()"
471 *
472 * @param pointer see PHP function "imagecopyresized()"
473 * @param pointer see PHP function "imagecopyresized()"
474 * @param integer see PHP function "imagecopyresized()"
475 * @param integer see PHP function "imagecopyresized()"
476 * @param integer 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 * @return void
483 * @access private
484 */
485 function imagecopyresized(&$im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h) {
486 imagecopyresized($im, $cpImg, $Xstart, $Ystart, $cpImgCutX, $cpImgCutY, $w, $h, $w, $h);
487 }
488
489 /**
490 * Create new image pointer from input file (either gif/png, in case the wrong format it is converted by t3lib_div::read_png_gif())
491 *
492 * @param string Absolute filename of the image file from which to start the icon creation.
493 * @return mixed If success, image pointer, otherwise "-1"
494 * @access private
495 * @see t3lib_div::read_png_gif
496 */
497 function imagecreatefrom($file) {
498 $file = t3lib_div::read_png_gif($file,$GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']);
499 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
500 return $file ? imagecreatefrompng($file) : -1;
501 } else {
502 return $file ? imagecreatefromgif($file) : -1;
503 }
504 }
505
506 /**
507 * Write the icon in $im pointer to $path
508 *
509 * @param pointer Pointer to GDlib image resource
510 * @param string Absolute path to the filename in which to write the icon.
511 * @return void
512 * @access private
513 */
514 function imagemake($im, $path) {
515 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
516 @ImagePng($im, $path);
517 } else {
518 @ImageGif($im, $path);
519 }
520 }
521 }
522 ?>