Redimensionnement d'images simple + mise en cache
De temps en temps, il arrive qu'une image existante soit nécessaire dans une autre taille. On peut alors soit créer avec Photoshop une version découpée sur mesure pour chaque variante de l'image et l'intégrer au site (ici, Autopush - Téléverser simplement les fichiers modifiés peut éventuellement convenir), soit faire tout cela à la volée avec un script PHP. Et pour ne pas trop pénaliser les performances, on peut aussi mettre le tout en cache et ne redimensionner l'image originale que si elle n'a pas déjà été redimensionnée à la taille voulue auparavant. Tout cela se fait certes un peu au détriment de l'espace disque, mais avec la version manuelle (découpe via Photoshop), ce ne serait pas différent ;-)
Il nous faut d'abord un fichier .htaccess qui envoie d'abord nos requêtes .png, .jpg et .jpeg à un script PHP, lequel fait ensuite le reste du travail. Voici ce qu'il faut mettre dans le fichier .htaccess pour que chaque fichier image passe automatiquement par le script PHP :
RewriteRule ^(.*)\.(jpg|jpeg|png)/?([0-9]*)?/([0-9]*)?/?([0-1]{1})?$ parse_image.php?i=$1&e=$2&w=$3&h=$4&r=$5 [L,QSA]
Le chemin vers parse_image.php doit bien sûr être adapté ;-) Cette règle HTACCESS ne fait rien d'autre qu'intercepter tous les fichiers de extension jpg, jpeg ou png et les rediriger vers parse_image.php. En outre, 3 paramètres peuvent être indiqués dans le chemin, qui seront traités par le script PHP (voir ci-dessous). Si aucun paramètre n'est transmis, l'« image principale » est appelée sans autre modification. Les autres paramètres sont
- Largeur de l'image de sortie (paramètre 1)
- Hauteur (paramètre 2)
- 1 ou 0, selon que l'on veut conserver ou non les proportions (paramètre 3)
On peut alors l'appeler ainsi :
<img src="images/040.jpg/100/200/1">
images/040.jpg est le chemin vers l'image, la première valeur (100) est la largeur de l'image de sortie, la deuxième (200) la hauteur, la troisième valeur indique si l'image doit être mise à l'échelle proportionnellement ou si l'on « découpe » simplement l'endroit voulu. Ici '1', donc la sortie est mise à l'échelle proportionnellement. Le script de mise en cache et de sortie ressemble alors à ceci : la constante « CACHEFOLDER » doit être adaptée, vers un dossier auquel PHP a un accès en lecture et en écriture (sinon nous ne pourrions pas enregistrer la nouvelle image). La constante ALLOWED_TYPES indique, en petit extra, quels types MIME sont autorisés et lesquels ne le sont pas.
# Der Ordner, in dem wir die Bilder cachen
define("CACHEFOLDER", "cache/images/");
# Zugelassene Typen - hier jpeg, jpg und png
define("ALLOWED_TYPES", ['image/jpeg', 'image/jpg', 'image/png']);
# Wir beziehen die GET-Variable r (ratio) und speichern je nach dem ein true oder false in unserer $keep_ratio
$keep_ratio = ($_GET['r'] == '1') ? true : false;
# Es werden die GET-Parameter geholt und in Variablen geschrieben. Muss man natürlich nicht machen, macht den ganzen Vorgang aber übersichtlicher
list($file, $ext, $dimensions['w'], $dimensions['h']) = [$_GET['i'], $_GET['e'], isset($_GET['w']) ? $_GET['w'] : 0, isset($_GET['h']) ? $_GET['h'] : 0];
# Es wird ein MD5-Hash erstellt bestehend aus Dateiname, Zielbreite und Zielhöhe und der Information, ob die Dimensionen erhalten bleiben sollen oder nicht.
$hash = CACHEFOLDER . md5($file.$ext.$dimensions['w'].$dimensions['h'].(($keep_ratio) ? '1' : '0'));
# $file_src enthält den kompletten Pfad zur Originaldatei
$file_src = $file . '.' . $ext;
# Wenn die Originaldatei nicht von einem der o.g. ALLOWED_TYPES ist, brechen wir die Verarbeitung ab (es ist kein png, jpg oder jpeg Bild und höchstwahrscheinlich wurde das Skript direkt aufgerufen)
if (!in_array(mime_content_type($file_src), ALLOWED_TYPES)) die();
# Wenn keine Datei existiert, welche unserem Hash entspricht, dann gibt es keine gecachte Version unseres Bildes und wir erstellen eine.
# Hierzu erstellen wir erst ein jpeg Bild von unserem Originalbild, beziehen die Größe des Bildes und skalieren dann das Bild abhängig von den angegebenen Parametern
if (!file_exists($hash)){
$res['src'] = imagecreatefromjpeg($file_src);
$filedata = getimagesize($file_src);
if ($dimensions['w'] == 0 || $dimensions['h'] == 0) list($dimensions['w'], $dimensions['h']) = [$filedata[0], $filedata[1]];
$res['dst'] = imagecreatetruecolor($dimensions['w'], $dimensions['h']);
if ($keep_ratio === false){
imagecopyresized($res['dst'], $res['src'], 0, 0, 0, 0, $dimensions['w'], $dimensions['h'], $filedata[0], $filedata[1]);
}else{
if ($filedata[0] && $filedata[1]) {
$dst['h'] = $dimensions['h'];
$dst['w'] = floor($filedata[0] * ($dimensions['h'] / $filedata[1]));
$crop['x'] = ceil(($filedata[0] - $filedata[1]) / 2);
$crop['y'] = 0;
}else{
$dst['w'] = $dimensions['w'];
$dst['h'] = floor($filedata[1] * ($dimensions['w'] / $filedata[0]));
$crop['x'] = 0;
$crop['y'] = ceil(($filedata[1] - $filedata[0]) / 2);
}
imagecopyresampled($res['dst'], $res['src'], 0, 0, $crop['x'], $crop['y'], $dst['w'], $dst['h'], $filedata[0], $filedata[1]);
}
# Schlussendlich geben wir unsere Datei aus.
imagejpeg($res['dst'], $hash);
}
header('Content-Type: ' . mime_content_type($hash));
header('Content-Length: ' . filesize($hash));
readfile($hash);