Css-generator

Description

Version Beta Juin 2009

Nécessite les extensions apache : php_zip, GD2
Javascript DOIT être activé !
Compatible IE et FF

Réduisez le nombre de requêtes HTTP sur les images et sauvegardez ainsi votre bande passante. Si vous avez n images à afficher, il vous faudra n requete HTTP, fusionner toutes vos images en une pour obtenir qu'une seule requête. Ce logiciel crée automatiquement l'image ainsi que le css associé.

Extrait de : http://spritegen.website-performance.org/section/what-are-css-sprites

"CSS sprites are a way to reduce the number of HTTP requests made for image resources referenced by your site. Images are combined into one larger image at defined X and Y coorindates. Having assigned this generated image to relevant page elements the background-position CSS property can then be used to shift the visible area to the required component image.
This technique can be very effective for improving site performance, particularly in situations where many small images, such as menu icons, are used. The Yahoo! home page, for example, employs the technique for exactly this."

Suite à la lecture de l'excellent article : http://css-tricks.com/css-sprites/ et http://www.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/
Et à la découverte de ce service web : http://spritegen.website-performance.org/

Je me suis mis en tête de proposer cette application. Qui nécessite encore quelques modifications !

Source / Exemple :


<?php
/**

  • Construction de l'image finale et des régles CSS, en fonction des
  • paramètres envoyés par le formulaire de index.php5.
*
  • Attention le processus peut prendre du temps, surtout avec moulte images
  • J'utilise ce service en local, je peux donc augmenter dans la configuration
  • de php la mémoire allouée a loisir, ce que vous devriez faire si un message
  • d'erreur survient.
* * Class makePics{ /**
  • Construction des differentes variables nécessaire à l'application.
* *
  • @arguments BOOL $css : 1 si le texte ne doit pas être affiché, sinon 0, defaut 0
  • STRING $rep : Dossier contenant les images à fusionnées
  • STRING $format : Format de l'image de sortie, defaut PNG, sinon JPG
  • STRING $colors : Nombre de couleurs de l'image PNG defaut 24bits
  • INT $qualityJPG : Si le format de sortie est JPG alors entier de 0 a 100
  • STRING $backColors : Code Hexadecimal d'une couleure, si le champ
  • back colors du formulaire est remplis, blanc par defaut
  • BOOL $footer : 1 pour afficher le footer sinon 0, defaut 1
  • INT $spaceH : Espacement horizontal entre les images fusionnées, par defaut 0
  • INT $spaceW : Espacement vertical entre les images fusionnées, par defaut 0
  • INT $widthMax : Largeur de l'image de sortie
  • STRING $prefixCSS : Nom d'un containaire CSS
  • STRING $prefix : Prefix CSS de class
  • STRING $suffix : Suffix CSS de class
  • ARRAY $dump : Tableau contenant les réponses du programme
  • @return VOID
  • /
public function __construct($css, $rep, $format = "PNG", $colors = "32", $qualityJPG = '', $backColors = '', $footer = 0, $spaceH = 0, $spaceW = 0, $widthMax = 1024, $prefixCSS = '', $prefix = '', $suffix='') { $this->css = $css; $this->rep = $rep; $this->format = $format; $this->colors = $colors; $this->qualityJPG = $qualityJPG; $this->backColors = $backColors; $this->footer = $footer; $this->spaceH = $spaceH; $this->spaceW = $spaceW; $this->widthMax = $widthMax; $this->backColors = $backColors; $this->prefixCSS = $prefixCSS; $this->prefix = $prefix; $this->suffix = $suffix; $this->largeurFooter = $this->widthMax ; $this->hauteurFooter = 25; if(!empty($this->backColors)) { $colors = makePics::getHex2Rgb($this->backColors); $this->R = $colors['Rouge']; $this->G = $colors['Vert']; $this->B = $colors['Bleu']; } else { $this->R = 255; $this->G = 255; $this->B = 255; } $this->dump = array(); $this->dump['Format sortie'] = $this->format; $this->dump['Nombre couleurs sortie'] = $this->colors; $this->dump['Couleur fond sortie'] = $this->backColors; $this->dump['R fond sortie'] = $this->R; $this->dump['G fond sortie'] = $this->G; $this->dump['B fond sortie'] = $this->B; $this->dump['Qualite'] = $this->qualityJPG; makePics::setPics(); makePics::setCssCode(); //makePics::getDump(); } /*
  • Retourne un tableau de toutes les images contenues dans rep, cad nom, hauteur, largeur, mime type
  • classé par ordre décroissant de largeur.
  • @arguments STRING $path : Dossier à lister
*
  • @static ARRAY $this->dump['All pics'] : ($largeur1, ("f" -> file, "w" -> width, "h" -> height, "t" -> Mime type))
  • ARRAY $this->dump['Nbr files'] : Nombre d'images totale à traiter
  • ARRAY $this->dump['All height'] : Toutes les hauteurs disponible
*
  • @return ARRAY $allL : cf $this->dump['All pics'] vers getPicsCoord();
  • /
private function getAllPics($path) { // ERROR if(!is_dir($path)) { throw new Exception ('Invalid argument path (1) : ' . $path . ', must be STRING to real folder'); } static $allFiles = array(); static $allL = array(); static $i = 0; static $Hauteur_Dispo = array(); static $tableau_elements = array(); $dir = opendir($path); // Cette partie vient du site du zero : http://www.siteduzero.com/tutoriel-3-33057-initiation-a-la-recursivite-en-php-notions-mise-en-oeuvre-et-utilisation.html while (($element_dossier = readdir($dir)) !== FALSE) { if ($element_dossier != '.' && $element_dossier != '..' && is_dir($path.'/'.$element_dossier)) { $tableau_elements = array_merge($tableau_elements, self::getAllPics($path.$element_dossier.'/')); } elseif ($element_dossier != '.' && $element_dossier != '..'&& @getimagesize($path . $element_dossier) != 0) { $t = getimagesize($path . $element_dossier ); $allFiles[$i] = array( "f" => $path . $element_dossier, "w"=> $t[0], "h"=> $t[1], "t" => $t['mime'] ); if(!in_array($t[0], $Hauteur_Dispo)) { $Hauteur_Dispo[] = $t[0]; } $allL[$t[0]][] = $allFiles[$i]; $i++; } } closedir($dir); $Hauteur_dispo = sort($Hauteur_Dispo); $this->dump['All height'] = $Hauteur_Dispo; $this->dump['Nbr files'] = $i; $this->dump['All pics'] = $allL; ksort($allL); $allL = array_reverse($allL, TRUE); return $allL; } /*
  • Calcul les coordonnées (x, y) pour chaque image du dossier source, et la taille finale de l'image
  • (largeur, hauteur)
  • @arguments VOID
*
  • @static INT $this->dump['Final pics height'] : Hauteur en pixel de l'image finale
  • INT $this->dump['Final pics width'] : Largeur en pixel de l'image finale
  • INT $this->dump['Line'] : Nombre de ligne totale
  • ARRAY $this->dump['All files coord'] : $endAllFiles
*
  • @return ARRAY $endAllFiles : ('f'=> chemin d'accés a un fichier, 'w' => largeur d un fichier,
  • 'h'=> hauteur d'un fichier, 't' => mime-type d'un fichier,
  • 'x'=> coordonnées x pour coller un fichier dans l'image finale,
  • 'y'=> coordonnées y pour coller un fichier dans l'image finale)
  • @NB : L'origine de l'image finale se trouve dans le coin superieur gauche de l'image finale
  • /
private function getPicsCoor() { $arrayFiles = makePics::getAllPics($this->rep); $widthMax = $this->widthMax; $lineToken = 0; static $fileNumber = 1; static $heightActualLine = 0; static $widthActualLine = 0; static $totalHeight = 0; static $heightMax = 0; static $x = 0; static $y = 0; $endAllFiles = array(); foreach($arrayFiles as $val) { foreach($val as $fval) { $x = $widthActualLine; if($this->css == 1) { $widthActualLine += $fval['w'] + $this->spaceW; } else { $widthActualLine += $fval['w'] + $this->spaceW+100; } $heightActualLine = $fval['h'] + $this->spaceH; if($heightActualLine > $heightMax) { $heightMax = $heightActualLine; } if($widthActualLine <= $widthMax) { $endAllFiles[] = array($fval['f'], $fval['w'], $fval['h'], $fval['t'], $x, $y); } else { $lineToken++; $widthActualLine = 0; $totalHeight += $heightMax; $y += $heightMax; $heightMax = 0; $heightActualLine = 0; } $fileNumber++; if($fileNumber == $this->dump['Nbr files']) { $totalHeight += $heightMax; } } } $this->dump['Final pics height'] = $totalHeight; $this->dump['Final pics width'] = $this->widthMax; $this->dump['Line'] = $lineToken; $this->dump['All files coord'] = $endAllFiles; return $endAllFiles; } /*
  • Creation de l'image finale dans laquelle nous allons copié toutes les images, selon
  • sont format et si il y a une couleurs de fond, avec ou sans footer
  • @arguments VOID
*
  • @return RESSOURCE image
  • /
private function setPicsType() { // Test du nombre de couleurs désiré pour créer une image truecolor si 24bits if($this->colors == "32" || $this->colors != "8") { // Test si le footer doit être présent if($this->footer == 1) { $imageF = imagecreatetruecolor($this->widthMax, $this->dump['Final pics height']+15); $tc = imagecolorallocate($imageF, 255, 255, 255); imagecolortransparent($imageF, $tc); imagestring($imageF, 1, 10, $this->dump['Final pics height']+4, '| Files : ' . $this->dump['Nbr files'] . ' | Width : ' . $this->dump['Final pics width'] . ' | Height : ' . $this->dump['Final pics height'] . ' | By inwebo |', $tc); } else { $imageF = imagecreatetruecolor($this->widthMax, $this->dump['Final pics height']); } } else { $imageF = imagecreate($this->widthMax, $this->dump['Final pics height']); } // PNG transparente if($this->format == "PNG" && $this->backColors == '') { imagealphablending($imageF,false); $col = imagecolorallocatealpha($imageF, 255, 255, 255, 127); imagefilledrectangle($imageF, 0,0 ,$this->widthMax, $this->dump['Final pics height'], $col); imagealphablending($imageF,true); } // PNG avec couleur de fond if($this->format == "PNG" && $this->backColors != '') { imagealphablending($imageF,false); $col = imagecolorallocate($imageF, $this->R, $this->G, $this->B); imagefilledrectangle($imageF, 0,0 ,$this->widthMax, $this->dump['Final pics height'], $col); imagealphablending($imageF,true); } // JPG n'est jamais transparente, couleur par defaut (blanc) if($this->format == "JPG") { imagealphablending($imageF,false); $col = imagecolorallocate($imageF, $this->R, $this->G, $this->B); imagefilledrectangle($imageF, 0,0 ,$this->widthMax, $this->dump['Final pics height'], $col); imagealphablending($imageF,true); } return $imageF; } /*
  • Fusionne toutes les images du dossier $path (cf getAllPics()), dans une image finale de dimension
  • transmise par getPicsCoord(), dans une image finale de format $this->format, avec ou sans footer,
  • avec ou sans couleur de fond ...
  • (largeur, hauteur)
  • @arguments VOID
*
  • @return RESSOURCE image
  • /
private function mergeAllPics() { // Toutes les images $endAllFiles = makePics::getPicsCoor(); // Notre fond $imageF = makePics::setPicsType(); foreach($endAllFiles as $val) { $imgSrc = $val[0]; // Parcourt tout notre tableau de fichier a la recherche du mime type switch($val[3]){ case 'image/png': $img_src_resource = imagecreatefrompng($imgSrc); break; case 'image/jpg': $img_src_resource = imagecreatefromjpg($imgSrc); break; case 'image/gif': $img_src_resource = imagecreatefromgif($imgSrc); break; } // Si nous voulons rajouter le nom des fichiers à notre image finale if($this->css == 0) { $temp = explode('/', $val[0]); $n = count($temp); $f = explode('.', $temp[$n-1]); $t = $f[0]; $tc = imagecolorallocate($imageF, 0, 0, 0); // Un peu du bricolage, colle le texte a droite de notre image avec une marge de 3px imagestring($imageF, 1, $val[4]+3+$val[1], $val[5], $t, $tc); } @imagecopy($imageF, $img_src_resource, $val[4], $val[5], 0, 0, $val[1], $val[2]); } return $imageF; } /*
  • Sauvegarde l'image finale (renvoyé par mergeAllPics()) dans le format choisis par
  • l'utilisateur
  • @arguments VOID
*
  • @static STRING $this->dump['URL pics'] : url pour telecharger l'image finale
  • @return VOID
  • /
private function setPics() { // Bricolage, car j'enregistre tout d'abord en PNG puis je la convertie en JPG $this->format == "JPG" $imageF = makePics::mergeAllPics(); imagealphablending($imageF,false); imagesavealpha($imageF,true); imagepng($imageF, $this->rep . 'test-big.png'); if($this->format == "JPG") { $t = imagecreatefrompng($this->rep . 'test-big.png'); imagejpeg($t,$this->rep . 'test-big.jpg', $this->qualityJPG); unlink($this->rep . 'test-big.png'); $this->dump['URL pics'] = $this->rep . 'test-big.jpg'; } else { $this->dump['URL pics'] = $this->rep . 'test-big.png'; } } /*
  • Affiche toutes les variables de la class pratique pour le debug
  • @arguments VOID
  • @return HTML
  • /
public function getDump() { echo'<code><pre>'; print_r($this->dump); echo'
</pre>';
}

/*
  • Ecrit dans un fichiers toutes les regles CSS, et les retournes pour affichage
  • @arguments VOID
  • @return STRING $buffer
  • /

private function setCssCode() {
$buffer='';
foreach($this->dump['All files coord'] as $answer) {
$temp = explode('/', $answer[0]);
$n = count($temp);
$f = explode('.', $temp[$n-1]);
$t = $f[0];
$buffer .= $this->prefixCSS . '.' . $this->prefix . $t . ' ' . $this->suffix .'{display:block; height:' . $answer[2] . ' px; width:' . $answer[1] . ' px; background-position:-' . $answer[4] . 'px -' . $answer[5] . 'px;}'."\n";
}

$this->dump['Css'] = $buffer;

$file = fopen($this->rep . '/' . 'style.css', "w+");
fputs ($file, $buffer);
fclose($file);

$this->dump['URL Css'] = $this->rep . 'style.css' ;

return $buffer;
}

// Cette fonction est ici : http://us2.php.net/hexdec
private function getHex2Rgb($color)
{
$lColor = strlen($color);
if($lColor > 1) {
if($color[0] == '#') {
$color = substr($color, 1);
}
}
if($lColor == 6) {
list($r, $g, $b) = array(
$color[0].$color[1],
$color[2].$color[3],
$color[4].$color[5]
);
}
elseif($lColor == 3) {
list($r, $g, $b) = array(
$color[0].$color[0],
$color[1].$color[1],
$color[2].$color[2]
);
}
else {
return false;
}

return array(
'Rouge' => hexdec($r),
'Vert' => hexdec($g),
'Bleu' => hexdec($b)
);
}

}

?>
</code>

Conclusion :

  • Attention
  • Le traitement d'image peut être relativement gourmand, si vous travaillez en local (ce que je vous
  • recommande pour ce logiciel) vous pouvez ajuster la quantité de memoire alloué à PHP.

*
  • ;;;;;;;;;;;;;;;;;;;
  • ; Resource Limits ;
  • ;;;;;;;;;;;;;;;;;;;

*
  • memory_limit = 16M ; Maximum amount of memory a script may consume (16MB)

*
  • Sur une configuration relativement ancienne, vous pouvez passer a 128 ou plus.


Si vous connaissez un algorithme pour ranger des surfaces en utilisant le minimum de place, je vous écoutes !

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.