[BUGFIX] Regression in t3lib_iconWorks::imagecopyresized
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Utility / IconUtility.php
1 <?php
2 namespace TYPO3\CMS\Backend\Utility;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Contains class for icon generation in the backend
31 * This library has functions that returns - and if necessary creates - the icon for an element in TYPO3
32 *
33 * Expects global vars:
34 * - $BACK_PATH
35 * - PATH_typo3
36 * - $TCA, $PAGES_TYPES
37 *
38 *
39 * Notes:
40 * These functions are strongly related to the interface of TYPO3.
41 * The class is included in eg. init.php
42 * ALL functions called without making a class instance, eg. "t3lib_iconWorks::getIconImage()"
43 *
44 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
45 * @package TYPO3
46 * @subpackage t3lib
47 */
48 class IconUtility {
49
50 static public $fileSpriteIconNames = array(
51 'htm' => 'mimetypes-text-html',
52 'html' => 'mimetypes-text-html',
53 'css' => 'mimetypes-text-css',
54 'js' => 'mimetypes-text-js',
55 'csv' => 'mimetypes-text-csv',
56 'php' => 'mimetypes-text-php',
57 'php6' => 'mimetypes-text-php',
58 'php5' => 'mimetypes-text-php',
59 'php4' => 'mimetypes-text-php',
60 'php3' => 'mimetypes-text-php',
61 'inc' => 'mimetypes-text-php',
62 'ts' => 'mimetypes-text-ts',
63 'txt' => 'mimetypes-text-text',
64 'class' => 'mimetypes-text-text',
65 'tmpl' => 'mimetypes-text-text',
66 'jpg' => 'mimetypes-media-image',
67 'jpeg' => 'mimetypes-media-image',
68 'gif' => 'mimetypes-media-image',
69 'png' => 'mimetypes-media-image',
70 'bmp' => 'mimetypes-media-image',
71 'tif' => 'mimetypes-media-image',
72 'tga' => 'mimetypes-media-image',
73 'psd' => 'mimetypes-media-image',
74 'eps' => 'mimetypes-media-image',
75 'avi' => 'mimetypes-media-video',
76 'mpg' => 'mimetypes-media-video',
77 'mpeg' => 'mimetypes-media-video',
78 'mov' => 'mimetypes-media-video',
79 'wav' => 'mimetypes-media-audio',
80 'mp3' => 'mimetypes-media-audio',
81 'mid' => 'mimetypes-media-audio',
82 'swf' => 'mimetypes-media-flash',
83 'swa' => 'mimetypes-media-flash',
84 'exe' => 'mimetypes-executable-executable',
85 'com' => 'mimetypes-executable-executable',
86 't3x' => 'mimetypes-compressed',
87 't3d' => 'mimetypes-compressed',
88 'zip' => 'mimetypes-compressed',
89 'tgz' => 'mimetypes-compressed',
90 'gz' => 'mimetypes-compressed',
91 'pdf' => 'mimetypes-pdf',
92 'doc' => 'mimetypes-word',
93 'dot' => 'mimetypes-word',
94 'docm' => 'mimetypes-word',
95 'docx' => 'mimetypes-word',
96 'dotm' => 'mimetypes-word',
97 'dotx' => 'mimetypes-word',
98 'sxw' => 'mimetypes-word',
99 'rtf' => 'mimetypes-word',
100 'xls' => 'mimetypes-excel',
101 'xlsm' => 'mimetypes-excel',
102 'xlsx' => 'mimetypes-excel',
103 'xltm' => 'mimetypes-excel',
104 'xltx' => 'mimetypes-excel',
105 'sxc' => 'mimetypes-excel',
106 'ppt' => 'mimetypes-powerpoint',
107 'pptm' => 'mimetypes-powerpoint',
108 'pptx' => 'mimetypes-powerpoint',
109 'potm' => 'mimetypes-powerpoint',
110 'potx' => 'mimetypes-powerpoint',
111 'mount' => 'apps-filetree-mount',
112 'folder' => 'apps-filetree-folder-default',
113 'default' => 'mimetypes-other-other'
114 );
115
116 /**
117 * Returns an icon image tag, 18x16 pixels, based on input information.
118 * This function is recommended to use in your backend modules.
119 *
120 * @param string $table The table name
121 * @param array $row The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
122 * @param string $backPath The backpath to the main TYPO3 directory (relative path back to PATH_typo3)
123 * @param string $params Additional attributes for the image tag
124 * @param boolean $shaded If set, the icon will be grayed/shaded
125 * @return string <img>-tag
126 * @see getIcon()
127 */
128 static public function getIconImage($table, $row = array(), $backPath, $params = '', $shaded = FALSE) {
129 $str = '<img' . self::skinImg($backPath, self::getIcon($table, $row, $shaded), 'width="18" height="16"') . (trim($params) ? ' ' . trim($params) : '');
130 if (!stristr($str, 'alt="')) {
131 $str .= ' alt=""';
132 }
133 $str .= ' />';
134 return $str;
135 }
136
137 /**
138 * Creates the icon for input table/row
139 * Returns filename for the image icon, relative to PATH_typo3
140 *
141 * @param string $table The table name
142 * @param array $row The table row ("enablefields" are at least needed for correct icon display and for pages records some more fields in addition!)
143 * @param boolean $shaded If set, the icon will be grayed/shaded
144 * @return string Icon filename
145 * @see getIconImage()
146 */
147 static public function getIcon($table, $row = array(), $shaded = FALSE) {
148 // Flags
149 // If set, then the usergroup number will NOT be printed unto the icon. NOTICE.
150 // The icon is generated only if a default icon for groups is not found... So effectively this is ineffective.
151 $doNotRenderUserGroupNumber = TRUE;
152 // Shadow
153 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
154 switch ((int) $row['t3ver_state']) {
155 case 1:
156 return 'gfx/i/shadow_hide.png';
157 break;
158 case 2:
159 return 'gfx/i/shadow_delete.png';
160 break;
161 case 3:
162 return 'gfx/i/shadow_moveto_plh.png';
163 break;
164 case 4:
165 return 'gfx/i/shadow_moveto_pointer.png';
166 break;
167 }
168 }
169 // First, find the icon file name. This can depend on configuration in TCA, field values and more:
170 if ($table == 'pages') {
171 $iconfile = $GLOBALS['PAGES_TYPES'][$row['doktype']]['icon'];
172 if (!$iconfile) {
173 $iconfile = $GLOBALS['PAGES_TYPES']['default']['icon'];
174 }
175 } else {
176 if (!($iconfile = $GLOBALS['TCA'][$table]['ctrl']['typeicons'][$row[$GLOBALS['TCA'][$table]['ctrl']['typeicon_column']]])) {
177 $iconfile = $GLOBALS['TCA'][$table]['ctrl']['iconfile'] ? $GLOBALS['TCA'][$table]['ctrl']['iconfile'] : $table . '.gif';
178 }
179 }
180 // Setting path of iconfile if not already set. Default is "gfx/i/"
181 if (!strstr($iconfile, '/')) {
182 $iconfile = 'gfx/i/' . $iconfile;
183 }
184 // Setting the absolute path where the icon should be found as a file:
185 if (substr($iconfile, 0, 3) == '../') {
186 $absfile = PATH_site . substr($iconfile, 3);
187 } else {
188 $absfile = PATH_typo3 . $iconfile;
189 }
190 // Initializing variables, all booleans except otherwise stated:
191 $hidden = FALSE;
192 $timing = FALSE;
193 $futuretiming = FALSE;
194 // In fact an integer value
195 $user = FALSE;
196 $deleted = FALSE;
197 // Set, if a page-record (only pages!) has the extend-to-subpages flag set.
198 $protectSection = FALSE;
199 $noIconFound = $row['_NO_ICON_FOUND'] ? TRUE : FALSE;
200 // + $shaded which is also boolean!
201 // Icon state based on "enableFields":
202 if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
203 $enCols = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns'];
204 // If "hidden" is enabled:
205 if ($enCols['disabled']) {
206 if ($row[$enCols['disabled']]) {
207 $hidden = TRUE;
208 }
209 }
210 // If a "starttime" is set and higher than current time:
211 if ($enCols['starttime']) {
212 if ($GLOBALS['EXEC_TIME'] < intval($row[$enCols['starttime']])) {
213 $timing = TRUE;
214 // And if "endtime" is NOT set:
215 if (intval($row[$enCols['endtime']]) == 0) {
216 $futuretiming = TRUE;
217 }
218 }
219 }
220 // If an "endtime" is set:
221 if ($enCols['endtime']) {
222 if (intval($row[$enCols['endtime']]) > 0) {
223 if (intval($row[$enCols['endtime']]) < $GLOBALS['EXEC_TIME']) {
224 // End-timing applies at this point.
225 $timing = TRUE;
226 } else {
227 // End-timing WILL apply in the future for this element.
228 $futuretiming = TRUE;
229 }
230 }
231 }
232 // If a user-group field is set:
233 if ($enCols['fe_group']) {
234 $user = $row[$enCols['fe_group']];
235 if ($user && $doNotRenderUserGroupNumber) {
236 $user = 100;
237 }
238 }
239 }
240 // If "deleted" flag is set (only when listing records which are also deleted!)
241 if ($col = $row[$GLOBALS['TCA'][$table]['ctrl']['delete']]) {
242 $deleted = TRUE;
243 }
244 // Detecting extendToSubpages (for pages only)
245 if ($table == 'pages' && $row['extendToSubpages'] && ($hidden || $timing || $futuretiming || $user)) {
246 $protectSection = TRUE;
247 }
248 // If ANY of the booleans are set it means we have to alter the icon:
249 if ($hidden || $timing || $futuretiming || $user || $deleted || $shaded || $noIconFound) {
250 $flags = '';
251 $string = '';
252 if ($deleted) {
253 $string = 'deleted';
254 $flags = 'd';
255 } elseif ($noIconFound) {
256 // This is ONLY for creating icons with "?" on easily...
257 $string = 'no_icon_found';
258 $flags = 'x';
259 } else {
260 if ($hidden) {
261 $string .= 'hidden';
262 }
263 if ($timing) {
264 $string .= 'timing';
265 }
266 if (!$string && $futuretiming) {
267 $string = 'futuretiming';
268 }
269 $flags .= ($hidden ? 'h' : '') . ($timing ? 't' : '') . ($futuretiming ? 'f' : '') . ($user ? 'u' : '') . ($protectSection ? 'p' : '') . ($shaded ? 's' : '');
270 }
271 // Create tagged icon file name:
272 $iconFileName_stateTagged = preg_replace('/.([[:alnum:]]+)$/', '__' . $flags . '.\\1', basename($iconfile));
273 // Check if tagged icon file name exists (a tagged icon means the icon base name with the flags added between body and extension of the filename, prefixed with underscore)
274 if (@is_file((dirname($absfile) . '/' . $iconFileName_stateTagged)) || @is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . '/' . dirname($iconfile) . '/' . $iconFileName_stateTagged))) {
275 // Look for [iconname]_xxxx.[ext]
276 return dirname($iconfile) . '/' . $iconFileName_stateTagged;
277 } else {
278 // Otherwise, create the icon:
279 $theRes = self::makeIcon($GLOBALS['BACK_PATH'] . $iconfile, $string, $user, $protectSection, $absfile, $iconFileName_stateTagged);
280 return $theRes;
281 }
282 } else {
283 return $iconfile;
284 }
285 }
286
287 /**
288 * Returns the src=... for the input $src value OR any alternative found in $TBE_STYLES['skinImg']
289 * Used for skinning the TYPO3 backend with an alternative set of icons
290 *
291 * @param string $backPath Current backpath to PATH_typo3 folder
292 * @param string $src Icon file name relative to PATH_typo3 folder
293 * @param string $wHattribs Default width/height, defined like 'width="12" height="14"'
294 * @param integer $outputMode Mode: 0 (zero) is default and returns src/width/height. 1 returns value of src+backpath, 2 returns value of w/h.
295 * @return string Returns ' src="[backPath][src]" [wHattribs]'
296 * @see skinImgFile()
297 */
298 static public function skinImg($backPath, $src, $wHattribs = '', $outputMode = 0) {
299 static $cachedSkinImages = array();
300 $imageId = md5($backPath . $src . $wHattribs . $outputMode);
301 if (isset($cachedSkinImages[$imageId])) {
302 return $cachedSkinImages[$imageId];
303 }
304 // Setting source key. If the icon is refered to inside an extension, we homogenize the prefix to "ext/":
305 $srcKey = preg_replace('/^(\\.\\.\\/typo3conf\\/ext|sysext|ext)\\//', 'ext/', $src);
306 // LOOKING for alternative icons:
307 if ($GLOBALS['TBE_STYLES']['skinImg'][$srcKey]) {
308 // Slower or faster with is_array()? Could be used.
309 list($src, $wHattribs) = $GLOBALS['TBE_STYLES']['skinImg'][$srcKey];
310 } elseif ($GLOBALS['TBE_STYLES']['skinImgAutoCfg']) {
311 // Otherwise, test if auto-detection is enabled:
312 // Search for alternative icon automatically:
313 $fExt = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['forceFileExtension'];
314 $scaleFactor = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] ? $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['scaleFactor'] : 1;
315 // Scaling factor
316 $lookUpName = $fExt ? preg_replace('/\\.[[:alnum:]]+$/', '', $srcKey) . '.' . $fExt : $srcKey;
317 // Set filename to look for
318 if ($fExt && !@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
319 // Fallback to original filename if icon with forced extension doesn't exists
320 $lookUpName = $srcKey;
321 }
322 // If file is found:
323 if (@is_file(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName))) {
324 // If there is a file...
325 $iInfo = @getimagesize(($GLOBALS['TBE_STYLES']['skinImgAutoCfg']['absDir'] . $lookUpName));
326 // Get width/height:
327 // Set $src and $wHattribs:
328 $src = $GLOBALS['TBE_STYLES']['skinImgAutoCfg']['relDir'] . $lookUpName;
329 $wHattribs = 'width="' . round($iInfo[0] * $scaleFactor) . '" height="' . round($iInfo[1] * $scaleFactor) . '"';
330 }
331 // In any case, set currect src / wHattrib - this way we make sure that an entry IS found next time we hit the function,
332 // regardless of whether it points to a alternative icon or just the current.
333 $GLOBALS['TBE_STYLES']['skinImg'][$srcKey] = array($src, $wHattribs);
334 }
335 // Rendering disabled (greyed) icons using _i (inactive) as name suffix ("_d" is already used)
336 $matches = array();
337 $srcBasename = basename($src);
338 if (preg_match('/(.*)_i(\\....)$/', $srcBasename, $matches)) {
339 $temp_path = dirname(PATH_thisScript) . '/';
340 if (!@is_file(($temp_path . $backPath . $src))) {
341 $srcOrg = preg_replace('/_i' . preg_quote($matches[2]) . '$/', $matches[2], $src);
342 $src = self::makeIcon($backPath . $srcOrg, 'disabled', 0, FALSE, $temp_path . $backPath . $srcOrg, $srcBasename);
343 }
344 }
345 // Return icon source/wHattributes:
346 $output = '';
347 switch ($outputMode) {
348 case 0:
349 $output = ' src="' . $backPath . $src . '" ' . $wHattribs;
350 break;
351 case 1:
352 $output = $backPath . $src;
353 break;
354 case 2:
355 $output = $wHattribs;
356 break;
357 }
358 $cachedSkinImages[$imageId] = $output;
359 return $output;
360 }
361
362 /***********************************
363 *
364 * Other functions
365 *
366 ***********************************/
367 /**
368 * Creates the icon file for the function getIcon()
369 *
370 * @param string $iconfile Original unprocessed Icon file, relative path to PATH_typo3
371 * @param string $mode Mode string, eg. "deleted" or "futuretiming" determining how the icon will look
372 * @param integer $user The number of the fe_group record uid if applicable
373 * @param boolean $protectSection Flag determines if the protected-section icon should be applied.
374 * @param string $absFile Absolute path to file from which to create the icon.
375 * @param string $iconFileName_stateTagged The filename that this icon should have had, basically [icon base name]_[flags].[extension] - used for part of temporary filename
376 * @return string Filename relative to PATH_typo3
377 * @access private
378 */
379 static public function makeIcon($iconfile, $mode, $user, $protectSection, $absFile, $iconFileName_stateTagged) {
380 $iconFileName = 'icon_' . \TYPO3\CMS\Core\Utility\GeneralUtility::shortMD5(($iconfile . '|' . $mode . '|-' . $user . '|' . $protectSection)) . '_' . $iconFileName_stateTagged . '.' . ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png'] ? 'png' : 'gif');
381 $mainpath = '../typo3temp/' . $iconFileName;
382 $path = PATH_site . 'typo3temp/' . $iconFileName;
383 if (file_exists(PATH_typo3 . 'icons/' . $iconFileName)) {
384 // Returns if found in typo3/icons/
385 return 'icons/' . $iconFileName;
386 } elseif (file_exists($path)) {
387 // Returns if found in ../typo3temp/icons/
388 return $mainpath;
389 } else {
390 // Makes icon:
391 if (file_exists($absFile)) {
392 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib']) {
393 // Create image pointer, if possible
394 $im = self::imagecreatefrom($absFile);
395 if ($im < 0) {
396 return $iconfile;
397 }
398 // Converting to gray scale, dimming the icon:
399 if ($mode == 'disabled' or $mode != 'futuretiming' && $mode != 'no_icon_found' && !(!$mode && $user)) {
400 $totalImageColors = ImageColorsTotal($im);
401 for ($c = 0; $c < $totalImageColors; $c++) {
402 $cols = ImageColorsForIndex($im, $c);
403 $newcol = round(($cols['red'] + $cols['green'] + $cols['blue']) / 3);
404 $lighten = $mode == 'disabled' ? 2.5 : 2;
405 $newcol = round(255 - (255 - $newcol) / $lighten);
406 ImageColorSet($im, $c, $newcol, $newcol, $newcol);
407 }
408 }
409 // Applying user icon, if there are access control on the item:
410 if ($user) {
411 if ($user < 100) {
412 // Apply user number only if lower than 100
413 $black = ImageColorAllocate($im, 0, 0, 0);
414 imagefilledrectangle($im, 0, 0, $user > 10 ? 9 : 5, 8, $black);
415 $white = ImageColorAllocate($im, 255, 255, 255);
416 imagestring($im, 1, 1, 1, $user, $white);
417 }
418 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_group.gif');
419 if ($ol_im < 0) {
420 return $iconfile;
421 }
422 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
423 }
424 // Applying overlay based on mode:
425 if ($mode) {
426 unset($ol_im);
427 switch ($mode) {
428 case 'deleted':
429 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_deleted.gif');
430 break;
431 case 'futuretiming':
432 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_timing.gif');
433 break;
434 case 'timing':
435 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_timing.gif');
436 break;
437 case 'hiddentiming':
438 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_hidden_timing.gif');
439 break;
440 case 'no_icon_found':
441 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_no_icon_found.gif');
442 break;
443 case 'disabled':
444 // is already greyed - nothing more
445 $ol_im = 0;
446 break;
447 case 'hidden':
448
449 default:
450 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_hidden.gif');
451 break;
452 }
453 if ($ol_im < 0) {
454 return $iconfile;
455 }
456 if ($ol_im) {
457 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
458 }
459 }
460 // Protect-section icon:
461 if ($protectSection) {
462 $ol_im = self::imagecreatefrom($GLOBALS['BACK_PATH'] . 'gfx/overlay_sub5.gif');
463 if ($ol_im < 0) {
464 return $iconfile;
465 }
466 self::imagecopyresized($im, $ol_im, 0, 0, 0, 0, imagesx($ol_im), imagesy($ol_im), imagesx($ol_im), imagesy($ol_im));
467 }
468 // Create the image as file, destroy GD image and return:
469 @self::imagemake($im, $path);
470 \TYPO3\CMS\Core\Utility\GeneralUtility::gif_compress($path, 'IM');
471 ImageDestroy($im);
472 return $mainpath;
473 } else {
474 return $iconfile;
475 }
476 } else {
477 return $GLOBALS['BACK_PATH'] . 'gfx/fileicons/default.gif';
478 }
479 }
480 }
481
482 /**
483 * The necessity of using this function for combining two images if GD is version 2 is that
484 * GD2 cannot manage to combine two indexed-color images without totally spoiling everything.
485 * In class.t3lib_stdgraphic this was solved by combining the images onto a first created true color image
486 * However it has turned out that this method will not work if the indexed png-files contains transparency.
487 * So I had to turn my attention to ImageMagick - my 'enemy of death'.
488 * And so it happend - ImageMagick is now used to combine my two indexed-color images with transparency. And that works.
489 * 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+)
490 * 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.
491 *
492 * @param resource $destinationImage Destination image
493 * @param resource $sourceImage Source image
494 * @param integer $destinationX Destination x-coordinate
495 * @param integer $destinationY Destination y-coordinate
496 * @param integer $sourceX Source x-coordinate
497 * @param integer $sourceY Source y-coordinate
498 * @param integer $destinationWidth Destination width
499 * @param integer $destinationHeight Destination height
500 * @param integer $sourceWidth Source width
501 * @param integer $sourceHeight Source height
502 * @return void
503 * @access private
504 * @see t3lib_stdGraphic::imagecopyresized()
505 */
506 static public function imagecopyresized(&$destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight) {
507 imagecopyresized($destinationImage, $sourceImage, $destinationX, $destinationY, $sourceX, $sourceY, $destinationWidth, $destinationHeight, $sourceWidth, $sourceHeight);
508 }
509
510 /**
511 * Create new image pointer from input file (either gif/png, in case the wrong format it is converted by t3lib_div::read_png_gif())
512 *
513 * @param string $file Absolute filename of the image file from which to start the icon creation.
514 * @return mixed If success, image pointer, otherwise "-1
515 * @access private
516 * @see t3lib_div::read_png_gif
517 */
518 static public function imagecreatefrom($file) {
519 $file = \TYPO3\CMS\Core\Utility\GeneralUtility::read_png_gif($file, $GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']);
520 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
521 return $file ? imagecreatefrompng($file) : -1;
522 } else {
523 return $file ? imagecreatefromgif($file) : -1;
524 }
525 }
526
527 /**
528 * Write the icon in $im pointer to $path
529 *
530 * @param pointer $im Pointer to GDlib image resource
531 * @param string $path Absolute path to the filename in which to write the icon.
532 * @return void
533 * @access private
534 */
535 static public function imagemake($im, $path) {
536 if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['gdlib_png']) {
537 @ImagePng($im, $path);
538 } else {
539 @ImageGif($im, $path);
540 }
541 if (@is_file($path)) {
542 \TYPO3\CMS\Core\Utility\GeneralUtility::fixPermissions($path);
543 }
544 }
545
546 /**********************************************
547 * SPRITE ICON API
548 *
549 * The Sprite Icon API helps you to quickly get the HTML for any icon you want
550 * this is typically wrapped in a <span> tag with corresponding CSS classes that
551 * will be responsible for the
552 *
553 * There are three ways to use this API:
554 *
555 * 1) for any given TCA record
556 * $spriteIconHtml = t3lib_iconWorks::getSpriteIconForRecord('pages', $row);
557 *
558 * 2) for any given file
559 * $spriteIconHtml = t3lib_iconWorks::getSpriteIconForFile('myimage.png');
560 *
561 * 3) for any other icon you know the name
562 * $spriteIconHtml = t3lib_iconWorks::getSpriteIcon('actions-document-open');
563 *
564 **********************************************/
565 /**
566 * This generic method is used throughout the TYPO3 Backend to show icons in any variation which are not
567 * bound to any file type (see getSpriteIconForFile) or database record (see getSpriteIconForRecord)
568 *
569 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
570 * already to have a pre-defined background image, and the correct background-position to show
571 * the necessary icon.
572 *
573 * @param string $iconName The name of the icon to fetch
574 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
575 * @param array $overlays An associative array with the icon-name as key, and the options for this overlay as an array again (see the parameter $options again)
576 * @return string The full HTML tag (usually a <span>)
577 * @access public
578 */
579 static public function getSpriteIcon($iconName, array $options = array(), array $overlays = array()) {
580 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
581 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
582 // Deal with the overlays
583 if (count($overlays)) {
584 foreach ($overlays as $overlayIconName => $overlayOptions) {
585 $overlayOptions['html'] = $innerHtml;
586 $overlayOptions['class'] = (isset($overlayOptions['class']) ? $overlayOptions['class'] . ' ' : '') . 't3-icon-overlay';
587 $innerHtml = self::getSpriteIcon($overlayIconName, $overlayOptions);
588 }
589 }
590 // Check if whished icon is available
591 $iconName = in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable']) || $iconName == 'empty-empty' ? $iconName : 'status-status-icon-missing';
592 // Create the CSS class
593 $options['class'] = self::getSpriteIconClasses($iconName) . (isset($options['class']) ? ' ' . $options['class'] : '');
594 unset($options['html']);
595 unset($options['tagName']);
596 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
597 }
598
599 /**
600 * This method is used throughout the TYPO3 Backend to show icons for a file type
601 *
602 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
603 * already to have a pre-defined background image, and the correct background-position to show
604 * the necessary icon.
605 *
606 * @param string $fileExtension The name of the icon to fetch, can be a file extension, full file path or one of the special keywords "folder" or "mount
607 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
608 * @return string The full HTML tag (usually a <span>)
609 * @access public
610 */
611 static public function getSpriteIconForFile($fileExtension, array $options = array()) {
612 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
613 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
614 // Create the CSS class
615 $options['class'] = self::mapFileExtensionToSpriteIconClass($fileExtension) . (isset($options['class']) ? ' ' . $options['class'] : '');
616 unset($options['html']);
617 unset($options['tagName']);
618 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
619 }
620
621 /**
622 * Generates the spriteicon css classes name for a given path or fileExtension
623 * usually called from getSpriteIconForFile or ExtJs Provider
624 *
625 * @param string $fileExtension FileExtension can be jpg, gif etc, but also be 'mount' or 'folder', but can also be a full path which will be resolved then
626 * @return string The string of the CSS class, see t3lib_iconworks::$fileSpriteIconNames
627 * @access private
628 */
629 static public function mapFileExtensionToSpriteIconClass($fileExtension) {
630 return self::getSpriteIconClasses(self::mapFileExtensionToSpriteIconName($fileExtension));
631 }
632
633 /**
634 * Generates the spriteicon name for a given path or fileExtension
635 * usually called from mapFileExtensionToSpriteIconClass and tceforms
636 *
637 * @param string $fileExtension FileExtension can be jpg, gif etc, but also be 'mount' or 'folder', but can also be a full path which will be resolved then
638 * @return string The string of the CSS class, see t3lib_iconworks::$fileSpriteIconNames
639 * @access private
640 */
641 static public function mapFileExtensionToSpriteIconName($fileExtension) {
642 // If the file is a whole file with name etc (mainly, if it has a "." or a "/"),
643 // then it is checked whether it is a valid directory
644 if (strpos($fileExtension, '.') !== FALSE || strpos($fileExtension, '/') !== FALSE) {
645 // Check if it is a directory
646 $filePath = dirname(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('SCRIPT_FILENAME')) . '/' . $GLOBALS['BACK_PATH'] . $fileExtension;
647 $path = \TYPO3\CMS\Core\Utility\GeneralUtility::resolveBackPath($filePath);
648 if (is_dir($path) || substr($fileExtension, -1) === '/' || substr($fileExtension, -1) === '\\') {
649 $fileExtension = 'folder';
650 } else {
651 if (($pos = strrpos($fileExtension, '.')) !== FALSE) {
652 $fileExtension = strtolower(substr($fileExtension, $pos + 1));
653 } else {
654 $fileExtension = 'default';
655 }
656 }
657 }
658 // If the file extension is not valid
659 // then use the default one
660 if (!isset(self::$fileSpriteIconNames[$fileExtension])) {
661 $fileExtension = 'default';
662 }
663 $iconName = self::$fileSpriteIconNames[$fileExtension];
664 return $iconName;
665 }
666
667 /**
668 * This method is used throughout the TYPO3 Backend to show icons for a DB record
669 *
670 * Generates a HTML tag with proper CSS classes. The TYPO3 skin has defined these CSS classes
671 * already to have a pre-defined background image, and the correct background-position to show
672 * the necessary icon.
673 *
674 * @param string $table The TCA table name
675 * @param array $row The DB record of the TCA table
676 * @param array $options An associative array with additional options and attributes for the tag. by default, the key is the name of the attribute, and the value is the parameter string that is set. However, there are some additional special reserved keywords that can be used as keys: "html" (which is the HTML that will be inside the icon HTML tag), "tagName" (which is an alternative tagName than "span"), and "class" (additional class names that will be merged with the sprite icon CSS classes)
677 * @return string The full HTML tag (usually a <span>)
678 * @access public
679 */
680 static public function getSpriteIconForRecord($table, array $row, array $options = array()) {
681 $innerHtml = isset($options['html']) ? $options['html'] : NULL;
682 $tagName = isset($options['tagName']) ? $options['tagName'] : NULL;
683 // Overlay this record icon with the status of the row
684 $overlaySpriteIconName = self::mapRecordOverlayToSpriteIconName($table, $row);
685 if ($overlaySpriteIconName) {
686 $overlayOptions = array(
687 'html' => $innerHtml,
688 'class' => 't3-icon-overlay'
689 );
690 $innerHtml = self::getSpriteIcon($overlaySpriteIconName, $overlayOptions);
691 }
692 // Fetch the name for the CSS class, based on the $row
693 $options['class'] = self::mapRecordTypeToSpriteIconClass($table, $row) . (isset($options['class']) ? ' ' . $options['class'] : '');
694 unset($options['html']);
695 unset($options['tagName']);
696 return self::buildSpriteHtmlIconTag($options, $innerHtml, $tagName);
697 }
698
699 /**
700 * this helper functions looks up the column that is used for the type of
701 * the chosen TCA table. And then fetches the corresponding class
702 * based on the chosen iconsprite class in this TCA
703 * The TCA looks up
704 * - [ctrl][typeicon_column]
705 * -
706 * This method solely takes care of the type of this record, not any
707 * statuses, used for overlays.
708 * You should not use this directly besides if you need classes for ExtJS iconCls.
709 *
710 * see t3lib/stddb/tables.php for an example with the TCA table "pages"
711 *
712 * @param string $table The TCA table
713 * @param array $row The selected record
714 * @return string The CSS class for the sprite icon of that DB record
715 * @access private
716 */
717 static public function mapRecordTypeToSpriteIconClass($table, array $row) {
718 return self::getSpriteIconClasses(self::mapRecordTypeToSpriteIconName($table, $row));
719 }
720
721 /**
722 * this helper functions looks up the column that is used for the type of
723 * the chosen TCA table. And then fetches the corresponding iconname
724 * based on the chosen iconsprite class in this TCA
725 * The TCA looks up
726 * - [ctrl][typeicon_column]
727 * -
728 * This method solely takes care of the type of this record, not any
729 * statuses, used for overlays.
730 * You should not use this directly besides if you need it in tceforms/core classes
731 *
732 * see t3lib/stddb/tables.php for an example with the TCA table "pages"
733 *
734 * @param string $tableThe TCA table
735 * @param array $row The selected record
736 * @return string The CSS class for the sprite icon of that DB record
737 * @access private
738 */
739 static public function mapRecordTypeToSpriteIconName($table, array $row) {
740 $recordType = array();
741 $ref = NULL;
742 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_column'])) {
743 $column = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column'];
744 if (isset($row[$column])) {
745 $recordType[1] = $row[$column];
746 } else {
747 $recordType[1] = 'default';
748 }
749 // Workaround to give nav_hide pages a complete different icon
750 // Although it's not a separate doctype
751 // and to give root-pages an own icon
752 if ($table === 'pages') {
753 if ($row['nav_hide']) {
754 $recordType[2] = $recordType[1] . '-hideinmenu';
755 }
756 if ($row['is_siteroot']) {
757 $recordType[3] = $recordType[1] . '-root';
758 }
759 if ($row['module']) {
760 $recordType[4] = 'contains-' . $row['module'];
761 }
762 }
763 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
764 foreach ($recordType as $key => $type) {
765 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type])) {
766 $recordType[$key] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'][$type];
767 } else {
768 unset($recordType[$key]);
769 }
770 }
771 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
772 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask'])) {
773 $recordType[5] = str_replace('###TYPE###', $row[$column], $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['mask']);
774 }
775 if (isset($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'])) {
776 $parameters = array('row' => $row);
777 $recordType[6] = \TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['userFunc'], $parameters, $ref);
778 }
779 } else {
780 foreach ($recordType as &$type) {
781 $type = 'tcarecords-' . $table . '-' . $type;
782 }
783 unset($type);
784 $recordType[0] = 'tcarecords-' . $table . '-default';
785 }
786 } else {
787 if (is_array($GLOBALS['TCA'][$table]['ctrl']['typeicon_classes'])) {
788 $recordType[0] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_classes']['default'];
789 } else {
790 $recordType[0] = 'tcarecords-' . $table . '-default';
791 }
792 }
793 krsort($recordType);
794 if (is_array($GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
795 foreach ($recordType as $iconName) {
796 if (in_array($iconName, $GLOBALS['TBE_STYLES']['spriteIconApi']['iconsAvailable'])) {
797 return $iconName;
798 }
799 }
800 }
801 return 'status-status-icon-missing';
802 }
803
804 /**
805 * this helper functions checks if the DB record ($row) has any special status
806 * based on the TCA settings like hidden, starttime etc, and then returns a specific
807 * Sprite icon class for the overlay of this DB record
808 * This method solely takes care of the overlay of this record, not any type
809 *
810 * Please note that this only returns one overlay, one status, that is prioritized
811 * by $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayPriorities']
812 * We wanted to not have these icons blown over by tons of overlays, so this is limited
813 * to just one.
814 *
815 * see t3lib/stddb/DefaultSettings for the default options, you will find
816 * $GLOBALS['TYPO3_CONF_VARS']['BE']['spriteIconRecordOverlayNames'] that shows
817 * the list of CSS classes that will be used for the sprites, mapped to the statuses here
818 *
819 * @param string $table The TCA table
820 * @param array $row The selected record
821 * @return string The CSS class for the sprite icon of that DB record
822 * @access private
823 */
824 static public function mapRecordOverlayToSpriteIconName($table, array $row) {
825 $tcaCtrl = $GLOBALS['TCA'][$table]['ctrl'];
826 // Calculate for a given record the actual visibility at the moment
827 $status = array(
828 'hidden' => FALSE,
829 'starttime' => FALSE,
830 'endtime' => FALSE,
831 'futureendtime' => FALSE,
832 'fe_group' => FALSE,
833 'deleted' => FALSE,
834 'protectedSection' => FALSE,
835 'nav_hide' => $row['nav_hide'] ? TRUE : FALSE,
836 'noIconFound' => $row['_NO_ICON_FOUND'] ? TRUE : FALSE
837 );
838 // Icon state based on "enableFields":
839 if (is_array($tcaCtrl['enablecolumns'])) {
840 $enCols = $tcaCtrl['enablecolumns'];
841 // If "hidden" is enabled:
842 if ($tcaCtrl['enablecolumns']['disabled'] && $row[$tcaCtrl['enablecolumns']['disabled']]) {
843 $status['hidden'] = TRUE;
844 }
845 // If a "starttime" is set and higher than current time:
846 if ($tcaCtrl['enablecolumns']['starttime'] && $GLOBALS['EXEC_TIME'] < intval($row[$tcaCtrl['enablecolumns']['starttime']])) {
847 $status['starttime'] = TRUE;
848 }
849 // If an "endtime" is set
850 if ($tcaCtrl['enablecolumns']['endtime']) {
851 if (intval($row[$tcaCtrl['enablecolumns']['endtime']]) > 0) {
852 if (intval($row[$tcaCtrl['enablecolumns']['endtime']]) < $GLOBALS['EXEC_TIME']) {
853 // End-timing applies at this point.
854 $status['endtime'] = TRUE;
855 } else {
856 // End-timing WILL apply in the future for this element.
857 $status['futureendtime'] = TRUE;
858 }
859 }
860 }
861 // If a user-group field is set
862 if ($tcaCtrl['enablecolumns']['fe_group'] && $row[$tcaCtrl['enablecolumns']['fe_group']]) {
863 $status['fe_group'] = TRUE;
864 }
865 }
866 // If "deleted" flag is set (only when listing records which are also deleted!)
867 if ($row[$tcaCtrl['delete']]) {
868 $status['deleted'] = TRUE;
869 }
870 // Detecting extendToSubpages (for pages only)
871 if ($table == 'pages' && $row['extendToSubpages']) {
872 $status['protectedSection'] = TRUE;
873 }
874 // Hook: allow some other process to influence the choice of icon overlay
875 // The method called receives the table name, the current row and the current status array as parameters
876 // The status array should be passed as a reference and in order to be modified within the hook
877 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'])) {
878 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_iconworks.php']['overrideIconOverlay'] as $classRef) {
879 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classRef);
880 if (method_exists($hookObject, 'overrideIconOverlay')) {
881 $hookObject->overrideIconOverlay($table, $row, $status);
882 }
883 }
884 }
885 // Now only show the status with the highest priority
886 $priorities = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayPriorities'];
887 $iconName = '';
888 if (is_array($priorities)) {
889 foreach ($priorities as $priority) {
890 if ($status[$priority]) {
891 $iconName = $GLOBALS['TBE_STYLES']['spriteIconApi']['spriteIconRecordOverlayNames'][$priority];
892 break;
893 }
894 }
895 }
896 return $iconName;
897 }
898
899 /**
900 * generic method to create the final CSS classes based on the sprite icon name
901 * with the base class and splits the name into parts
902 * is usually called by the methods that are responsible for fetching the names
903 * out of the file name, or the record type
904 *
905 * @param string $name Iconname like 'actions-document-new'
906 * @return string A list of all CSS classes needed for the HTML tag
907 */
908 static public function getSpriteIconClasses($iconName) {
909 $cssClasses = ($baseCssClass = 't3-icon');
910 $parts = explode('-', $iconName);
911 if (count($parts) > 1) {
912 // Will be something like "t3-icon-actions"
913 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0]);
914 // Will be something like "t3-icon-actions-document"
915 $cssClasses .= ' ' . ($baseCssClass . '-' . $parts[0] . '-' . $parts[1]);
916 // Will be something like "t3-icon-document-new"
917 $cssClasses .= ' ' . ($baseCssClass . '-' . substr($iconName, (strlen($parts[0]) + 1)));
918 }
919 return $cssClasses;
920 }
921
922 /**
923 * low level function that generates the HTML tag for the sprite icon
924 * is usually called by the three API classes (getSpriteIcon, getSpriteIconForFile, getSpriteIconForRecord)
925 * it does not care about classes or anything else, but just plainly builds the HTML tag
926 *
927 * @param array $tagAttributes An associative array of additional tagAttributes for the HTML tag
928 * @param string $innerHtml The content within the tag, a "&nbsp;" by default
929 * @param string $tagName The name of the HTML element that should be used (span by default)
930 * @return string The sprite html icon tag
931 */
932 static protected function buildSpriteHtmlIconTag(array $tagAttributes, $innerHtml = NULL, $tagName = NULL) {
933 $innerHtml = $innerHtml === NULL ? '&nbsp;' : $innerHtml;
934 $tagName = $tagName === NULL ? 'span' : $tagName;
935 $attributes = '';
936 foreach ($tagAttributes as $attribute => $value) {
937 $attributes .= ' ' . htmlspecialchars($attribute) . '="' . htmlspecialchars($value) . '"';
938 }
939 return '<' . $tagName . $attributes . '>' . $innerHtml . '</' . $tagName . '>';
940 }
941
942 }
943
944
945 ?>