Dans les exemples ci-dessous, on ne va pas modifier de pixels existants (principe du filtre photo) mais créer des images. Les filtres seront donc des filtres de rendu, et c'est parmi les filtres de rendu qu'on va les placer.
Pour éviter d'alourdir les scripts, on ne leur demande pas de créer l'image en la dimensionnant et d'y ajouter un calque (l'image et le calque sont des objets) mais on va créer une image sous Gimp, ce qui permet de choisir ses dimensions et la dote automatiquement d'un calque. Ces lignes économisées en Python vont d'ailleurs faire intervenir les deux objets "image" et "calque" par lecture de leurs propriétés (par exemple leur taille) sous "Python". Dans le langage de la programmation objet, on dira que l'instanciation est faite par l'utilisateur sous "Gimp" et non par "Python".
=Fonction de deux variables=
Comme les coordonnées sous "Gimp" sont entières, on peut représenter graphiquement le pgcd de ces coordonnées comme une image 2D. La première ligne sert à expliquer au moteur "Gimp" que c'est un filtre "Python" qu'on met en place:
import math
from math import *
from gimpfu import *
Et pendant qu'on y est, on importe les fonctions mathématiques et l'extension "gimpfu" (les trois dernières lignes ci-dessus).
Algorithme d'Euclide en Python.
L'algorithme d'Euclide pour calculer un pgcd peut se résumer à la description suivante:
On peut aussi le décrire "impérativement" par l'algorithme suivant:
Python permet aisément d'affecter simultanément deux variables, ce qui raccourcit considérablement le code (en plus, le test de non-divisibilité de a par b revient au calcul du reste euclidien de a par b, interprété booléennement comme "faux" par "Python" tant qu'il est non nul):
def gcd(a,b):
 while(a%b):
 a,b=b,a%b
 return b
