Décortiquons un script-fu pour Gimp

19 05 2009

Il n’y a pas de macro enregistrable sous The Gimp comme c’est le cas pour Photoshop. Si vous voulez automatiser des actions répétitives sous The Gimp, il faut passer par l’écriture d’un script-fu.

Plutôt que de relire toujours les mêmes scripts basiques, je vous propose d’analyser un script réel (je m’en sers régulièrement).

Splash screen The Gimp 2.6

Splash screen The Gimp 2.6

Il y a 2 façons de créer des macros ou scripts sous The Gimp :

  • Script-fu : permet d’utiliser un langage dérivé du langage Scheme, celui qui sera présenté dans ce billet, peu lisible et aisé d’accès mais présent sur la majorité des distributions de The Gimp.
  • Python-fu : permet d’utiliser le langage Python pour développer des scripts, plus lisible et aisé d’accès mais présent avant tout sous Linux.

Ces environnements profitent tous les deux du même jeu de procédures.

Le langage Scheme

Si vous êtes habitué à programmer en C, PHP ou tout autre langage procédural et/ou objet, oubliez (presque) tout !

En Scheme, tout est liste.Un appel de fonction ? une liste. Un tableau ? une liste. Une boucle ? une liste…

Et une liste s’écrit entre parenthèses.

Et il va falloir aimer imbriquer les listes, c’est moi qui vous le dit.

Vous êtes prevenus.

Procédures disponibles

The Gimp met à disposition des scripts l’ensemble des fonctions accessibles par l’utilisateurs ainsi que d’autres fonctions.

La liste complète des procédures avec leurs paramètres et un texte d’aide est disponible à travers le Navigateur de procédures. Dans The Gimp 2.6, c’est le menu Aide → Navigateur de procédures.

Navigateur de procédures de The Gimp

Navigateur de procédures de The Gimp

Le script à décortiquer

Le script que je propose de décortiquer fait les actions suivantes :

  • découpage automatique de l’image,
  • réduction de l’image à 500 pixels de large,
  • redimensionnement du canevas (pas l’image) à 510 pixels de large,
  • aplatissement de l’image,
  • ajout d’une bordure noire de 1 pixel de large :
    • sélection de toute l’image,
    • réduction de la sélection de 1 pixel,
    • inversion de la sélection,
    • remplissage de la sélection avec du noir,
    • déselection,
  • passage au mode couleurs indexées (32 couleurs),
  • correction de la première et de la dernière couleur.

Voici le code source du script :

