Il est né ?
Vous êtes ici : mk0phpgtk.xgarreau.org >> aide >> devel >> gd : Masque de transparence PHP/GD2
Version imprimable

Masque de transparence PHP/GD2

Voici un exemple d'utilisation de gd2 en php. Ce script permet d'appliquer un masque de transparence à une image.

Introduction

Ce script a été écrit suite à une question intéressante sur les forums d'apachefrance.com

Il s'agissait à la base de faire des angles arrondis aux images et puis, les fonctionnalités ont tellement dégénérées que j'ai décidé d'écrire cette page pour vous présenter le script ...

Utilisation

Ce script peut fonctionner de plusieurs manières. On l'inclut en attribut src des balises img dela façon suivante:

<img src="arrondi.php?img=pic.jpg&mask=mask.png&bg_r=216&bg_g=252&bg_b=216" />

arrondi.php peut être précédé d'un chemin absolu ou relatif selon le répertoire où il se trouve, par rapport à la page dans laquelle on l'utilise.

Voyons les paramètres:

Installation

Placez arrondi.php et un masque mask.png par défaut dans un répertoire de votre site. Créez un sous répertoire cache dans le quel le script doit pouvoir écrire (autorisation en exécution et écriture pour tous ou chmod 777 pour être sûr).

C'est tout !

Le script

arrondi.php

<?php
if (!isset($_GET["img"])) die('missing img parameter');
if (strstr("http://", $_GET["img"])) die('Only for internal use');
if (strstr("http://", $_GET["mask"])) die('Only for internal use');


// On regarde si l'utilisateur utilise IE ou autre chose
if (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
    $isIE = true;
} else {
    $isIE = false;
}


$src = array();


// On vérifie l'existence de l'image
$src['file'] = $_GET['img'];
if (!file_exists($src['file'])) die('Image does not exist');


// On regarde si l'utilisateur a spécifié une couleur de fond
if (isset($_GET['bg_r']) && isset($_GET['bg_g']) && isset($_GET['bg_b'])) {
    $src['img_bgcolor']['r'] = intval($_GET['bg_r']);
    $src['img_bgcolor']['g'] = intval($_GET['bg_g']);
    $src['img_bgcolor']['b'] = intval($_GET['bg_b']);
}


// On se procure les infos sur l'image (taille/type mime)
$src['infos'] = getimagesize($src['file']);


// On charge le masque
$src['maskfile'] = (isset($_GET['mask']) ? $_GET['mask'] : "./mask.png");
$src['origmask'] = imagecreatefrompng($src['maskfile']);


// On Vérifie l'existence du masque
if (!file_exists($src['maskfile'])) die('mask file does not exist');


// On cherche l'image en cache
$src['cache_file'] = "./cache/".md5($src['file'].$src['maskfile']);

if (isset($src['img_bgcolor'])) {
    $src['cache_file'] .= "r".$src['img_bgcolor']['r'];
    $src['cache_file'] .= "g".$src['img_bgcolor']['g'];
    $src['cache_file'] .= "b".$src['img_bgcolor']['b'];
} else {
    $src['cache_file'] .= (($isIE)?"IE":"");
}
if (file_exists($src['cache_file']) &&
    (intval(filemtime($src['file'])) < intval(filemtime($src['cache_file']))) &&
    (intval(filemtime($src['maskfile'])) < intval(filemtime($src['cache_file'])))) {
    // Si on a l'image traitée en cache 
    // Et que l'image source n'est pas plus récente que celle en cache
    // on l'envoie !
    if (!isset($src['img_bgcolor'])) {
        header ("Content-Type: image/png");
    } else {
        header ("Content-Type: image/jpeg");
    }
    readfile($src['cache_file']);
    exit();
}
// Sinon on continue le traitement


// On se procure la taille du masque
$src['origmask_info'] = getimagesize($src['maskfile']);


// On crée un masque à la bonne taille
$src['mask'] = imagecreatetruecolor ($src['infos'][0], $src['infos'][1]);


// On y copie le masque de départ
imagealphablending($src['mask'], FALSE);
imagecopyresized(
    $src['mask'], $src['origmask'],
    0, 0,
    0, 0,
    $src['infos'][0], $src['infos'][1],
    $src['origmask_info'][0], $src['origmask_info'][1]);


// On se débarasse du masque de départ
imagedestroy($src['origmask']);


