Articles taggés gd

symfony

Manipulation d’images sous Symfony2

0

Dans un article précédent, je montrais une bibliothèque permettant de manipuler des images d’une manière un peu particulière, mais à mon sens intéréssant. Ici, nous allons parler de la façon dont cette bibliothèque peut s’intégrer à Symfony2.

Je travaille actuellement sous Symfony2 et j’ai été amené à manipuler des images dans une application que je développe. Ayant déjà sous la main ma propre classe de gestion d’images, j’ai décidé de l’intégrer au framework à l’aide d’un Bundle. Comme vous pourrez le remarquer si vous jetez un oeil au projet git correspondant, l’intégration de la classe dans un bundle Symfony2 ne nécéssite pas beaucoup de code supplémentaire.

Installation

Commencez par placer le dépôt git dans vos dépendances et clonez-le. Ajoutez alors l’espace de nom Gregwar à votre app/autoloader.php :

'Gregwar' => __DIR__.'/../vendor/gregwar-image/bundle/',

Une fois fait, ajouter le bundle à votre app/AppKernel.php :

...
public function registerBundles()
{
$bundles = array(
...
new Gregwar\ImageBundle\GregwarImageBundle(),
...
);
...

Il ne vous reste plus qu’à ajouter à votre fichier de configuration (ex: app/config/config.yml) :

gregwar_image: ~

Puis, créez le dossier web/cache et donnez les permissions à apache d’écrire dedans

mkdir web/cache
chmod 777 web/cache

Si vous voulez utiliser un autre nom, précisez le dans la configuration:

gregwar_image:
   cache_dir: mes_fichies_caches

Services fournis

Ce Bundle Symfony2 vous fournit principalement deux choses:

  1. Un service image.handling permettant d’utiliser la classe Gregwar\Image avec l’injection de dépendance;
  2. Un helper twig, qui vous permet d’utiliser les fonctionnalités de Gregwar\Image directement dans vos templates

Je ne m’attarderais pas sur le premier point, vous l’aurez vite compris, vous pouvez écrire des lignes de la forme:

$this->get('image.handling')->open('linux.jpg')
    ->grayscale()
    ->rotate(12)
    ->save('out.jpg')

Dans vos contrôleurs ou dans n’importe quel classe ayant accès aux services, ce qui peut s’avérer pratique !

La partie intéréssante repose sur l’helper Twig, qui peut être très utile en tirant profit du dossier de cache. Le bundle enregistre la fonction twig image() qui fournit la même API qu’avec la classe Gregwar\Image. Un exemple:

<!-- template.html.twig -->

<img src="{{ image('linux.png').resize('30%').rotate(-12).jpeg }}" />

Le résultat sera alors l’adresse du fichier de cache hashé. Petit bonus: cet helper fait lui-même appel à l’helper asset() pour le chemin du fichier de cache.

Vous pouvez également profiter de l’API de la classe image:

linux.png a une largeur de {{ image('linux.png').width }} px

Dépôt Gregwar/ImageBundle sur Github

Image d'origine, 200x92

Maitrisez la taille de vos images

2

Voici une solution générique au problème souvent rencontré de la gestion de la taille des images. En effet, et comme vous le savez, redimensionner un objet <img> a tendance à faire charger à l’utilisateur une image beaucoup trop grosse pour ce qu’il en verra, de plus les navigateurs n’ont pas toujours de modules d’anti-aliasing. La solution bien connue est de générer, coté serveur, des images de la bonne dimension (qu’il s’agisse de miniature ou pas).

J’ai écrit cette classe pour essayer de me débarasser de ce problème ennuyeux, voici comment elle fonctionne.

Chargement d’une image

Tout d’abord, il faut instancier l’image, puis lui dire quel fichier charger

$i = new Image;
$i->fromFile("image.jpg");

Le paramètre peut aussi être passé directement dans le constructeur, afin de gagner de la place:

$i = new Image("image.jpg");

Appliquer une redimension

Il existe ensuite plusieurs façon de redimensionner l’image, voici des exemples pour mieux comprendre.

Image d'origine, 200x92

$i->;resize(300,200), réduit éventuellement l'image mais ne l'agrandit jamais (pratique pour les miniatures)

$i->scaleResize(300,200), redimensionne l'image en gardant le ratio de maniere a la faire tenir dans la place attribuée

$i->forceResize(300,200), force l'image a faire exactement la taille donnée, sans que le ratio ne compte (peut déformer)

$i->forceResize(null, 120), force l'image a faire 120 de hauteur, le ratio sera gardé

$i->cropResize(150,100), fonctionne comme resize mais coupe l'espace blanc autour de l'image (revient à limiter la largeur et la hauteur)

Chaîne d’opération

Notons que tout l’interêt du code que je présente ici est que les opérations ne sont pas appliquées. En effet apres une ouverture (fromFile) et une redimension (resize…) la classe n’a strictement rien fait d’autre que d’enregistrer tout ce qui lui est demandé. Il est alors possible de la forcer à effectuer les opérations et à sauvegarder l’image avec la fonction save() (voir plus bas). Mais l’option la plus interessante est de lui demander d’utiliser son système de cache de manière à tout gérer automatiquement.

En appellant la méthode cacheFile(), la classe commencera à calculer un hash de tout ce qui lui est demandé (les opérations, le fichier d’origine, le format demandé etc.) et générera alors un nom de fichier de cache. Si ce fichier existe, elle ne fera strictement rien d’autre que de retourner le nom de ce fichier. Si il n’existe pas, elle appellera save(), la fonction permettant de générer l’image en la sortant dans le fichier de cache.

Les fonctions jpeg(), gif() et png() sont des raccourcis de cacheFile().

Exemples et raccourcis

Voici un exemple d’execution détaillé:

//Créé l'instance
$i = new Image;
//Charge l'image "image.jpg"
$i->fromFile("image.jpg");
//Utilise une redimension non-agrandissante dans une boite 300x200
$i->resize(300, 200);
//Applique les modifications ou alors récupere le cache correspondant
// $file contiendra le nom du fichier cache obtenu
$file = $i->jpeg();

Et la version raccourcie, grace à la définition de la fonction Image() et des return $this; Imaginez que vous écriviez une gallerie photo dans laquelle vous souhaitez mettre des miniatures en 120×120:


L’interêt est de mêler étroitement la simplicité d’écriture et les performances. Lorsque le fichier de cache existe déja, l’utilisation de la classe Image ne nécessite que le calcul d’un hash et quelques vérifications. Une fois le dossier de cache correctement configuré, cette ligne suffira a maitriser le rendu des images.

Autre utilisation, rendu dans un fichier

Nous voudrons parfois pouvoir utiliser ce système non pas à l’affichage, mais à un instant précis du code. Pour cela vous pouvez utiliser la fonction save($fichier, $format= »jpg », $qualite=80).

//Ouverture de l'image
$i = new Image($file_name);
//Utilise une redimension non-agrandissante dans une boite 120x120
$i->resize(120, 120);
//Sauvegarde le résultat dans le répertoire des miniatures (thumb)
$i->save($thumb_dir.$file_name, "jpg");

Pour conclure voici les sources de la classe en question:
Voir le code source de la classe Image

Haut de page