TOP
tetris Programmez un Tetris en Java
360 pages PDF pour apprendre à votre rythme.
Développez des jeux vidéo en Java.
www.jdevmaker.com
Gimp 2.4
Documentation
Tutoriels
Ressources
Divers

Dernière mise à jour le 07 avr 2008
consultée 4712 fois
Apprendre  ›  Écrire un script-fu  ›  Tutoriel partie 10

 

Scheme, Tutoriel : Initiation avancée partie 10

Ce document est sous un contrat Creative Commons.

 

Maintenant, le niveau va devenir plus élevé. Assurez-vous avant de poursuivre d'avoir parfaitement intégré la partie Initiation, et voyons les variables globales et locales.

Précisons que cette notion de variable globales et locales est un peu "du pinaillage" pour l'écriture de script-fu, alors que cela ne l'est absolument pas pour l'écriture d'une application. Cela dit, nombre de script-fu utilisent des variables globales et locales, il vaut donc mieux savoir ce que c'est, plutôt que risquer de ne rien y comprendre.

Pour rappel voici l'état actuel de notre script :

10 (define (script-fu-nouveau-calque-rapide image drawable) ;; declaration de la fonction
15 (gimp-image-undo-group-start img) ;; début d'historique d'annulation
20 (set! width (car (gimp-image-width img))) ;; variable de largeur de l'image
30 (set! height (car (gimp-image-height img))) ;; variable de hauteur de l'image
40 (set! new-layer (car (gimp-layer-new img width height RGBA-IMAGE "Nom du calque" 100 NORMAL)))
45 (gimp-edit-clear new-layer)
50 (gimp-image-add-layer img new-layer -1)
85 (gimp-image-undo-group-end img) ;; fin d'historique d'annulation
90 ) ;; fin de la fonction
 
100 (script-fu-register "script-fu-nouveau-calque-rapide" ;; nom du script
110 "<Image>/Perso/Quick Layer" ;; position du script dans le menu
120 "Cree un calque directement, sans dialogue" ;; commentaires
130 "Auteur" ;; auteur
140 "Copyright" ;; copyright
150 "Date" ;; date
160 "" ;; types d'images supportés par le script
170 SF-IMAGE "Image" 0 ;; image dans lequel le calque est ajouté
180 SF-DRAWABLE "Drawable" 0 ;; calque actif de l'image
190 ) ;; fin du register

 

Introduction

A ce niveau, il nous faut encore revenir sur les variables afin d'être plus "averti" ; bien entendu, cela devient un peu plus complexe, mais comme toujours je vais tâcher d'expliqué cela simplement.

Il nous faut distinguer les variables globales des variables locales.

>Faisons une analogie avec le commerce. Les variables globales sont le commerce International, tandis que les variables locales sont un commerce de proximité, régional. La fonction de notre script (ou éventuellement tout le script), c'est la planète Terre.

Le commerce de proximité ne s'étend pas au delà d'une certaine région, il couvre une zone locale, alors que le commerce International couvre la globalité du territoire accessible. Se dégage de cela une notion d'accessibilité, de disponibilité. Ainsi un habitant de Tokyo aura accès au commerce local de sa ville, ou au commerce International, mais pas au commerce local de l'Auvergne. En revanche, un Auvergnat aura accès au commerce local de l'auvergne, ainsi qu'au commerce international, mais pas au commerce local de Tokyo.

Cette notion de disponibilité s'appelle la portée (on parle aussi de visibilité).

 

Mises au point

Les variables globales sont appelées ainsi (on parle aussi de variables publiques), parce qu'elles sont accessibles partout, et pas seulement à l'intérieur de la "zone" dans laquelle elles ont été déclarées.

Les variables locales sont appelées ainsi (on parle aussi de variables privées) sont disponibles seulement dans la "zone" où elles ont été déclarées.

On apprend souvent que les variables globales sont définies par la commande set! (ou à la rigueur define), et les variables locales par la commande let*. C'est parfois inexact.

