|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2010-2011 Steffen Ritter <info@steffen-ritter.net> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 00028 00029 /** 00030 * sprite generator 00031 * 00032 * @author Steffen Ritter <info@steffen-ritter.net> 00033 * @package TYPO3 00034 * @subpackage t3lib 00035 */ 00036 00037 class t3lib_spritemanager_SpriteGenerator { 00038 /** 00039 * template creating CSS for the spritefile 00040 * 00041 * @var string 00042 */ 00043 protected $templateSprite = ' 00044 .###NAMESPACE###-###SPRITENAME### { 00045 background-image: url(\'###SPRITEURL###\') !important; 00046 height: ###DEFAULTHEIGHT###px; 00047 width: ###DEFAULTWIDTH###px; 00048 } 00049 '; 00050 00051 /** 00052 * 00053 * template creating CSS for position and size of a single icon 00054 * 00055 * @var string 00056 */ 00057 protected $templateIcon = '.###NAMESPACE###-###ICONNAME### { 00058 background-position: -###LEFT###px -###TOP###px !important; 00059 ###SIZE_INFO### 00060 } 00061 '; 00062 00063 /** 00064 * most common icon-width in the sprite 00065 * 00066 * @var int 00067 */ 00068 protected $defaultWidth = 0; 00069 00070 /** 00071 * most common icon-height in the sprite 00072 * 00073 * @var int 00074 */ 00075 protected $defaultHeight = 0; 00076 00077 /** 00078 * calculated width of the sprite 00079 * 00080 * @var int 00081 */ 00082 protected $spriteWidth = 0; 00083 00084 /** 00085 * calculated height of the sprite 00086 * @var int 00087 */ 00088 protected $spriteHeight = 0; 00089 00090 /** 00091 * sprite name, will be the filename, too 00092 * 00093 * @var string 00094 */ 00095 protected $spriteName = ''; 00096 00097 /** 00098 * the folder the sprite-images will be saved (relative to PATH_site) 00099 * 00100 * @var string 00101 */ 00102 protected $spriteFolder = 'typo3temp/sprites/'; 00103 00104 /** 00105 * the folder the sprite-cs will be saved (relative to PATH_site) 00106 * 00107 * @var string 00108 */ 00109 protected $cssFolder = 'typo3temp/sprites/'; 00110 00111 /** 00112 * the spriteName will not be included in icon names 00113 * 00114 * @var boolean 00115 */ 00116 protected $ommitSpriteNameInIconName = FALSE; 00117 00118 /** 00119 * @var boolean 00120 * @deprecated IE6 support will be dropped within 4.6 - then gifcopies are superflous 00121 */ 00122 protected $generateGIFCopy = TRUE; 00123 00124 /** 00125 * namespace of css classes 00126 * 00127 * @var string 00128 */ 00129 protected $nameSpace = 't3-icon'; 00130 00131 /** 00132 * setting this to true, the timestamp of the creation will be included to the background import 00133 * helps to easily rebuild sprites without cache problems 00134 * 00135 * @var boolean 00136 */ 00137 protected $includeTimestampInCSS = TRUE; 00138 00139 /** 00140 * all bases/root-names included in the sprite which has to be in css 00141 * as sprite to include the background-image 00142 * 00143 * @var array 00144 */ 00145 protected $spriteBases = array(); 00146 00147 /** 00148 * collects data about all icons to process 00149 * 00150 * @var array 00151 */ 00152 protected $iconsData = array(); 00153 00154 /** 00155 * collects all sizes of icons within this sprite and there count 00156 * 00157 * @var array 00158 */ 00159 protected $iconSizes = array(); 00160 00161 /** 00162 * maps icon-sizes to iconnames 00163 * 00164 * @var array 00165 */ 00166 protected $iconNamesPerSize = array(); 00167 00168 /** 00169 * space in px between to icons in the sprite (gap) 00170 * 00171 * @var int 00172 */ 00173 protected $space = 2; 00174 00175 /** 00176 * Initializes the configuration of the spritegenerator 00177 * 00178 * @param string $spriteName the name of the sprite to be generated 00179 * @return void 00180 */ 00181 public function __construct($spriteName) { 00182 $this->spriteName = $spriteName; 00183 } 00184 00185 /** 00186 * Sets namespace of css code 00187 * 00188 * @param string $string 00189 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00190 */ 00191 public function setNamespace($nameSpace) { 00192 $this->nameSpace = $nameSpace; 00193 return $this; 00194 } 00195 00196 /** 00197 * Sets the spritename 00198 * 00199 * @param string $spriteName the name of the sprite to be generated 00200 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00201 */ 00202 public function setSpriteName($spriteName) { 00203 $this->spriteName = $spriteName; 00204 return $this; 00205 } 00206 00207 /** 00208 * Sets the sprite-graphics target-folder 00209 * 00210 * @param string $folder the target folder where the generated sprite is stored 00211 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00212 */ 00213 public function setSpriteFolder($folder) { 00214 $this->spriteFolder = $folder; 00215 return $this; 00216 } 00217 00218 /** 00219 * Sets the sprite-css target-folder 00220 * 00221 * @param string $folder the target folder where the generated CSS files are stored 00222 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00223 */ 00224 public function setCSSFolder($folder) { 00225 $this->cssFolder = $folder; 00226 return $this; 00227 } 00228 00229 /** 00230 * Setter do enable the exclusion of the sprites-name from iconnames 00231 * 00232 * @param boolean $value 00233 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00234 */ 00235 public function setOmmitSpriteNameInIconName($value) { 00236 $this->ommitSpriteNameInIconName = is_bool($value) ? $value : FALSE; 00237 return $this; 00238 } 00239 00240 /** 00241 * Setter to adjust how much space is between to icons in the sprite 00242 * 00243 * @param int $value 00244 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00245 */ 00246 public function setIconSpace($value) { 00247 $this->space = intval($value); 00248 return $this; 00249 } 00250 00251 /** 00252 * Setter to enable/disable generating a GIF-Copy of the sprite 00253 * 00254 * @param boolean $value 00255 * @deprecated IE6 support will be dropped within 4.6 - then gifcopies are superflous 00256 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00257 */ 00258 public function setGenerateGifCopy($value) { 00259 $this->generateGIFCopy = is_bool($value) ? $value : TRUE; 00260 return $this; 00261 } 00262 00263 /** 00264 * Setter for timestamp inclusion: imageFiles will be included with ?timestamp 00265 * 00266 * @param boolean $value 00267 * @return t3lib_spritemanager_SpriteGenerator an instance of $this, to enable chaining. 00268 */ 00269 public function setIncludeTimestampInCSS($value) { 00270 $this->includeTimestampInCSS = is_bool($value) ? $value : TRUE; 00271 return $this; 00272 } 00273 00274 /** 00275 * Teads all png,gif,jpg files from the passed folder name (including 1 subfolder level) 00276 * extracts size information and stores data in internal array, 00277 * afterwards triggers sprite generation. 00278 * 00279 * @param array $inputFolder folder from which files are read 00280 * @return array 00281 */ 00282 public function generateSpriteFromFolder(array $inputFolder) { 00283 $iconArray = array(); 00284 foreach ($inputFolder as $folder) { 00285 // detect all files to be included in sprites 00286 $iconArray = array_merge( 00287 $iconArray, 00288 $this->getFolder($folder) 00289 ); 00290 } 00291 return $this->generateSpriteFromArray($iconArray); 00292 } 00293 00294 /** 00295 * Method processes an array of files into an sprite, 00296 * the array can be build from files within an folder or 00297 * by hand (as the SpriteManager does) 00298 * 00299 * @param array $files array(icon name => icon file) 00300 * @return array 00301 */ 00302 public function generateSpriteFromArray(array $files) { 00303 if (!$this->ommitSpriteNameInIconName) { 00304 $this->spriteBases[] = $this->spriteName; 00305 } 00306 00307 $this->buildFileInformationCache($files); 00308 // calculate Icon Position in sprite 00309 $this->calculateSpritePositions(); 00310 00311 $this->generateGraphic(); 00312 00313 $this->generateCSS(); 00314 00315 $iconNames = array_keys($this->iconsData); 00316 natsort($iconNames); 00317 00318 return array( 00319 'spriteImage' => PATH_site . $this->spriteFolder . $this->spriteName . '.png', 00320 'spriteGifImage' => PATH_site . $this->spriteFolder . $this->spriteName . '.gif', 00321 'cssFile' => PATH_site . $this->cssFolder . $this->spriteName . '.css', 00322 'cssGif' => PATH_site . $this->cssFolder . $this->spriteName . '-ie6.css', 00323 'iconNames' => $iconNames 00324 ); 00325 } 00326 00327 /** 00328 * Generates the css files 00329 * 00330 * @return void 00331 */ 00332 protected function generateCSS() { 00333 $cssData = ''; 00334 $cssIe6 = ''; 00335 00336 if ($this->includeTimestampInCSS) { 00337 $timestamp = '?' . time(); 00338 } else { 00339 $timestamp = ''; 00340 } 00341 00342 $spritePathForCSS = $this->resolveSpritePath(); 00343 00344 $markerArray = array( 00345 '###NAMESPACE###' => $this->nameSpace, 00346 '###DEFAULTWIDTH###' => $this->defaultWidth, 00347 '###DEFAULTHEIGHT###' => $this->defaultHeight, 00348 '###SPRITENAME###' => '', 00349 '###SPRITEURL###' => ($spritePathForCSS ? $spritePathForCSS . '/' : '') 00350 ); 00351 $markerArray['###SPRITEURL###'] .= $this->spriteName . '.png' . $timestamp; 00352 00353 foreach ($this->spriteBases as $base) { 00354 $markerArray['###SPRITENAME###'] = $base; 00355 $cssData .= t3lib_parsehtml::substituteMarkerArray($this->templateSprite, $markerArray); 00356 } 00357 00358 if ($this->generateGIFCopy) { 00359 $markerArray['###SPRITEURL###'] = str_replace('.png', '.gif', $markerArray['###SPRITEURL###']); 00360 foreach ($this->spriteBases as $base) { 00361 $cssIe6 .= t3lib_parsehtml::substituteMarkerArray($this->templateSprite, $markerArray); 00362 } 00363 } 00364 00365 foreach ($this->iconsData as $key => $data) { 00366 $temp = $data['iconNameParts']; 00367 array_shift($temp); 00368 $cssName = implode('-', $temp); 00369 $markerArrayIcons = array( 00370 '###NAMESPACE###' => $this->nameSpace, 00371 '###ICONNAME###' => $cssName, 00372 '###LEFT###' => $data['left'], 00373 '###TOP###' => $data['top'], 00374 '###SIZE_INFO###' => '' 00375 ); 00376 if ($data['height'] != $this->defaultHeight) { 00377 $markerArrayIcons['###SIZE_INFO###'] .= TAB . 'height: ' . $data['height'] . 'px;' . LF; 00378 } 00379 if ($data['width'] != $this->defaultWidth) { 00380 $markerArrayIcons['###SIZE_INFO###'] .= TAB . 'width: ' . $data['width'] . 'px;' . LF; 00381 } 00382 $cssData .= t3lib_parsehtml::substituteMarkerArray($this->templateIcon, $markerArrayIcons); 00383 00384 } 00385 00386 t3lib_div::writeFile(PATH_site . $this->cssFolder . $this->spriteName . '.css', $cssData); 00387 if ($this->generateGIFCopy) { 00388 t3lib_div::writeFile(PATH_site . $this->cssFolder . $this->spriteName . '-ie6.css', $cssIe6); 00389 } 00390 } 00391 00392 /** 00393 * Compares image path to CSS path and creates the relative backpath from css to the sprites 00394 * 00395 * @return string 00396 */ 00397 protected function resolveSpritePath() { 00398 // Fix window paths 00399 $this->cssFolder = str_replace('\\', '/', $this->cssFolder); 00400 $this->spriteFolder = str_replace('\\', '/', $this->spriteFolder); 00401 00402 $cssPathSegments = t3lib_div::trimExplode('/', trim($this->cssFolder, '/')); 00403 $graphicPathSegments = t3lib_div::trimExplode('/', trim($this->spriteFolder, '/')); 00404 00405 $i = 0; 00406 while (isset($cssPathSegments[$i]) && isset($graphicPathSegments[$i]) && 00407 $cssPathSegments[$i] == $graphicPathSegments[$i]) { 00408 unset($cssPathSegments[$i]); 00409 unset($graphicPathSegments[$i]); 00410 ++$i; 00411 } 00412 foreach ($cssPathSegments as $key => $value) { 00413 $cssPathSegments[$key] = '..'; 00414 } 00415 $completePath = array_merge($cssPathSegments, $graphicPathSegments); 00416 $path = implode('/', $completePath); 00417 return t3lib_div::resolveBackPath($path); 00418 } 00419 00420 /** 00421 * The actual sprite generator, renders the command for Im/GM and executes 00422 * 00423 * @return void 00424 */ 00425 protected function generateGraphic() { 00426 $iconParameters = array(); 00427 $tempSprite = t3lib_div::tempnam($this->spriteName); 00428 00429 $filePath = array( 00430 'mainFile' => PATH_site . $this->spriteFolder . $this->spriteName . '.png', 00431 'gifFile' => NULL 00432 ); 00433 // create black true color image with given size 00434 $newSprite = imagecreatetruecolor($this->spriteWidth, $this->spriteHeight); 00435 imagesavealpha($newSprite, TRUE); 00436 // make it transparent 00437 imagefill($newSprite, 0, 0, imagecolorallocatealpha($newSprite, 0, 255, 255, 127)); 00438 foreach ($this->iconsData as $icon) { 00439 $function = 'imagecreatefrom' . strtolower($icon['fileExtension']); 00440 if (function_exists($function)) { 00441 $currentIcon = $function($icon['fileName']); 00442 imagecopy($newSprite, $currentIcon, $icon['left'], $icon['top'], 0, 0, $icon['width'], $icon['height']); 00443 } 00444 } 00445 imagepng($newSprite, $tempSprite . '.png'); 00446 00447 if ($this->generateGIFCopy) { 00448 $filePath['gifFile'] = PATH_site . $this->spriteFolder . $this->spriteName . '.gif'; 00449 $gifSprite = imagecreatetruecolor($this->spriteWidth, $this->spriteHeight); 00450 // make it transparent 00451 imagefill($gifSprite, 0, 0, imagecolorallocate($gifSprite, 127, 127, 127)); 00452 foreach ($this->iconsData as $icon) { 00453 $function = 'imagecreatefrom' . strtolower($icon['fileExtension']); 00454 if (function_exists($function)) { 00455 $currentIcon = $function($icon['fileName']); 00456 imagecopy($gifSprite, $currentIcon, $icon['left'], $icon['top'], 0, 0, $icon['width'], $icon['height']); 00457 } 00458 } 00459 imagecolortransparent($gifSprite, imagecolorallocate($gifSprite, 127, 127, 127)); 00460 imagegif($gifSprite, $tempSprite . '.gif'); 00461 } 00462 00463 t3lib_div::upload_copy_move($tempSprite . '.png', $filePath['mainFile']); 00464 t3lib_div::unlink_tempfile($tempSprite . '.png'); 00465 if ($this->generateGIFCopy) { 00466 t3lib_div::upload_copy_move($tempSprite . '.gif', $filePath['gifFile']); 00467 t3lib_div::unlink_tempfile($tempSprite . '.gif'); 00468 } 00469 } 00470 00471 /** 00472 * Arranges icons in sprites, 00473 * afterwards all icons have information about ther position in sprite 00474 */ 00475 protected function calculateSpritePositions() { 00476 $currentLeft = 0; 00477 $currentTop = 0; 00478 // calculate width of every icon-size-group 00479 $sizes = array(); 00480 foreach ($this->iconSizes as $sizeTag => $count) { 00481 $size = $this->explodeSizeTag($sizeTag); 00482 $rowWidth = ceil(sqrt($count)) * $size['width']; 00483 while (isset($sizes[$rowWidth])) { 00484 $rowWidth++; 00485 } 00486 $sizes[$rowWidth] = $sizeTag; 00487 } 00488 // reverse sorting: widest group to top 00489 krsort($sizes); 00490 // integerate all icons grouped by icons size into the sprite 00491 foreach ($sizes as $sizeTag) { 00492 $size = $this->explodeSizeTag($sizeTag); 00493 $currentLeft = 0; 00494 $rowCounter = 0; 00495 00496 $rowSize = ceil(sqrt($this->iconSizes[$sizeTag])); 00497 00498 $rowWidth = $rowSize * $size['width'] + ($rowSize - 1) * $this->space; 00499 $this->spriteWidth = ($rowWidth > $this->spriteWidth ? $rowWidth : $this->spriteWidth); 00500 $firstLine = TRUE; 00501 00502 natsort($this->iconNamesPerSize[$sizeTag]); 00503 foreach ($this->iconNamesPerSize[$sizeTag] as $iconName) { 00504 if ($rowCounter == $rowSize - 1) { 00505 $rowCounter = -1; 00506 } elseif ($rowCounter == 0) { 00507 if (!$firstLine) { 00508 $currentTop += $size['height']; 00509 $currentTop += $this->space; 00510 } 00511 $firstLine = FALSE; 00512 $currentLeft = 0; 00513 } 00514 $this->iconsData[$iconName]['left'] = $currentLeft; 00515 $this->iconsData[$iconName]['top'] = $currentTop; 00516 00517 $currentLeft += $size['width']; 00518 $currentLeft += $this->space; 00519 00520 $rowCounter++; 00521 } 00522 $currentTop += $size['height']; 00523 $currentTop += $this->space; 00524 } 00525 $this->spriteHeight = $currentTop; 00526 } 00527 00528 /** 00529 * Function getFolder traverses the target directory, 00530 * locates all iconFiles and collects them into an array 00531 * 00532 * @param string path to an folder which contains images 00533 * @return array returns an array with all files key: iconname, value: fileName 00534 */ 00535 protected function getFolder($directoryPath) { 00536 $subFolders = t3lib_div::get_dirs(PATH_site . $directoryPath); 00537 if (!$this->ommitSpriteNameInIconName) { 00538 $subFolders[] = ''; 00539 } 00540 $resultArray = array(); 00541 00542 foreach ($subFolders as $folder) { 00543 if ($folder !== '.svn') { 00544 $icons = t3lib_div::getFilesInDir(PATH_site . $directoryPath . $folder . '/', 'gif,png,jpg'); 00545 if (!in_array($folder, $this->spriteBases) && count($icons) && $folder !== '') { 00546 $this->spriteBases[] = $folder; 00547 } 00548 foreach ($icons as $icon) { 00549 $fileInfo = pathinfo($icon); 00550 00551 $iconName = ($folder ? $folder . '-' : '') . $fileInfo['filename']; 00552 if (!$this->ommitSpriteNameInIconName) { 00553 $iconName = $this->spriteName . '-' . $iconName; 00554 } 00555 00556 $resultArray[$iconName] = $directoryPath . $folder . '/' . $icon; 00557 } 00558 } 00559 } 00560 return $resultArray; 00561 } 00562 00563 /** 00564 * Generates file information cache from file array 00565 * 00566 * @param array list of all files with their icon name 00567 * @return void 00568 */ 00569 protected function buildFileInformationCache(array $files) { 00570 foreach ($files as $iconName => $iconFile) { 00571 00572 $iconNameParts = t3lib_div::trimExplode('-', $iconName); 00573 if (!in_array($iconNameParts[0], $this->spriteBases)) { 00574 $this->spriteBases[] = $iconNameParts[0]; 00575 } 00576 $fileInfo = @pathinfo(PATH_site . $iconFile); 00577 $imageInfo = @getimagesize(PATH_site . $iconFile); 00578 00579 $this->iconsData[$iconName] = array( 00580 'iconName' => $iconName, 00581 'iconNameParts' => $iconNameParts, 00582 'singleName' => $fileInfo['filename'], 00583 'fileExtension' => $fileInfo['extension'], 00584 'fileName' => PATH_site . $iconFile, 00585 'width' => $imageInfo[0], 00586 'height' => $imageInfo[1], 00587 'left' => 0, 00588 'top' => 0 00589 ); 00590 00591 $sizeTag = $imageInfo[0] . 'x' . $imageInfo[1]; 00592 if (isset($this->iconSizes[$sizeTag])) { 00593 $this->iconSizes[$sizeTag] += 1; 00594 } else { 00595 $this->iconSizes[$sizeTag] = 1; 00596 $this->iconNamesPerSize[$sizeTag] = array(); 00597 } 00598 $this->iconNamesPerSize[$sizeTag][] = $iconName; 00599 } 00600 // find most common image size, save it as default 00601 asort($this->iconSizes); 00602 $defaultSize = $this->explodeSizeTag(array_pop(array_keys($this->iconSizes))); 00603 $this->defaultWidth = $defaultSize['width']; 00604 $this->defaultHeight = $defaultSize['height']; 00605 } 00606 00607 /** 00608 * Transforms size tag into size array 00609 * 00610 * @param string a size tag at the cache arrays 00611 * @return array 00612 */ 00613 protected function explodeSizeTag($tag = '') { 00614 $size = t3lib_div::trimExplode("x", $tag); 00615 return array( 00616 'width' => $size[0], 00617 'height' => $size[1] 00618 ); 00619 } 00620 00621 } 00622 00623 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/spritemanager/class.t3lib_spritemanager_spritegenerator.php'])) { 00624 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/spritemanager/class.t3lib_spritemanager_spritegenerator.php']); 00625 } 00626 ?>
1.8.0