Création du filtre.
Pour éviter d'avoir à créer et dimensionner l'image sous "Python", on va la considérer comme une variable d'entrée du script (le filtre). Comme on le voit plus bas dans la partie "enregistrement" du script, l'image est un objet "Python" appelé ici "img" (c'est une variable locale). Le script s'appelle "python_pgcd" et il est constitué d'une fonction portant non sur des nombres, mais sur des images. Que fait donc ce script?
def python_pgcd(img) :
 largeur=img.width
 hauteur=img.height
 calque=img.layers[0]
 for x in range(largeur):
 for y in range(hauteur):
 g=gcd(x+1,y+1)%256
 couleur=(g,0,0)
 calque.set_pixel(x,y,couleur)
Enregistrement dans la base de données.
Pour pouvoir tester ce filtre, il est donc nécessaire de l'enregistrer dans la base de données de "Gimp" (avant de lancer celui-ci). Ce qui se fait en entrant un texte de ce genre en bas du script:
register(
 "pgcd",
 "pgcd de x et y",
 "rendu du pgcd",
 "Auteur du script",
 "Licence GPL",
 "2010",
 "calcul des pgcd...",
 [
 (PF_IMAGE,"img","image vide",None)
 [],
 python_pgcd,
 menu="<Image>/Filters/Render")
Le texte entre crochets signifie que la fonction "python_pgcd" dont le nom figure juste au-dessous, a une variable (puisque la liste de ses variables ne contient qu'une entrée!), que celle-ci est du type "PF_IMAGE", qu'elle s'appelle "img", que son titre est "image vide" et qu'elle n'a pas de valeur par défaut.
Pour finir d'enregistrer le filtre, il reste à dire où. Et ci-dessus, c'est dans le sous-menu des rendus, lui-même dans le menu des filtres.
Pour finir le script, il reste un appel à la fonction "main()":
main()
Le tout doit être enregistré dans un fichier texte ayant l'extension ".py", dont le bit "exécutable" doit être positionné, et placé dans le dossier des filtres "Gimp".
Effet produit.
Lorsqu'on met au point un filtre "Gimp", il est vivement conseillé de lancer le "Gimp" dans une console, celle-ci affichant les (inévitables) erreurs de mise au point, ce qui aide à voir ce qui ne va pas (déboguer...). Une fois le Gimp lancé, et une image créée en 400 fois 400 pixels, on devrait retrouver le script dans le menu "Rendus" du "Gimp", et une fois celui-ci lancé, au bout de quelques secondes, on devrait voir l'image suivante:
=Utilisation du hasard pour créer une fractale=
Un autre exemple: Le triangle de Sierpinski, construit itérativement comme un IFS. Le principe est assez simple mais non déterministe:
Alors, pour tout choix initial de M, le nuage de points ainsi construits se rapproche du triangle de Sierpinski. Pour mieux montrer l'effet du hasard, on donne à M une couleur rouge, verte ou bleue selon le résultat du dé.
Pour avoir un nombre pseudoaléatoire égal à 1, 2 ou 3, on écrit en "Python" de=ceil(3*random()) mais cela nécessite qu'on charge préalablement le module "random" par from random import *
Pour raccourcir encore le code, on peut définir une fonction "Python" pour calculer les coordonnées du milieu d'un segment. Voici le filtre complet:
import math
from math import *
from random import *
from gimpfu import *
def milieu(m,n):
 return ((m[0]+n[0])/2,(m[1]+n[1])/2)
def python_sierpinski(img) :
 largeur=img.width
 hauteur=img.height
 calque=img.layers[0]
 A=(largeur/2,0)
 B=(0,hauteur)
 C=(largeur,hauteur)
 M=(largeur/2,hauteur/2)
 for i in range(100000):
 de=ceil(3*random())
 if de==1:
 M=milieu(A,M)
 couleur=(255,0,0)
 elif de==2:
 M=milieu(B,M)
 couleur=(0,255,0)
 else:
 M=milieu(C,M)
 couleur=(0,0,255)
 x=M[0]
 y=M[1]
 calque.set_pixel(x,y,couleur)
register(
 "sierpinski",
 "ifs en couleurs",
 "dessin du triangle",
 "Auteur du script",
 "Licence GPL",
 "2010",
 "Sierpinski",
 [
 (PF_IMAGE,"img","image vide",None)
 [],
 python_sierpinski,
 menu="<Image>/Filters/Render")
main()
En appliquant ce filtre à une image vide de 400 pixels par 400, on obtient la figure suivante:
Cette image est à comparer avec la version JavaScript créée avec ImageJ dans le chapitre précédent.
=Triangle chromatique=
Pour ce dernier exemple, on va dessiner point par point un triangle, les quantités de rouge, vert et bleu étant les coordonnées barycentriques du pixel dans le triangle. Les sommets du triangle sont A(0,hauteur) qui est tout en bas à gauche (en effet l'axe des ordonnées est dirigé vers le bas), B(largeur,hauteur) qui est en bas à droite et C=(largeur/2,0) qui est donc en haut au milieu. La première boucle est celle sur les ordonnées, qui réalise donc un balayage ligne par ligne (comme dans un écran télé) de haut en bas. Dans cette boucle, on calcule la demi-largeur qui est formula_1. Mais comme "y" est un entier, on veut que "Python" le considère comme réel pour que la division des réels lui soit appliquée. On le convertit donc en réel en lui additionnant "0.0". De même, la division par 2 est celle par 2.0 pour indiquer que c'est bien par un réel qu'on divise. Mais on va boucler de formula_2 à formula_3, ce qui nécessite donc que "demilargeur" soit un entier! Donc on l'arrondit, ce qui donne
demilargeur=int((y+0.0)/hauteur*largeur/2.)
Pour la quantité de bleu, c'est facile, elle est proportionnelle à "1-y" (en allant de 0 à 255). Donc les quantités de rouge et de vert s'additionnent à une quantité proportionnelle à "y". Cette variable est multipliée par une autre variable appelée "rv" (pour "rouge-vert") pour avoir la quantité de vert, et par "1-rv" pour avoir la quantité de rouge. Ceci illustre l'associativité des barycentres. Donc formula_4. Mais pour convertir "x" en réel, on ajoute 0.0 au numérateur,et pour éviter le risque de diviser par 0, on ajoute un nombre petit mais positif au dénominateur:
rv=(x-largeur/2+demilargeur+0.0)/2/(demilargeur+0.000001)
Finalement le script complet donne ceci:
import math
from math import *
from gimpfu import *
def python_couleurs(img) :
 largeur=img.width
 hauteur=img.height
 calque=img.layers[0]
 A=(0,hauteur)
 B=(largeur,hauteur)
 C=(largeur/2,0)
 for y in range(hauteur):
 demilargeur=int((y+0.0)/hauteur*largeur/2.)
 for x in range(largeur/2-demilargeur,largeur/2+demilargeur+1):
 rv=(x-largeur/2+demilargeur+0.0)/2/(demilargeur+0.000001)
 rouge=int((y+0.0)/hauteur*255*(1-rv))
 vert=int((y+0.0)/hauteur*255*rv)
 bleu=int((1-(y+0.0)/hauteur)*255)
 couleur=(rouge,vert,bleu)
 calque.set_pixel(x,y,couleur)
register(
 "couleurs",
 "triangle chromatique",
 "dessin du triangle",
 "Auteur du script",
 "Licence GPL",
 "2010",
 "Triangle des couleurs",
 [
 (PF_IMAGE,"img","image vide",None)
 [],
 python_couleurs,
 menu="<Image>/Filters/Render")
main()
En appliquant ce filtre à une image vide de 400 pixels par 400, on obtient le triangle des couleurs que voici:
Un peu d'antialiasing ne ferait pas de mal (dans "Filtres>Amélioration>Lissage")...
=Ensembles de Julia et de Mandelbrot=
Utiliser les mêmes techniques pour construire les ensembles de Julia et de Mandelbrot est laissé en exercice. En effet