Une variable est globale a partir du moment où sa portée est globale. Je précise cela parce que bien qu'ayant défini des variables avec set!, vos variables peuvent être malgré tout locales. En revanche, toutes variables déclarées par let* seront nécessairement locales.

Procédons par ordre !

 

Les variables accessibles dans la fonction.

Consultez le script du début de page.

Les variables img et drawable (ligne 10) sont des variables déclarées au moment de la déclaration de la fonction script-fu-nouveau-calque-rapide, ainsi elles doivent être considérées comme locales : elles sont accessibles dans toute la fonction, mais pas dans tout le script.

Vous pouvez faire appel a elles n'importe où du moment que vous vous trouvez à l'intérieur de la fonction script-fu-nouveau-calque-rapide.

Cependant comme elles ont précisément été déclarées dans cette fonction, elles ne sont accessible QUE dans cette fonction, et nulle part ailleurs. Ainsi, dans l'hypothèse ou nous ajouterions une seconde fonction bidule,  ces 2 variables ne seraient pas accessible dans la fonction bidule.

Cela est aussi valable pour les variables width et height.

Et pourtant, nous avons utilisé dans un cas define et dans l'autre set!.

 

Nous allons aussi revenir sur cette règle que j'avais énoncé dans la partie 5, un nom unique par variable.

Bien ! Cessons la théorie et mettons en évidence que img et drawable sont locales.

 

Remplir

Avant voyons 2 autres commandes de l'API de Gimp. Ajoutez une nouvelle ligne 60 :

(gimp-edit-fill new-layer 0) ;; remplir de la couleur PP

Cela nous permet de remplir la calque new-layer de la couleur de premier plan.

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Désormais le nouveau calque est rempli de la couleur de premier plan. Vous remarquerez sans doute que cela semble se comporter bizarrement dans le sens ou il vous faut cliquez sur le calque "Arrière-plan" pour que l'image soit correctement affichée.

Rajoutez une ligne 70 :

(gimp-displays-flush) ;; actualise l'image

Cette commande s'insère en fin de script afin que l'image s'affiche correctement, et palit au tout petit problème que nous avions plus haut.

Nous avons donc le script suivant :

10 (define (script-fu-nouveau-calque-rapide image drawable) ;; declaration de la fonction
15 (gimp-image-undo-group-start img) ;; début d'historique d'annulation
20 (set! width (car (gimp-image-width img))) ;; variable de largeur de l'image
30 (set! height (car (gimp-image-height img))) ;; variable de hauteur de l'image
40 (set! new-layer (car (gimp-layer-new img width height RGBA-IMAGE "Nom du calque" 100 NORMAL)))
45 (gimp-edit-clear new-layer)
50 (gimp-image-add-layer img new-layer -1)
60 (gimp-edit-fill new-layer 0) ;; remplir de la couleur PP
70 (gimp-displays-flush) ;; actualise l'image
85 (gimp-image-undo-group-end img) ;; fin d'historique d'annulation
90 ) ;; fin de la fonction
 
100 (script-fu-register "script-fu-nouveau-calque-rapide" ;; nom du script
110 "<Image>/Perso/Quick Layer" ;; position du script dans le menu
120 "Cree un calque directement, sans dialogue" ;; commentaires
130 "Auteur" ;; auteur
140 "Copyright" ;; copyright
150 "Date" ;; date
160 "" ;; types d'images supportés par le script
170 SF-IMAGE "Image" 0 ;; image dans lequel le calque est ajouté
180 SF-DRAWABLE "Drawable" 0 ;; calque actif de l'image
190 ) ;; fin du register

Nous allons obtenir la même chose, en passant par une autre fonction. Cette nouvelle fonction n'a pas vraiment de raison d'être si ce n'est à démontrer la portée de img et drawable. Elle pourrait se justifier concrètement par le fait qu'elle est accessible partout dans le script. Ainsi elle peut être appelé à partir de n'importe qu'elle autre fonction. On peut aussi appeler autant de fois que l'on veut cette fonction, a chaque fois par une seule ligne de code et donc déclencher une tâche complexe susceptible d'être demandée plusieurs fois, ce qui évite la réécriture de ce même code.

Voici donc les lignes 3,5 et 7 :

