Web2master
Entraînement hexadécimal Générateur de dégradés Projects & Prototypes

Générateur de dégradés

Introduction

Etant un flemmard qui s'assume, je n'ai jamais eu le courage d'user de Photoshop et The Gimp pour créer les designs des sites web que je codais. Pourtant, il me fallait un moyen de les rendre un minimum attractif... J'ai donc surfé sur un grand nombre de sites à la recherche d'un point commun dans leur graphisme qui les rend moins affreux que les miens.

A vrai dire, si on écarte tout ce qui est de conception purement humaine (logos, bannières, icônes...), il ne reste principalement qu'une chose : les dégradés, en particulier les dégradés verticaux. En effet, un simple dégradé peut donner au visiteur l'illusion d'un relief sur la page et, comme par magie, la rendre beaucoup moins austère.

Or, avec GD, il est largement possible de générer des dégradés avec de très simples formules mathématiques ! Il ne me restait donc plus qu'à créer un script qui prenne en argument les codes couleurs des 2 extrémités, la direction ainsi que la taille du dégradé, et j'aurais enfin des images générées à la volée pour faire un design simple et efficace :-)

A propos des codes couleurs, si vous ne maîtrisez pas encore la syntaxe hexadécimale, cliquez ici pour dérouler le mini-tutoriel associé.

Code du générateur

Voici donc le code du générateur en question, à enregistrer par exemple sous le nom gd.php :

<?php

define
('HORIZONTAL'0);
define('VERTICAL'1);

class 
Color {
    private 
$red$green$blue;
    private 
$alpha 0;
    public function 
__construct ($str) {
        if (
func_num_args() == 4) {
            
$this->red intval(func_get_arg(0));
            
$this->green intval(func_get_arg(1));
            
$this->blue intval(func_get_arg(2));
            
$this->alpha intval(func_get_arg(3));
        }
        else {
            if (
strlen($str) == 3)
                
$str $str[0].$str[0].$str[1].$str[1].$str[2].$str[2];
            elseif (
strlen($str) == 4)
                
$str $str[0].$str[0].$str[1].$str[1].$str[2].$str[2].$str[3].$str[3];
            
$this->red $this->getColor(substr($str02));
            
$this->green $this->getColor(substr($str22));
            
$this->blue $this->getColor(substr($str42));
            
$this->alpha floor($this->getColor(substr($str62)) / 2);
        }
    }
    private function 
getColor ($str) {
        return 
base_convert($str1610);
    }
    public function 
allocate ($img) {
        return 
imagecolorallocatealpha($img$this->red$this->green$this->blue$this->alpha);
    }
    static public function 
interpolate (Color $startColor $stop$percent) {
        return new 
Color(
            
round($percent $start->red + ($percent) * $stop->red),
            
round($percent $start->green + ($percent) * $stop->green),
            
round($percent $start->blue + ($percent) * $stop->blue),
            
round($percent $start->alpha + ($percent) * $stop->alpha)
        );
    }
}

class 
Image {
    private 
$img;
    public function 
__construct ($x$y$background null) {
        
$this->img imagecreatetruecolor($x$y);
        
imagealphablending($this->imgfalse);
        
imagesavealpha($this->imgtrue);
        if (
$background)
            
$this->setPolygon(array(
                
00,
                
$x0,
                
$x$y,
                
0$y
            
), $background);
    }
    public function 
setPixel($x$yColor $color) {
        
$c $color->allocate($this->img);
        
imagesetpixel($this->img$x$y$c);
    }
    public function 
setPolygon($pointsColor $color) {
        
$c $color->allocate($this->img);
        
$num_points count($points) / 2;
        
imagefilledpolygon($this->img$points$num_points$c);
    }
    public function 
renderPNG () {
        
header('Content-type: image/png');
        
imagepng($this->img);
    }
}

switch (@
$_GET['type']) {
    case 
'gradient':
        
$size intval(@$_GET['size']);
        
$direction = (@$_GET['direction'] == 'horizontal') ? HORIZONTAL VERTICAL;
        
$start = (string)@$_GET['start'];
        
$stop = (string)@$_GET['stop'];
        
$pow floatval(@$_GET['pow']);
        
$start = new Color($start);
        
$stop = new Color($stop);
        switch (
$direction) {
            case 
HORIZONTAL:
                
$image = new Image($size1);
                for (
$i $i $size $i++) {
                    
$r $i max(1$size 1);
                    
$image->setPixel($i0Color::interpolate($start$stoppow($r$pow)));
                }
                break;
            case 
VERTICAL:
                
$image = new Image(1$size);
                for (
$i $i $size $i++) {
                    
$r $i max(1$size 1);
                    
$image->setPixel(0$iColor::interpolate($start$stoppow($r$pow)));
                }
                break;
        }
        
$image->renderPNG();
        break;
    case 
'pixel':
        
$color = (string)@$_GET['color'];
        
$color = new Color($color);
        
$image = new Image(11);
        
$image->setPixel(00$color);
        
$image->renderPNG();
        break;
}

