Feature #23150 ยป rfc15079.diff
t3lib/spritemanager/class.t3lib_spritemanager_spritegenerator.php (Revision 0) | ||
---|---|---|
<?php
|
||
/***************************************************************
|
||
* Copyright notice
|
||
*
|
||
* (c) 2010 Steffen Ritter <info@steffen-ritter.net>
|
||
* All rights reserved
|
||
*
|
||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||
* free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* The GNU General Public License can be found at
|
||
* http://www.gnu.org/copyleft/gpl.html.
|
||
* A copy is found in the textfile GPL.txt and important notices to the license
|
||
* from the author is found in LICENSE.txt distributed with these scripts.
|
||
*
|
||
*
|
||
* This script is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* This copyright notice MUST APPEAR in all copies of the script!
|
||
***************************************************************/
|
||
/**
|
||
* sprite generator
|
||
*
|
||
* @author Steffen Ritter <info@steffen-ritter.net>
|
||
* @package TYPO3
|
||
* @subpackage t3lib
|
||
*/
|
||
class t3lib_spritemanager_SpriteGenerator {
|
||
/**
|
||
* template creating CSS for the spritefile
|
||
* @var string
|
||
*/
|
||
private $templateSprite = '
|
||
.NAMESPACE-SPRITENAME {
|
||
background-image: url(\'SPRITEURL\');
|
||
height: DEFAULTHEIGHTpx;
|
||
width: DEFAULTWIDTHpx;
|
||
}
|
||
';
|
||
/**
|
||
*
|
||
* template creating CSS for position and size of a single icon
|
||
* @var string
|
||
*/
|
||
private $templateIcon = '
|
||
.NAMESPACE-ICONNAME {
|
||
background-position: -LEFTpx -TOPpx;
|
||
SIZE_INFO
|
||
}
|
||
';
|
||
/**
|
||
* most common icon-width in the sprite
|
||
* @var int
|
||
*/
|
||
private $defaultWidth = 0;
|
||
/**
|
||
* most common icon-width in the sprite
|
||
* @var int
|
||
*/
|
||
private $defaultHeight = 0;
|
||
/**
|
||
* calculated width of the sprite
|
||
* @var int
|
||
*/
|
||
private $spriteWidth = 0;
|
||
/**
|
||
* calculated height of the sprite
|
||
* @var int
|
||
*/
|
||
private $spriteHeight = 0;
|
||
/**
|
||
* sprite name, will be the filename, too
|
||
* @var string
|
||
*/
|
||
private $spriteName = '';
|
||
/**
|
||
* the folder the sprite-images will be saved (relative to PATH_site)
|
||
* @var string
|
||
*/
|
||
private $spriteFolder = 'typo3temp/sprites/';
|
||
/**
|
||
* the folder the sprite-cs will be saved (relative to PATH_site)
|
||
* @var string
|
||
*/
|
||
private $cssFolder = 'typo3temp/sprites/';
|
||
/**
|
||
* the spriteName will not be included in icon names
|
||
* @var boolean
|
||
*/
|
||
private $ommitSpriteNameInIconName = FALSE;
|
||
/**
|
||
* @var boolean
|
||
* @deprecated IE6 support will be dropped within 4.6 - then gifcopies are superflous
|
||
*/
|
||
private $generateGIFCopy = TRUE;
|
||
/**
|
||
* namepsce of css classes
|
||
* @var string
|
||
*/
|
||
private $nameSpace = 't3-icon';
|
||
/**
|
||
* setting this to true, the timestamp of the creation will be included to the background import
|
||
* helps to easily rebuild sprites without cache problems
|
||
* @var boolean
|
||
*/
|
||
private $includeTimestampInCSS = TRUE;
|
||
/**
|
||
* all bases/root-names included in the sprite which has to be in css
|
||
* as sprite to include the background-image
|
||
* @var array
|
||
*/
|
||
private $spriteBases = array();
|
||
/**
|
||
* collects data about all icons to proces
|
||
* @var array
|
||
*/
|
||
private $iconsData = array();
|
||
/**
|
||
* collects all sizes of icons within this sprite and there count
|
||
* @var array
|
||
*/
|
||
private $iconSizes = array();
|
||
/**
|
||
* maps icon-sizes to iconnames
|
||
* @var array
|
||
*/
|
||
private $iconNamesPerSize = array();
|
||
/**
|
||
* space in px between to icons in the sprite (gap)
|
||
* @var int
|
||
*/
|
||
private $space = 2;
|
||
/**
|
||
* initializes the configuration of the spritegenerator
|
||
*
|
||
* @param string $spriteName the name of the sprite to be generated
|
||
* @return void
|
||
*/
|
||
public function __construct($spriteName) {
|
||
$this->spriteName = $spriteName;
|
||
}
|
||
/**
|
||
* sets namespace of css code
|
||
* @param string $string
|
||
* @return $this
|
||
*/
|
||
public function setNamespace($nameSpace) {
|
||
$this->nameSpace = $nameSpace;
|
||
return $this;
|
||
}
|
||
/**
|
||
* sets the spritename
|
||
* @param string $spriteName the name of the sprite to be generated
|
||
* @return $this
|
||
*/
|
||
public function setSpriteName($spriteName) {
|
||
$this->spriteName = $spriteName;
|
||
return $this;
|
||
}
|
||
/**
|
||
* sets the sprite-graphics target-folder
|
||
* @param string $folder the target folder where the generated sprite is stored
|
||
* @return $this
|
||
*/
|
||
public function setSpriteFolder($folder) {
|
||
$this->spriteFolder = $folder;
|
||
return $this;
|
||
}
|
||
/**
|
||
* sets the sprite-css target-folder
|
||
* @param string $folder the target folder where the generated CSS files are stored
|
||
* @return $this
|
||
*/
|
||
public function setCSSFolder($folder) {
|
||
$this->cssFolder = $folder;
|
||
return $this;
|
||
}
|
||
/**
|
||
* setter do enable the exclusion of the sprites-name from iconnames
|
||
* @param boolean $value
|
||
* @return $this
|
||
*/
|
||
public function setOmmitSpriteNameInIconName($value) {
|
||
$this->ommitSpriteNameInIconName = is_bool($value) ? $value : FALSE;
|
||
return $this;
|
||
}
|
||
/**
|
||
* setter to adjust how much space is between to icons in the sprite
|
||
* @param int $value
|
||
* @return $this
|
||
*/
|
||
public function setIconSpace($value) {
|
||
$this->space = intval($value);
|
||
return $this;
|
||
}
|
||
/**
|
||
* setter to enable/disable generating a GIF-Copy of the sprite
|
||
* @param boolean $value
|
||
* @deprecated IE6 support will be dropped within 4.6 - then gifcopies are superflous
|
||
* @return $this
|
||
*/
|
||
public function setGenerateGifCopy($value) {
|
||
$this->generateGIFCopy = is_bool($value) ? $value : TRUE;
|
||
return $this;
|
||
}
|
||
/**
|
||
* setter for timestamp inclusion: imageFiles will be included with ?timestamp
|
||
* @param boolean $value
|
||
*/
|
||
public function setIncludeTimestampInCSS($value) {
|
||
$this->includeTimestampInCSS = is_bool($value) ? $value : TRUE;
|
||
return $this;
|
||
}
|
||
/**
|
||
* reads all png,gif,jpg files from the passed foldername (including 1 subfolder level)
|
||
* extracts size information and stores data in internal array,
|
||
* afterwards triggers sprite generation.
|
||
* @param array $inputFolder folder from which files are read
|
||
* @return array
|
||
*/
|
||
public function generateSpriteFromFolder(array $inputFolder) {
|
||
$iconArray = array();
|
||
foreach ($inputFolder as $folder) {
|
||
//detect all files to be included in sprites
|
||
$iconArray = array_merge(
|
||
$iconArray,
|
||
$this->getFolder($folder)
|
||
);
|
||
}
|
||
return $this->generateSpriteFromArray($iconArray);
|
||
}
|
||
/**
|
||
*
|
||
* @param array $files
|
||
* @return array
|
||
*/
|
||
public function generateSpriteFromArray(array $files) {
|
||
if (!$this->ommitSpriteNameInIconName) {
|
||
$this->spriteBases[] = $this->spriteName;
|
||
}
|
||
t3lib_div::debug($this->spriteBases);
|
||
$this->buildFileInformationCache($files);
|
||
// calculate Icon Position in sprite
|
||
$this->calculateSpritePositions();
|
||
$this->generateGraphic();
|
||
$this->generateCSS();
|
||
$iconNames = array_keys($this->iconsData);
|
||
natsort($iconNames);
|
||
return array(
|
||
'spriteImage' => PATH_site . $this->spriteFolder . $this->spriteName . '.png',
|
||
'spriteGifImage'=> PATH_site . $this->spriteFolder . $this->spriteName . '.gif',
|
||
'cssFile' => PATH_site . $this->cssFolder . $this->spriteName . '.css',
|
||
'cssGif' => PATH_site . $this->cssFolder . $this->spriteName . '-ie6.css',
|
||
'iconNames' => $iconNames
|
||
);
|
||
}
|
||
/**
|
||
* generates the css files
|
||
* @return void
|
||
*/
|
||
private function generateCSS() {
|
||
$cssData = '';
|
||
$cssIe6 = '';
|
||
if($this->includeTimestampInCSS) {
|
||
$timestamp = '?' . time();
|
||
} else {
|
||
$timestamp = '';
|
||
}
|
||
$spritePathForCSS = $this->resolveSpritePath();
|
||
$markerArray = array(
|
||
'NAMESPACE' => $this->nameSpace,
|
||
'DEFAULTWIDTH' => $this->defaultWidth,
|
||
'DEFAULTHEIGHT' => $this->defaultHeight,
|
||
'SPRITENAME' => '',
|
||
'SPRITEURL' => ($spritePathForCSS ? $spritePathForCSS . DIRECTORY_SEPARATOR : '')
|
||
);
|
||
$markerArray['SPRITEURL'] .= $this->spriteName . '.png' . $timestamp;
|
||
foreach ($this->spriteBases as $base) {
|
||
$markerArray['SPRITENAME'] = $base;
|
||
$cssData .= t3lib_parsehtml::substituteMarkerArray($this->templateSprite, $markerArray);
|
||
}
|
||
if ($this->generateGIFCopy) {
|
||
$markerArray['SPRITEURL'] = str_replace('.png','.gif',$markerArray['SPRITEURL']);
|
||
foreach ($this->spriteBases as $base) {
|
||
$cssIe6 .= t3lib_parsehtml::substituteMarkerArray($this->templateSprite, $markerArray);
|
||
}
|
||
}
|
||
foreach ($this->iconsData as $key => $data) {
|
||
$markerArrayIcons = array(
|
||
'NAMESPACE' => $this->nameSpace,
|
||
'ICONNAME' => $data['singleName'],
|
||
'LEFT' => $data['left'],
|
||
'TOP' => $data['top'],
|
||
'SIZE_INFO' => ''
|
||
);
|
||
if ($data['height'] != $this->defaultHeight) {
|
||
$markerArrayIcons['SIZE_INFO'] .= "\theight: " . $data['height'] . 'px;' . LF;
|
||
}
|
||
if ($data['width'] != $this->defaultWidth) {
|
||
$markerArrayIcons['SIZE_INFO'] .= "\twidth: " . $data['width'] . 'px;' . LF;
|
||
}
|
||
$cssData .= t3lib_parsehtml::substituteMarkerArray($this->templateIcon, $markerArrayIcons);
|
||
}
|
||
t3lib_div::writeFile(PATH_site . $this->cssFolder . $this->spriteName . '.css', $cssData);
|
||
if ($this->generateGIFCopy) {
|
||
t3lib_div::writeFile(PATH_site . $this->cssFolder . $this->spriteName . '-ie6.css', $cssIe6);
|
||
}
|
||
}
|
||
/**
|
||
* compares Img-Path to CSS path and creates the relative backpath from css to the sprites
|
||
* @return string
|
||
*/
|
||
private function resolveSpritePath() {
|
||
$cssPathSegments = t3lib_div::trimExplode(DIRECTORY_SEPARATOR, trim($this->cssFolder, '/'));
|
||
$graphicPathSegments = t3lib_div::trimExplode(DIRECTORY_SEPARATOR, trim($this->spriteFolder, '/'));
|
||
$i = 0;
|
||
while (isset($cssPathSegments[$i]) && isset($graphicPathSegments[$i]) &&
|
||
$cssPathSegments[$i] == $graphicPathSegments[$i]) {
|
||
unset($cssPathSegments[$i]);
|
||
unset($graphicPathSegments[$i]);
|
||
++$i;
|
||
}
|
||
foreach ($cssPathSegments AS $key => $value) {
|
||
$cssPathSegments[$key] = '..';
|
||
}
|
||
$completePath = array_merge($cssPathSegments, $graphicPathSegments);
|
||
$path = implode(DIRECTORY_SEPARATOR, $completePath);
|
||
return t3lib_div::resolveBackPath($path);
|
||
}
|
||
/**
|
||
* the actual sprite generator, renders the command for Im/GM and executes
|
||
* @return void
|
||
*/
|
||
private function generateGraphic() {
|
||
$iconParameters = array();
|
||
$tempSprite = t3lib_div::tempnam($this->spriteName);
|
||
$filePath = array(
|
||
'mainFile' => PATH_site . $this->spriteFolder . $this->spriteName . '.png',
|
||
'gifFile' => NULL
|
||
);
|
||
// create black true color image with given size
|
||
$newSprite = imagecreatetruecolor($this->spriteWidth, $this->spriteHeight);
|
||
imagesavealpha($newSprite, true);
|
||
// make it transparent
|
||
imagefill($newSprite, 0, 0, imagecolorallocatealpha($newSprite, 0, 255, 255, 127));
|
||
foreach ($this->iconsData AS $icon) {
|
||
$function = 'imagecreatefrom' . strtolower($icon['fileExtension']);
|
||
if(function_exists($function)) {
|
||
$currentIcon = $function($icon['fileName']);
|
||
imagecopy($newSprite, $currentIcon, $icon['left'], $icon['top'], 0, 0, $icon['width'], $icon['height']);
|
||
}
|
||
}
|
||
imagepng($newSprite, $tempSprite . '.png');
|
||
if ($this->generateGIFCopy) {
|
||
$filePath['gifFile'] = PATH_site . $this->spriteFolder . $this->spriteName . '.gif';
|
||
$gifSprite = imagecreatetruecolor($this->spriteWidth, $this->spriteHeight);
|
||
// make it transparent
|
||
imagefill($gifSprite, 0, 0, imagecolorallocate($gifSprite, 127, 127, 127));
|
||
foreach ($this->iconsData AS $icon) {
|
||
$function = 'imagecreatefrom' . strtolower($icon['fileExtension']);
|
||
if(function_exists($function)) {
|
||
$currentIcon = $function($icon['fileName']);
|
||
imagecopy($gifSprite, $currentIcon, $icon['left'], $icon['top'], 0, 0, $icon['width'], $icon['height']);
|
||
}
|
||
}
|
||
imagecolortransparent($gifSprite, imagecolorallocate($gifSprite, 127, 127, 127));
|
||
imagegif($gifSprite, $tempSprite . '.gif');
|
||
}
|
||
t3lib_div::upload_copy_move($tempSprite . '.png', $filePath['mainFile']);
|
||
t3lib_div::unlink_tempfile($tempSprite . '.png');
|
||
if ($this->generateGIFCopy) {
|
||
t3lib_div::upload_copy_move($tempSprite . '.gif', $filePath['gifFile']);
|
||
t3lib_div::unlink_tempfile($tempSprite . '.gif');
|
||
}
|
||
}
|
||
/**
|
||
* aranges icons in sprites,
|
||
* afterwards all icons have information about ther position in sprite
|
||
*/
|
||
private function calculateSpritePositions() {
|
||
$currentLeft = 0;
|
||
$currentTop = 0;
|
||
// calculate width of every icon-size-group
|
||
$sizes = array();
|
||
foreach ($this->iconSizes as $sizeTag => $count) {
|
||
$size = $this->explodeSizeTag($sizeTag);
|
||
$sizes[ceil(sqrt($count)) * $size['width']] = $sizeTag;
|
||
}
|
||
// reverse sorting: widest group to top
|
||
krsort($sizes);
|
||
// integerate all icons grouped by icons size into the sprite
|
||
foreach ($sizes as $sizeTag) {
|
||
$size = $this->explodeSizeTag($sizeTag);
|
||
$currentLeft = 0;
|
||
$rowCounter = 0;
|
||
$rowSize = ceil(sqrt($this->iconSizes[$sizeTag]));
|
||
$rowWidth = $rowSize * $size['width'] + ($rowSize - 1) * $this->space;
|
||
$this->spriteWidth = ($rowWidth > $this->spriteWidth ? $rowWidth : $this->spriteWidth);
|
||
$firstLine = true;
|
||
natsort($this->iconNamesPerSize[$sizeTag]);
|
||
foreach ($this->iconNamesPerSize[$sizeTag] as $iconName) {
|
||
if ($rowCounter == $rowSize - 1) {
|
||
$rowCounter = -1;
|
||
} else if ($rowCounter == 0) {
|
||
if(!$firstLine) {
|
||
$currentTop += $size['height'];
|
||
$currentTop += $this->space;
|
||
}
|
||
$firstLine = false;
|
||
$currentLeft = 0;
|
||
}
|
||
$this->iconsData[$iconName]['left'] = $currentLeft;
|
||
$this->iconsData[$iconName]['top'] = $currentTop;
|
||
$currentLeft += $size['width'];
|
||
$currentLeft += $this->space;
|
||
$rowCounter++;
|
||
}
|
||
$currentTop += $size['height'];
|
||
$currentTop += $this->space;
|
||
}
|
||
$this->spriteHeight = $currentTop;
|
||
}
|
||
/**
|
||
* getFiles traverses the target directory,
|
||
* locates all iconFiles and
|
||
* @param string path to an folder which contains images
|
||
* @return array returns an array with all files key: iconname, value: fileName
|
||
*/
|
||
private function getFolder($directoryPath) {
|
||
$subFolders = t3lib_div::get_dirs(PATH_site . $directoryPath);
|
||
if (!$this->ommitSpriteNameInIconName) {
|
||
$subFolders[] = '';
|
||
}
|
||
$resultArray = array();
|
||
foreach ($subFolders as $folder) {
|
||
if ($folder != '.svn') {
|
||
$icons = t3lib_div::getFilesInDir(PATH_site . $directoryPath . $folder . DIRECTORY_SEPARATOR, 'gif,png,jpg');
|
||
if (!in_array($folder, $this->spriteBases) && count($icons)) {
|
||
$this->spriteBases[] = $folder;
|
||
}
|
||
foreach ($icons AS $icon) {
|
||
$fileInfo = pathinfo($icon);
|
||
$iconName = ($folder ? $folder . '-' : '') . $fileInfo['filename'];
|
||
if (!$this->ommitSpriteNameInIconName) {
|
||
$iconName = $this->spriteName . '-' . $iconName;
|
||
}
|
||
$resultArray[$iconName] = $directoryPath . $folder . DIRECTORY_SEPARATOR . $icon;
|
||
}
|
||
}
|
||
}
|
||
return $resultArray;
|
||
}
|
||
/**
|
||
* generates fileInformation Cache from file Array
|
||
* @param array list of all files with their icon name
|
||
* @return void
|
||
*/
|
||
private function buildFileInformationCache(array $files) {
|
||
foreach ($files as $iconName => $iconFile) {
|
||
$fileInfo = pathinfo(PATH_site . $iconFile);
|
||
$imageInfo = getimagesize(PATH_site . $iconFile);
|
||
$this->iconsData[$iconName] = array(
|
||
'iconName' => $iconName,
|
||
'singleName'=> $fileInfo['filename'],
|
||
'fileExtension'=> $fileInfo['extension'],
|
||
'fileName' => PATH_site . $iconFile,
|
||
'width' => $imageInfo[0],
|
||
'height' => $imageInfo[1],
|
||
'left' => 0,
|
||
'top' => 0
|
||
);
|
||
$sizeTag = $imageInfo[0] . 'x' . $imageInfo[1];
|
||
if (isset($this->iconSizes[$sizeTag])) {
|
||
$this->iconSizes[$sizeTag] += 1;
|
||
} else {
|
||
$this->iconSizes[$sizeTag] = 1;
|
||
$this->iconNamesPerSize[$sizeTag] = array();
|
||
}
|
||
$this->iconNamesPerSize[$sizeTag][] = $iconName;
|
||
}
|
||
// find most common imagesize, save it as default
|
||
asort($this->iconSizes);
|
||
$defaultSize = $this->explodeSizeTag(array_pop(array_keys($this->iconSizes)));
|
||
$this->defaultWidth = $defaultSize['width'];
|
||
$this->defaultHeight = $defaultSize['height'];
|
||
}
|
||
/**
|
||
* transforms size tag into size array
|
||
* @param string a size tag at the cache arrays
|
||
* @return array
|
||
*/
|
||
private function explodeSizeTag($tag = '') {
|
||
$size = t3lib_div::trimExplode("x", $tag);
|
||
return array(
|
||
'width' => $size[0],
|
||
'height'=> $size[1]
|
||
);
|
||
}
|
||
}
|
||
?>
|
t3lib/core_autoload.php (Arbeitskopie) | ||
---|---|---|
't3lib_spritemanager' => PATH_t3lib . 'class.t3lib_spritemanager.php',
|
||
't3lib_spritemanager_spriteicongenerator' => PATH_t3lib . 'interfaces/interface.t3lib_spritemanager_spriteicongenerator.php',
|
||
't3lib_spritemanager_simplehandler' => PATH_t3lib . 'spritemanager/class.t3lib_spritemanager_simplehandler.php',
|
||
't3lib_spritemanager_spritegenerator' => PATH_t3lib . 'spritemanager/class.t3lib_spritemanager_spritegenerator.php',
|
||
);
|
||
$tslibClasses = require(PATH_typo3 . 'sysext/cms/ext_autoload.php');
|