3 (define (fonction-remplir img2 drawable2)
5 (gimp-edit-fill drawable2 0)
7 )

Le nom de la fonction est fonction-remplir.

Remplacez la ligne 60 par :

(fonction-remplir img new-layer) ;; appeler la fonction "fonction-remplir"

soit,

3 (define (fonction-remplir img2 drawable2) ;; seconde fonction
5 (gimp-edit-fill drawable2 0) ;; remplir le calque
7 ) ;; fin de la 2eme fonction
10 (define (script-fu-nouveau-calque-rapide image drawable) ;; declaration de la fonction
15 (gimp-image-undo-group-start img) ;; début d'historique d'annulation
20 (set! width (car (gimp-image-width img))) ;; variable de largeur de l'image
30 (set! height (car (gimp-image-height img))) ;; variable de hauteur de l'image
40 (set! new-layer (car (gimp-layer-new img width height RGBA-IMAGE "Nom du calque" 100 NORMAL)))
45 (gimp-edit-clear new-layer)
50 (gimp-image-add-layer img new-layer -1)
60 (fonction-remplir img new-layer) ;; appeler la fonction "fonction-remplir"
70 (gimp-displays-flush) ;; actualise l'image
85 (gimp-image-undo-group-end img) ;; fin d'historique d'annulation
90 ) ;; fin de la fonction
 
100 (script-fu-register "script-fu-nouveau-calque-rapide" ;; nom du script
110 "<Image>/Perso/Quick Layer" ;; position du script dans le menu
120 "Cree un calque directement, sans dialogue" ;; commentaires
130 "Auteur" ;; auteur
140 "Copyright" ;; copyright
150 "Date" ;; date
160 "" ;; types d'images supportés par le script
170 SF-IMAGE "Image" 0 ;; image dans lequel le calque est ajouté
180 SF-DRAWABLE "Drawable" 0 ;; calque actif de l'image
190 ) ;; fin du register

Nous disons en ligne 3 à cette fonction fonction-remplir que 2 variables devront "lui être passé" lorsqu'elle sera appelée. Variables que nous appelons img2 et drawable2. En ligne 60, nous passons le contenu des variables img et drawable respectivement dans img2 et drawable2. De sorte img2 sera égal à img, et drawable2 à drawable.

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Le résultat est le même !

 

Locales vous dis-je !

Quel rapport avec les variables globales ou locales ? Aucun pour l'instant. Modifiez maintenant la ligne 3 et 5 par,