?>

Notons qu'un argument supplémentaire, "pow", doit être fourni : il permet d'avoir une répartition non-linéaire des couleurs (dominante de l'une sur l'autre) afin d'accentuer certains effets de relief.

Sous cette forme, pour générer un dégradé blanc-noir de 100 pixels de hauteur sur un bloc #bloc par exemple, vous devrez utiliser le code CSS suivant :

#bloc {
background: #fff
            url('gd.php?size=100&direction=vertical&start=000000&stop=ffffff&pow=1')
            repeat-x
            top;
}

Une syntaxe à améliorer

Vous serez d'accord avec moi quand je dis que c'est un peu moche, voire même ignoble. Mais n'oublions pas notre cher ami l'URL Rewriting ! Si vous disposez de cette précieuse extension sur votre serveur, le fichier .htaccess suivant, à mettre dans le même répertoire, vous simplifiera la vie :

RewriteEngine on

RewriteRule	^images\/v(\d+)_([0-9a-f]+)_([0-9a-f]+).png$	gd.php?type=gradient&size=$1&start=$2&stop=$3&pow=1&direction=vertical	[L]
RewriteRule	^images\/v(\d+)_([0-9a-f]+)_([0-9a-f]+)_(\d+.?\d*).png$	gd.php?type=gradient&size=$1&start=$2&stop=$3&pow=$4&direction=vertical	[L]
RewriteRule	^images\/h(\d+)_([0-9a-f]+)_([0-9a-f]+).png$	gd.php?type=gradient&size=$1&start=$2&stop=$3&pow=1&direction=horizontal	[L]
RewriteRule	^images\/h(\d+)_([0-9a-f]+)_([0-9a-f]+)_(\d+.?\d*).png$	gd.php?type=gradient&size=$1&start=$2&stop=$3&pow=$4&direction=horizontal	[L]
RewriteRule	^images\/p_([0-9a-f]+).png$	gd.php?type=pixel&color=$1	[L]

Vous pourrez dès lors utiliser une syntaxe beaucoup plus propre pour générer vos images, qui par ailleurs a l'avantage de cacher que vous utilisez un script de génération d'images :

#bloc {
background: #fff
            url('images/v100_ffffff_000000.png')
            repeat-x
            top;
}

Alternative sans URL Rewriting

Comme me l'a fait remarquer KOogar de WebRankInfo, on peut se passer de l'URL Rewriting, qui n'est pas disponible sur tous les serveurs, en utilisant une syntaxe du type img.php?t=v100_ffffff_000000.png au lieu de images/v100_ffffff_000000.png.

Pour cela, il faut user des expressions rationnelles, comme dans le fichier img.php suivant :

<?php

$t 
= @$_GET['t'];
if (
preg_match('/^v(\d+)_([0-9a-f]+)_([0-9a-f]+)$/'$t$matches)) {
    
$_GET = array(
        
'type' => 'gradient',
        
'size' => $matches[1],
        
'start' => $matches[2],
        
'stop' => $matches[3],
        
'pow' => 1,
        
'direction' => 'vertical'
    
);
    include(
'gd.php');
}
else if (
preg_match('/^v(\d+)_([0-9a-f]+)_([0-9a-f]+)_(\d+.?\d*)$/'$t$matches)) {
    
$_GET = array(
        
'type' => 'gradient',
        
'size' => $matches[1],
        
'start' => $matches[2],
        
'stop' => $matches[3],
        
'pow' => $matches[4],
        
'direction' => 'vertical'
    
);
    include(
'gd.php');
}
else if (
preg_match('/^h(\d+)_([0-9a-f]+)_([0-9a-f]+)$/'$t$matches)) {
    
$_GET = array(
        
'type' => 'gradient',
        
'size' => $matches[1],
        
'start' => $matches[2],
        
'stop' => $matches[3],
        
'pow' => 1,
        
'direction' => 'horizontal'
    
);
    include(
'gd.php');
}
else if (
preg_match('/^h(\d+)_([0-9a-f]+)_([0-9a-f]+)_(\d+.?\d*)$/'$t$matches)) {
    
$_GET = array(
        
'type' => 'gradient',
        
'size' => $matches[1],
        
'start' => $matches[2],
        
'stop' => $matches[3],
        
'pow' => $matches[4],
        
'direction' => 'horizontal'
    
);
    include(
'gd.php');
}
else if (
preg_match('/^p_([0-9a-f]+)$/'$t$matches)) {
    
$_GET = array(
        
'type' => 'pixel',
        
'color' => $matches[1]
    );
    include(
'gd.php');
}

?>

Autres détails

Merci d'avoir lu ce tutoriel ;-)