// On charge l'image de départ en fonction de son type
switch($src['infos']['mime']) {
    case 'image/jpg':
    case 'image/jpeg':
        $src['img'] = imagecreatefromjpeg($src['file']);
        break;
    case 'image/gif':
	$tmp = imagecreatefromgif($src['file']);
	$src['img'] = imagecreatetruecolor($src['infos'][0], $src['infos'][1]);
	imagecopy ($src['img'], $tmp, 0, 0, 0, 0, $src['infos'][0], $src['infos'][1]);
	imagedestroy($tmp);
	break;
    case 'image/png':
        $src['img'] = imagecreatefrompng($src['file']);
        break;
    default:
        exit();
}
imagealphablending($src['img'], isset($src['img_bgcolor']));


// Pour IE, on passe en mode indéxé 
// Et on dit que la couleur se trouvant en 0,0 sera la couleur transparente ...
if ($isIE && !isset($src['img_bgcolor'])) {
    imagetruecolortopalette($src['img'], FALSE, 256);
    $trans_color = imagecolorat($src['img'], 0, 0);
    imagecolortransparent($src['img'], $trans_color);
}


// On affecte à chaque pixel de l'image
// la valeur de l'alpha dans le masque
// et éventuellement la couleur de fond mélangée
for ($i=0; $i<$src['infos'][0]; ++$i) {
    for ($j=0; $j<$src['infos'][1]; ++$j) {
        if ($isIE && !isset($src['img_bgcolor'])) {
            $pxl = imagecolorsforindex(
                      $src['mask'],
                      imagecolorat($src['mask'], $i, $j));
            $pxl_alpha = $pxl['alpha'];
            if ($pxl_alpha>=120)
                imagesetpixel($src['img'], $i, $j, $trans_color);
        } else {
            $pxl_alpha = imagecolorsforindex(
                              $src['mask'],
                              imagecolorat($src['mask'], $i, $j));
            $pxl_color = imagecolorsforindex(
                              $src['img'],
                              imagecolorat($src['img'], $i, $j));
            if (!isset($src['img_bgcolor']))
                $color = imagecolorallocatealpha (
                              $src['img'],
                              $pxl_color['red'],
                              $pxl_color['green'],
                              $pxl_color['blue'],
                              $pxl_alpha['alpha']);
            else
                $color = imagecolorallocatealpha (
                              $src['img'],
                              $src['img_bgcolor']['r'],
                              $src['img_bgcolor']['g'],
                              $src['img_bgcolor']['b'],
                              127-$pxl_alpha['alpha']);
            imagesetpixel($src['img'], $i, $j, $color);
        }
    }
}


// Pas besoin de sauver l'alpha si on a affaire à IE,
// il n'en tient pas compte ...
if (!$isIE) {
    imagesavealpha($src['img'], TRUE);
}


// On crée le fichier en cache
if (!isset($src['img_bgcolor'])) {
    imagepng($src['img'], $src['cache_file']);
} else {
    imagejpeg($src['img'], $src['cache_file']);
}
imagedestroy($src['img']);
imagedestroy($src['mask']);


// On envoi le header et l'image du cache
if (!isset($src['img_bgcolor'])) {
    header("Content-Type: image/png");
} else {
    header("Content-Type: image/jpeg");
}
readfile($src['cache_file']);
?>

Explications

Le script détecte le browser utilisé vie l'entête "User-Agent" pour voir si on a affaire à Internet Explorer ou non. Ce test est nécessaire car IE ne gère pas correctement les images png comportant une couche alpha ...

Le script gère un cache dans lequel il stocke toutes les images qui lui ont été demandées, en fonction du browser, de la couleur de fond et du masque appliqué. Ceci accélère le traitement, l'application du masque de transparence étant relativement long, il est mieux de ne le faire qu'une fois.

En l'absence des composantes de couleurs de fond, le script envoit un PNG RVB avec couche alpha sur 7 bits si le browser utilisé n'est pas IE et un simple png indéxé avec une couleur transparente (comme un GIF) s'il s'agit d'un internaute utilisant IE. Autant dire qu'en utilisant Firefox ou Opera, on obtient une image beaucoup mieux finie ...

Si les composantes de fond sont spécifiées, le script crée un jpg en mélangeant la couleur de fond spéfifiée en fonction du masque alpha. Ceci donne une qualité équivalente au PNG RVBA et une taille très inférieure pour les images. En revanche, le résultat n'est parfait que sur un fond uni ...

Quelques exemples (avec leur masque)

L'arrondi

Le feu de l'amour

Le Zaz :-)

a+

Auteur : Xavier GARREAU
Modifié le 22.02.2007

Rechercher :

Google
 
Web www.xgarreau.org