(define (fonction-remplir img drawable)
(gimp-edit-fill drawable 0)

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Nous utilisons des noms de variables identiques à celles utilisées dans la fonction script-fu-nouveau-calque-rapide, cela nous est permis car ces variables sont limitées dans leurs portées respectives. Ce ne sont pas les mêmes, bien qu'ayant des noms identiques. Il est a noter que dans la fonction script-fu-nouveau-calque-rapide, drawable fait référence au calque actif, alors que dans notre fonction fonction-remplir, drawable fait référence au nouveau calque créé (new-layer).

De même démontrons que width et height sont aussi locales et non globales. Rajoutez une ligne 4 :

(set! height 0)

et remplacez la ligne 5 :

(gimp-edit-fill drawable height)

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Nous utilisons deux variables height, mais ces variables sont locales, elles ne sont pas identiques, elles sont seulement disponibles dans la fonction dans laquelle ces variables ont été déclarées. Dans le premier cas height=0, dans le second la valeur de hauteur de l'image active.

Supprimez les lignes 3,5,7,60 et 70.

 

Variables globales

Nous ne pouvons plus avoir 2 variables portant le même nom lorsque l'une d'entre elle est globale, il y a conflit. Gimp prendra en compte la dernière rencontrée ignorant l'autre.

Nous allons transformé notre variable locale height en variable globale.

Insérer une ligne 5 :

(set! height 100)

Ajoutez 2 point-virgule au début de la ligne 30, afin de la transformer en commentaire (elle ne sera pas considéré comme du code) :

;; (set! height (car (gimp-image-height img)))

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Tous les calques créés ont une hauteur constante de 100 pixels.

Comme la variable height n'est pas déclarée dans une fonction particulière elle est globale, c'est à dire accessible à partir de n'importe qu'elle autres fonctions, soit dans la totalité du script.

 

Variables locales avec let*

Il est recommandé, lorsque l'on veut écrire un programme dans les règles, de favoriser au maximum les variables locales au détriment des variables globales. C'est un concept général, vrai pour tous les langages de programmation.

Cela bien évidement, n'est pas toujours possible, et vous aurez sans doute besoin de variables globales.

En Scheme, il est de bon ton de favoriser les variables locales déclarées par let*. Là encore ce ne sera pas toujours possible, essayez simplement d'éviter le plus possible la commande set!.

Bien évidement toutes les variables des paramètres du script-fu-register devront êtres déclarées par define, c'est incontournable.

 

La commande let* s'exprime ainsi :

(let*                       ;; début du let* / début de la portée des variables
   (                         ;; ouverture déclaration de variables
   (variable1 x)         ;; variable(s) et sa valeur(s)
   (variable2 y)
   etc...
   )                         ;; fermeture déclaration de variables
  (tache1)               ;; tâche(s)
  (tache2)
  (tache3)
  etc...
 )                           ;; fin du let / fin de la portée des variables

Bien sur il peut y avoir une ou plusieurs variables déclarées, une seule ou plusieurs tâches. Les variables ainsi déclarées ont une portée limitée, située entre les extrêmes parenthèses du let*.

 

Tapez,

(let* ((variable 5)) (/ variable 2))

Dans la console script-fu, vous obtiendrez le résultat, soit (s'il ne fait pas d'erreur de calcul) 2.5 !

Cette forme, adaptée à notre script donne ce qui suit :

10 (define (script-fu-nouveau-calque-rapide image drawable) ;; declaration de la fonction
20 (gimp-image-undo-group-start img) ;; début d'historique d'annulation
30    (let*
35           (
40           (width (car (gimp-image-width img)))
45           (height (car (gimp-image-height img)))
50           (new-layer (car (gimp-layer-new img width height RGBA-IMAGE "Nom du calque" 100 NORMAL)))
55           )
60         (gimp-edit-clear new-layer)
70         (gimp-image-add-layer img new-layer -1)
75   );; fin du let

80 (gimp-image-undo-group-end img) ;; fin d'historique d'annulation
90 ) ;; fin de la fonction
 
100 (script-fu-register "script-fu-nouveau-calque-rapide" ;; nom du script
110        "<Image>/Perso/Quick Layer" ;; position du script dans le menu
120        "Cree un calque directement, sans dialogue" ;; commentaires
130        "Auteur" ;; auteur
140        "Copyright" ;; copyright
150        "Date" ;; date
160        "" ;; types d'images supportés par le script
170        SF-IMAGE "Image" 0 ;; image dans lequel le calque est ajouté
180        SF-DRAWABLE "Drawable" 0 ;; calque actif de l'image
190 ) ;; fin du register

Enregistrez et faites Rafraîchir les script-fu. Puis testez le script.

Le résultat est le même, mais width et height sont désormais des variables purement locale.

Remarquez que les variables déclarées à l'intérieur du let ont une portée encore plus réduite que précédemment. Cependant, nous pourrions ensuite écrire d'autres procédures, et développer ainsi le script. Les variables width et height n'y serait pas accessible.

C'est cette notion de portée qu'il faut bien comprendre. Toutes variables déclarées dans un let ne seront disponible qu'a l'intérieur de celui-ci. Ainsi si vous avez besoin de ces variables dans vos procédures, vos procédures doivent être écrites aussi à l'intérieur du let. Si cela n'est pas possible, rendez vos variables globales. Vous voyez que désormais, cela se complique un peu, et que l'écriture d'un script doit passer par une phase de conception, où l'on "pense" le script avant de l'écrire.

 

 

Valide XHTML 1.0 Strict
Valide CSS 2.0
Valide Accessibilité
Creative Commons License

Tous les documents et ressources sont sous un contrat Creative Commons.