(define (script-fu-frequentation image)
  ; Démarre un niveau de undo
  (gimp-image-undo-group-start image)

  ; Définit les couleurs d'avant-plan (noir) et d'arrière-plan (blanc)
  (gimp-context-set-foreground '(0 0 0))
  (gimp-context-set-background '(255 255 255))

  ; Découpage automatique de l'image
  (plug-in-autocrop 0 image (car (gimp-image-get-active-drawable image)))

  ; Réduit l'image à 500 pixels de large
  (let* ((old-largeur (car (gimp-image-width  image)))
         (old-hauteur (car (gimp-image-height image)))
         (new-largeur 500)
         (new-hauteur (/ (* old-hauteur new-largeur) old-largeur))
        )
    (gimp-image-scale image new-largeur new-hauteur)
  )

  ; Retaille le canevas à 510 pixels de large
  (let* ((old-largeur (car (gimp-image-width  image)))
         (old-hauteur (car (gimp-image-height image)))
         (new-largeur 510)
         (new-hauteur (/ (* old-hauteur new-largeur) old-largeur))
         (new-offsetx (/ (- new-largeur old-largeur) 2))
         (new-offsety (/ (- new-hauteur old-hauteur) 2))
        )
    (gimp-image-resize image new-largeur new-hauteur new-offsetx new-offsety)
  )

  ; Aplatit l'image
  (gimp-image-flatten image)

  ; Sélectionne toute l'image
  (gimp-selection-all image)

  ; Réduit la sélection de 1 pixel
  (gimp-selection-shrink image 1)

  ; Inverse la sélection
  (gimp-selection-invert image)

  ; Remplit la sélection de noir (couleur d'avant-plan)
  (let* ((drawable (car (gimp-image-active-drawable image))))
    (gimp-edit-bucket-fill drawable 0 0 100 0 0 0 0)
  )

  ; Déselectionne tout
  (gimp-selection-none image)

  ; Passe en mode couleurs indexées à 32 couleurs
  ; (gimp-image-convert-indexed image NO-DITHER MAKE-PALETTE 32 FALSE FALSE "")
  (gimp-image-convert-indexed image 0 0 32 0 0 "")

  ; Corrige la première et la dernière couleur
  (let* ((colormap (cadr (gimp-image-get-colormap image))))
    (aset colormap 0 0)
    (aset colormap 1 0)
    (aset colormap 2 0)

    (aset colormap 93 255)
    (aset colormap 94 255)
    (aset colormap 95 255)

    (gimp-image-set-colormap image (* 32 3) colormap)
  )

  ; Termine le niveau de undo
  (gimp-image-undo-group-end image)

)

(script-fu-register "script-fu-frequentation"
		    "<Image>/Script-Fu/AMS/Prépare la fréquentation..."
		    "Prépare la fréquentation DAP"
		    "Frédéric Bisson <zigazou@free.fr>"
		    "Frédéric Bisson"
		    "2008-11-14"
		    "RGB*"
		    SF-IMAGE "Input Image" 0
)

Le script décortiqué

Un script-fu peut contenir plusieurs macros. On parlera ici du cas classique où il n’y a qu’une seule macro définie.

Le script-fu est alors scindé en 2 parties :

  • définition de la macro : contient toutes les actions à réaliser,
  • enregistrement auprès de The Gimp : prévient The Gimp de l’existence de notre fonction et lui indique où elle va devoir se retrouver dans le menu.

Définition

(define (script-fu-frequentation image)
  ...
)

Où :

  • define : indique qu’on va définir une nouvelle fonction,
  • script-fu-frequentation : nom de la fonction qu’il est de bon ton de commencer par script-fu pour que tout le monde puisse s’y retrouver,
  • image : argument de la fonction, elle contiendra l’image en cours,
  • : actions à réaliser quand la fonction est appelée.

Démarrer un niveau undo

(gimp-image-undo-group-start image)

À la manière des rollback en base de données, on va transformer la séquence d’actions en une action unique du point de vue de l’utilisateur.

Sans cette ligne, l’utilisateur devrait faire 13 annulations pour défaire les modifications.

L’image en cours est passée en paramètre.

Définir les couleurs d’avant-plan et d’arrière-plan

Avant/arrière-plan

Avant/arrière-plan

(gimp-context-set-foreground '(0 0 0))
(gimp-context-set-background '(255 255 255))

Ces deux commandes permettent de définir :

  • l’avant-plan à noir (rouge=0, vert=0, bleu=0)
  • l’arrière plan à blanc (rouge=255, vert=255, bleu=255)

Note : L’apostrophe avant la parenthèse indique au langage Scheme de ne pas chercher à exécuter le contenu de la liste (il s’agit ici uniquement de valeurs).

Découpage automatique de l’image

(plug-in-autocrop 0 image (car (gimp-image-get-active-drawable image)))

La commande plug-in-autocrop prend 3 paramètres :

  • 0 : demande au plug-in de fonctionner en mode non-interactif,
  • image : image sur laquelle effectuer l’opération,
  • (car (gimp-image-get-active-drawable image)) : récupère le drawable actif de l’image. La commande gimp-image-get-active-drawable retourne une liste et la commande car permet de récupérer le premier élément de cette liste.

Cette commande est équivalente au menu Image → Découpage automatique de l’image

Menu Image → Découpage automatique de l’image

Découpage automatique de l’image

Notes sur les drawable :

  • un drawable est une zone sur laquelle on peut effectuer des opérations,
  • une image peut contenir plusieurs drawable.
  • un calque et un masque de calque sont des drawable.

Réduction de l’image

(let* ((old-largeur (car (gimp-image-width  image)))
       (old-hauteur (car (gimp-image-height image)))
       (new-largeur 500)
       (new-hauteur (/ (* old-hauteur new-largeur) old-largeur))
      )
  (gimp-image-scale image new-largeur new-hauteur)
)

La commande let* permet de créer des variables locales au bloc :

  • old-largeur : récupère la largeur actuelle de l’image,
  • old-hauteur : récupère la hauteur actuelle de l’image,
  • new-largeur : nouvelle largeur fixée à 500 pixels,
  • new-hauteur : calcule la nouvelle hauteur pour qu’elle soit proportionnelle à la hauteur actuelle, notez l’écriture bizarre du calcul qui revient à faire (old-hauteur×new-largeur)/old-largeur.

Une fois new-largeur et new-hauteur calculées, il suffit d’appeler la commande gimp-image-scale qui correspond à menu Image → Échelle et taille de l’image….

Échelle et taille de l’image

Échelle et taille de l’image

Note : gimp-image-scale prend le mode d’interpolation par défaut (Aucun, Linéaire, Bicubique, Lanczos 3). Il est possible de forcer un mode d’interpolation en utilisant gimp-image-scale-full.

Retaille le canevas à 510 pixels de large

(let* ((old-largeur (car (gimp-image-width  image)))
       (old-hauteur (car (gimp-image-height image)))
       (new-largeur 510)
       (new-hauteur (/ (* old-hauteur new-largeur) old-largeur))
       (new-offsetx (/ (- new-largeur old-largeur) 2))
       (new-offsety (/ (- new-hauteur old-hauteur) 2))
      )
  (gimp-image-resize image new-largeur new-hauteur new-offsetx new-offsety)
)

La commande let* permet de créer des variables locales au bloc :

  • old-largeur, old-hauteur, new-largeur, new-hauteur : le principe est le même que pour l’explication précédente,
  • new-offsetx, new-offsety : décalage de l’image actuelle dans le nouveau canevas, valeurs calculées pour placer l’image au centre.

La commande gimp-image-resize correspond au menu Image → Taille du canevas…

Taille du canevas

Taille du canevas

Aplatit l’image

(gimp-image-flatten image)

La commande gimp-image-flatten correspond au menu Image → Aplatir l’image.

Menu Image → Aplatir l’image

Menu Image → Aplatir l’image

Sélectionne toute l’image

(gimp-selection-all image)

La commande gimp-selection-all correspond au menu Sélection → Tout.

Menu Sélection → Tout

Menu Sélection → Tout

Réduit la sélection de 1 pixel

(gimp-selection-shrink image 1)

La commande gimp-selection-shrink correspond au menu Sélection → Réduire…

Réduire la sélection

Réduire la sélection

Inverse la sélection

(gimp-selection-invert image)

La commande gimp-selection-invert correspond au menu Sélection → Inverser.

Menu Sélection → Inverser

Menu Sélection → Inverser

Remplit la sélection de noir

Outil pot de peinture

Outil pot de peinture

(let* ((drawable (car (gimp-image-active-drawable image))))
 (gimp-edit-bucket-fill drawable 0 0 100 0 0 0 0)
)

La commande gimp-edit-bucket-fill correspond à l’outil pot de peinture. Elle travaille sur un drawable et non sur l’image.

Cette commande prend 8 paramètres :

  • drawable : le calque sur lequel effectuer le remplissage,
  • 0 : type de remplissage, 0=couleur de premier plan,
  • 0 : mode de remplissage, 0=mode normal,
  • 100 : opacité en pourcentage,
  • 0 : seuil de sensibilité,
  • 0 : utiliser l’option Remplir via Composite, 0=non,
  • 0 0 : coordonnée x et y où effectuer le remplissage.

Désélectionne tout

(gimp-selection-none image)

La commande gimp-selection-none correspond au menu Selection → Aucune.

Menu Sélection → Aucune

Menu Sélection → Aucune

Mode couleurs indexées

(gimp-image-convert-indexed image 0 0 32 0 0 "")

Les paramètres utilisées sont :

  • image : l’image à convertir,
  • 0 : tramage des couleurs, 0=pas de tramage,
  • 0 : type de palette, 0=générer une palette optimale,
  • 32 : nombre de couleurs,
  • 0 : active le tramage de la transparence, 0=non,
  • 0 : enlever les couleurs non utilisées de la palette, 0=non,
  • “” : nom de la palette, inutilisé pour une palette optimale.

La commande gimp-image-convert-indexed correspond au menu Image → Mode → Couleurs indexées…

Mode couleurs indexées

Mode couleurs indexées

Corrige les couleurs

(let* ((colormap (cadr (gimp-image-get-colormap image))))
  (aset colormap 0 0)
  (aset colormap 1 0)
  (aset colormap 2 0)

  (aset colormap 93 255)
  (aset colormap 94 255)
  (aset colormap 95 255)

  (gimp-image-set-colormap image (* 32 3) colormap)
)

La commande let* permet de créer une variable locale au bloc. La variable colormap reçoit ainsi la palette de couleurs utilisées par l’image courante sous forme de liste.

La liste contient 1 valeur par composante (rouge, vert, bleu). La palette ayant été précisée à l’étape précédente à 32 couleurs, on a donc une liste de 96 valeurs :

  • les valeurs d’index 0, 1, 2 correspondent aux composantes de la première couleur,
  • les valeurs d’index 93, 94, 95 correspond aux composantes de la dernière couleur.

La commande aset permet de positionner une valeur dans la liste. Il faut donc 3 appels à cette commande pour modifier une couleur de la palette.

Finalement, la commande gimp-image-set-colormap permet de réaffecter la palette de couleurs ainsi créée à l’image. Ses paramètres sont :

  • image : l’image à modifier,
  • (* 32 3) : nombre d’entrées dans la liste (32 couleurs×3 composantes),
  • colormap : la nouvelle palette.

La commande gimp-image-set-colormap est équivalente à l’action de modifier la palette :

Réglage de la palette

Réglage de la palette

Termine le niveau undo

(gimp-image-undo-group-end image)

La commande gimp-image-undo-group-end permet de terminer le bloc undo débuté au tout début de la fonction.

Enregistre la macro auprès de The Gimp

(script-fu-register "script-fu-frequentation"
                    "<Image>/Script-Fu/AMS/Prépare la fréquentation..."
                    "Prépare la fréquentation DAP"
                    "Frédéric Bisson <zigazou@rouen.fr>"
                    "Frédéric Bisson"
                    "2008-11-14"
                    "RGB*"
                    SF-IMAGE "Input Image" 0
)

La commande script-fu-register permet de prévenir The Gimp de l’existence de notre fonction avec les paramètres suivants :

  • “script-fu-frequentation” : la fonction à enregistrer s’appelle script-fu-frequentation,
  • “<Image>/Script-Fu/AMS/Prépare la fréquentation…” : la fonction sera accessible depuis le menu Script-Fu → AMS → Prépare la fréquentation,
  • “Prépare la fréquentation DAP” : description de la fonction,
  • “Frédéric Bisson <zigazou@rouen.fr>” : auteur
  • “Frédéric Bisson” : copyright,
  • “2008-11-14″ : date de création/modification,
  • “RGB*” : modes de couleurs supportés (RGB*=RGB+RGBA),
  • SF-IMAGE “Input Image” 0 : premier et seul paramètre de la fonction.

Actions

Information

6 réponses

19 05 2009
Daily News About Linux : A few links about Linux - Tuesday, 19 May 2009 14:39

[...] Décortiquons un script-fu pour Gimp [...]

31 08 2009
Bean

Bonjour,
j’ai lu votre article avec beaucoup d’intérêt.
Je suis en train de créer un script fu pour régler le niveau d’une image.
ça se passe les étapes suivantes:
je copie l’image dans gimp
crée un nouveau calque avec opacité 40 et couleur grise, et nommé “calque”
fusionne les deux calque
modifier le niveau.
J’ai déjà fais une partie du code, mais quand je teste, il y a un message d’erreur : “Error: eval: unbound variable: calque

Pourriez vous m’aider pour réaliser ce script?
Merci d’avance

Voici le code:
(define (script-fu-niveaux-bean image)

;demarrer undo
(gimp-image-undo-group-start image)

;Nouveau calque
(gimp-layer-new image 1000 1000 RGBA-IMAGE “calque” 100 NORMAL)
(gimp-image-add-layer image calque -1)

;definir la couleur grise
(gimp-context-set-foreground ‘(233 233 233))

;Remplissage
(gimp-edit-bucket-fill “calque” 0 0 40 0 0 0 0)

;Termine le niveau de undo
(gimp-image-undo-group-end image)
)

(script-fu-register “script-fu-niveaux-bean
“/Script-Fu/AMS/Niveaux bean…”
“Traitement”
“”
“Bean”
“2009-08-31″
“RGB*”
SF-IMAGE “Input Image” 0

)

31 08 2009
zigazou

Bonjour,

Le problème vient de ces 2 lignes :
(gimp-layer-new image 1000 1000 RGBA-IMAGE “calque” 100 NORMAL)
(gimp-image-add-layer image calque -1)

Tout d’abord, il ne faut pas confondre “calque” et calque : le premier est une chaîne de caractère tandis que le second est un nom de variable.

Ensuite, la deuxième ligne tente d’utiliser la variable calque qui n’a été définie nulle part ailleurs.

Il faudrait procéder comme suit :
(let* ((calque (gimp-layer-new image 1000 1000 RGBA-IMAGE “calque” 100 NORMAL)))
(gimp-image-add-layer image calque -1)
)

(code non testé mais ça devrait être grosso-modo la source du problème)

1 09 2009
Bean

Effectivement il s’agit de la déclaration de variable, merci beaucoup.
Par contre maintenant c’est la fonction de remplissage qui pose problème: j’aimerais remplir le nouveau calque d’une couleur grise d’opacité 40. Mais:
soit je mets : (gimp-edit-bucket-fill calque 0 0 40 0 0 0 0)) ça ne marche pas à cause de la déclaration de variable probablement,
soit en utilisant votre code (let* ((drawable (car (gimp-image-active-drawable image))))
(gimp-edit-bucket-fill drawable 0 0 40 0 0 0 0)
))
ça ne marche pas non plus,
pour plus de précision je vous recopie le code entier:
(define (script-fu-niveaux-bean image calque)

;demarrer undo
(gimp-image-undo-group-start image)

;Nouveau calque
(let* (
(largeur (car (gimp-image-width image)))
(hauteur (car (gimp-image-height image)))
(calque 0)
)

(set! calque(car (gimp-layer-new image
largeur
hauteur
RGBA-IMAGE
“calque”
100
NORMAL)))
(gimp-image-add-layer image calque -1)

;definir la couleur grise
(gimp-context-set-foreground ‘(233 233 233))

;Remplissage
;(gimp-edit-bucket-fill calque 0 0 40 0 0 0 0))
(let* ((drawable (car (gimp-image-active-drawable image))))
(gimp-edit-bucket-fill drawable 0 0 40 0 0 0 0)
))

;Termine le niveau de undo
(gimp-image-undo-group-end image)
)

(script-fu-register “script-fu-niveaux-bean”
“/Script-Fu/AMS/Niveaux-bean…”
“Traitement”
“”
“Bean”
“2009-08-31″
“RGB*”
SF-IMAGE “Input Image” 0
SF-DRAWABLE “calque” 0)

1 09 2009
Bean

finalement ça marche, j’ai utilisé la procédure gimp-edit-fill au lieu de gimp-edit-bucket-fill

du coup j’ai pu aussi faire la fusion des calques et le niveaux, j’ai juste à faire en sorte que tout ceci se fait par lot

Merci

1 09 2009
zigazou

Cool, content pour toi !

@+

Laisser un commentaire