Installation
Serveur de fontes
Utilisation
Squelette d'un fichier
Débuggage
Le nom des fonctions
Coloriage et dégradés
Sélections
Exemples de fonds
Fontes
Arguments
Arguments en ligne de commande
Écrire un fichier sur le disque
Lire un fichier
Texte en provenance de LaTeX
Masques
Transformation du blanc en transparent
Fontes : divers effets
Installer un Plug-in
Animations
Recoller deux images
PDL
Installer une version récente de Perl (sans aucune option de développement, comme les Threads), les modules Gtk, PDL, une version récente de Gimp (ici, 1.1.26), et le module Gimp si nécessaire.
Récupérer des fontes PostScript ou True Type
Dans chaque répertoire contenant des fontes PostScript, taper
type1inst mkfontdir
Dans chaque répertoire contenant des fontes True Type, taper
ttmkfdir > fonts.scale mkfontdir
Si l'on est sur un terminal X, lancer un serveur de fontes (in faut une version récente de xfs, qui reconnaisse les fontes TTF)
xfs -config xfs_config -port 2365 & xset +fp tcp/`hostname`:2365 xset fp rehash
où le fichier xfs_config contient des choses comme :
client-limit = 10 clone-self = on catalogue = /share/nfs/users1/umr-tge/zoonek/spool/GIMP_FONTS/freefont, /share/nfs/users1/umr-tge/zoonek/spool/GIMP_FONTS/sharefont, /share/nfs/users1/umr-tge/zoonek/spool/GIMP_FONTS/TTF default-point-size = 120 default-resolutions = 100,100,75,75 use-syslog = off
Si nécessaire (sur un TX), lancer le serveur de fontes.
Lancer Gimp
unset LANG LC_TYPE gimp &
Lancer le serveur Perl
Xtns-->Perl-->Server
Lancer un script en Perl
perl 1.pl
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; # Commandes de débuggage : tous les appels de fonctions # de la PDB (Oricedural Data Base) seront affichés, # avec leurs arguments et leur sugnification. #Gimp::set_trace(TRACE_NAME); Gimp::set_trace(TRACE_ALL); register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [], sub { # Créer une nouvelle image my $image = new Image(256, 256, RGB); # Faire attention à la fonction Undo Gimp->gimp_undo_push_group_start($image); # Créer un calque dans l'image (il en faut au moins un) # et ne pas oublier de l'attacher à l'image. # Il est généralement judicieux de colorier le calque, # sinon, il peut contenir n'importe quoi. my $background = $image->layer_new($image->width, $image->height, RGB_IMAGE, "Background", 100, NORMAL_MODE); $image->add_layer($background, 0); $background->drawable_fill(BG_IMAGE_FILL); # On peut créer un autre calque. # Celui-ci contient un « channel alpha » et sera transparent. my $layer = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "first layer", 100, NORMAL_MODE); $image->add_layer($layer, 0); $layer->fill(TRANS_IMAGE_FILL); # On fait ce que l'on a à faire avec l'image ... # On réactive la commande Undo Gimp->gimp_undo_push_group_end($image); # On renvoie l'image nouvellement créée (qui va s'afficher) return $image; }; # Ne pas oublier cette dernière ligne !!! # (Si le script s'exécute sans donner d'erreur mais sans qu'aucune # image ne s'affiche, vous l'avez oubliée.) exit main;
Voici à quoi ressemblent les instructions de débuggage
gimp_image_new( INT32 width=256 "The width of the image" INT32 height=256 "The height of the image" INT32 type=0 "The type of image: { RGB (0), GRAY (1), INDEXED (2) }" ) = ( IMAGE image=8 "The ID of the newly created image" ) gimp_undo_push_group_start( IMAGE image=8 "The ID of the image in which to pop an undo group" ) = ( ) gimp_palette_get_foreground( ) = ( COLOR foreground=[255,255,0] "The foreground color" ) gimp_palette_get_background( ) = ( COLOR background=[255,0,0] "The background color" ) gimp_palette_set_foreground( COLOR foreground=[255,255,0] "The foreground color" ) = ( ) gimp_palette_set_background( COLOR background=[255,0,0] "The background color" ) = ( ) gimp_image_width( IMAGE image=8 "The image" ) = ( INT32 width=256 "The image's width" ) gimp_image_height( IMAGE image=8 "The image" ) = ( INT32 height=256 "The image's height" ) gimp_layer_new( IMAGE image=8 "The image to which to add the layer" INT32 width=256 "The layer width: (0 < width)" INT32 height=256 "The layer height: (0 < height)" INT32 type=0 "The layer type: { RGB_IMAGE (0), RGBA_IMAGE (1), GRAY_IMAGE (2), GRAYA_IMAGE (3), INDEXED_IMAGE (4), INDEXEDA_IMAGE (5) }" STRING name="Background" "The layer name" FLOAT opacity=100.000000 "The layer opacity: (0 <= opacity <= 100)" INT32 mode=0 "The layer combination mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE (15) }" ) = ( LAYER layer=25 "The newly created layer" ) gimp_image_add_layer( IMAGE image=8 "The image" LAYER layer=25 "The layer" INT32 position=0 "The layer position" ) = ( ) gimp_drawable_fill( DRAWABLE drawable=25 "The drawable" INT32 fill_type=1 "The type of fill: FG_IMAGE_FILL (0), BG_IMAGE_FILL (1), WHITE_IMAGE_FILL (2), TRANS_IMAGE_FILL (3), NO_IMAGE_FILL (4)" ) = ( ) gimp_blend( DRAWABLE drawable=25 "The affected drawable" INT32 blend_mode=0 "The type of blend: { FG_BG_RGB (0), FG_BG_HSV (1), FG_TRANS (2), CUSTOM (3) }" INT32 paint_mode=0 "The paint application mode: { NORMAL_MODE (0), DISSOLVE_MODE (1), BEHIND_MODE (2), MULTIPLY_MODE (3), SCREEN_MODE (4), OVERLAY_MODE (5), DIFFERENCE_MODE (6), ADDITION_MODE (7), SUBTRACT_MODE (8), DARKEN_ONLY_MODE (9), LIGHTEN_ONLY_MODE (10), HUE_MODE (11), SATURATION_MODE (12), COLOR_MODE (13), VALUE_MODE (14), DIVIDE_MODE (15) }" INT32 gradient_type=0 "The type of gradient: { LINEAR (0), BILINEAR (1), RADIAL (2), SQUARE (3), CONICAL_SYMMETRIC (4), CONICAL_ASYMMETRIC (5), SHAPEBURST_ANGULAR (6), SHAPEBURST_SPHERICAL (7), SHAPEBURST_DIMPLED (8), SPIRAL_CLOCKWISE (9), SPIRAL_ANTICLOCKWISE (10) }" FLOAT opacity=100.000000 "The opacity of the final blend (0 <= opacity <= 100)" FLOAT offset=0.000000 "Offset relates to the starting and ending coordinates specified for the blend. This parameter is mode dependent (0 <= offset)" INT32 repeat=0 "Repeat mode: { REPEAT_NONE (0), REPEAT_SAWTOOTH (1), REPEAT_TRIANGULAR (2) }" INT32 supersample=0 "Do adaptive supersampling (TRUE or FALSE)" INT32 max_depth=0 "Maximum recursion levels for supersampling" FLOAT threshold=0.000000 "Supersampling threshold" FLOAT x1=0.000000 "The x coordinate of this blend's starting point" FLOAT y1=0.000000 "The y coordinate of this blend's starting point" FLOAT x2=255.000000 "The x coordinate of this blend's ending point" FLOAT y2=255.000000 "The y coordinate of this blend's ending point" ) = ( ) gimp_undo_push_group_end( IMAGE image=8 "The ID of the image in which to pop an undo group" ) = ( )
Pour avoir le nom d'une fonction, on cherche dans la PDB.
Xtns-->DB Browser
Une fois qu'on a le nom de la fonction, on peut l'appeler de différentes manières en Perl. Prenons l'exemple de la fonction
gimp_blend(drawable, blend_mode, paint_mode, gradient_type, opacity, offset, repeat, supersample, max_depth, threshold, x1, y1, x2, y2)
On peut l'appeler des manières suivantes.
Gimp->gimp_blend($drawable, $blend_mode, ...); $drawable->blend($blend_mode, ...);
Beaucoup de fonctions agissent sur un drawable mais demandent en argument à la fois une image et un drawable, sans pour autant utiliser l'image : on peut l'omettre.
Certaines fonctions (en particulier les plug-ins) attendent aussi un premier argument, spécifiant si la fonction est appelée interactivement ou non : il ne faut pas le mettre. C'est par exemple le cas de la fonction
plug_in_plasma( run_mode, image, drawable, seed, turbulence);
On peut l'invoquer des manières suivantes.
Gimp-->plug_in_plasma($image, $drawable, $seed, $turbulence); Gimp-->plug_in_plasma($drawable, $seed, $turbulence); $drawable->plug_in_plasma($seed, $turbulence);
Les différentes commandes fill permettent de colorier l'image (ou la partie sélectionnée d'une image) à l'aide d'une couleur ou d'un motif.
gimp_bucket_fill gimp_drawable_fill gimp_edit_fill
La commande blend permet de colorier avec un dégradé (linéaire, circulaire, en dents de scie, etc.)
gimp_blend
Voici un exemple complet.
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; # Commandes de débuggage : tous les appels de fonctions # de la PDB (Oricedural Data Base) seront affichés, # avec leurs arguments et leur sugnification. #Gimp::set_trace(TRACE_NAME); Gimp::set_trace(TRACE_ALL); register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [], sub { # Créer une nouvelle image my $image = new Image(256, 256, RGB); # Faire attention à la fonction Undo Gimp->gimp_undo_push_group_start($image); # On sauvegarde les couleur du tracé et de fond, # car on va les modifier. my $fg = Palette->get_foreground(); my $bg = Palette->get_background(); Palette->set_foreground("yellow"); Palette->set_background([255,0,0]); # Créer un calque dans l'image (il en faut au moins un) # et ne pas oublier de l'attacher à l'image. # Il est généralement judicieux de colorier le calque, # sinon, il peut contenir n'importe quoi. my $background = $image->layer_new($image->width, $image->height, RGB_IMAGE, "Background", 100, NORMAL_MODE); $image->add_layer($background, 0); $background->drawable_fill(BG_IMAGE_FILL); # On fait ce que l'on a à faire avec l'image $background->blend(FG_BG_RGB, NORMAL_MODE, LINEAR, 100, 0, REPEAT_NONE, 0, 0, 0, 0, 0, 255, 255); # On réactive la commande Undo Gimp->gimp_undo_push_group_end($image); # On restaure les couleurs Palette->set_foreground($fg); Palette->set_background($bg); # On renvoie l'image nouvellement créée (qui va s'afficher) return $image; }; exit main;
On peut sélectionner une partie rectangulaire de l'image, une partie circulaire (avec anti-aliasing), avec éventuellement un « dégradé de transparence » le long du bors de la sélection (feather).
gimp_rect_select gimp_ellipse_select
Il est aussi possible de sélectionner une zône quelconque, délimitée par une famille de points, ou de sélectionner une zône de manière « intelligente » (fuzzy) en fonction des couleurs.
gimp_free_select gimp_fuzzy_select
Voici deux exemples de sélections imbriquées les unes dans les autres.
my $max = 10; for(my $i=0; $i<$max; $i++){ $image->rect_select( $image->width/$max/2*$i, $image->height/$max/2*$i, ($max-$i)/$max*$image->width, ($max-$i)/$max*$image->height, REPLACE, 0, 0); $background->blend(FG_BG_RGB, NORMAL_MODE, LINEAR, 100, 0, REPEAT_NONE, 0, 0, 0, ($image->selection_bounds)[1..4]); my ($a, $b) = (Palette->get_foreground, Palette->get_background); Palette->set_background($a); Palette->set_foreground($b); } $image->selection_clear;
$image->ellipse_select( $image->width/$max/2*$i, $image->height/$max/2*$i, ($max-$i)/$max*$image->width, ($max-$i)/$max*$image->height, REPLACE, 1, # Antialiasing 0, 0);
Créer des « nuages » (plasma) et éclaircir l'image (levels).
$background->plug_in_plasma(1236, 2); $background->levels(VALUE_LUT, 0, 255, # In 1, # Gamma correction 150, 255); # Out
Dessiner des nuages (plasma) et les rendre un peu flous (gauss_iir). Dans un autre calque, créer d'autres nuages (plasma), les faire passer en noir et blanc (desaturate) (peut-être pas nécessaire), et utiliser ce calque pour cabosser le premier (bump_map). Le second calque n'étant plus nécessaire, on peut l'effacer (remove_layer).
$background->plug_in_plasma(1236, 2); $background->plug_in_gauss_iir(50,1,1); my $bump = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "bumps", 100, NORMAL_MODE); $image->add_layer($bump,0); $bump->fill(TRANS_IMAGE_FILL); $bump->plug_in_plasma(1234,2); $bump->desaturate(); $background->plug_in_bump_map($bump, 135, 45, 10, # Profondeur, 0, 0, 0, 0, 1, # Compensate for darkening 0, LINEAR); $bump->remove_layer();
Il convient tout d'abord d'avoir le nom de la fonte que l'on va utiliser, par exemple à l'aide d'une des deux commandes suivantes.
xlsfonts | less xfontsel
On peut ajouter du texte (text_fontname) à un calque déjà existant, mais on n'obtient qu'une sélection flottante, qu'il faut ensuite accrocher (anchor) à ce calque.
# Création d'un nouveau calque (au dessus du fond), pour le texte. # Celui-ci contient un « channel alpha » et sera transparent. my $layer = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "first layer", 100, NORMAL_MODE); $image->add_layer($layer, 0); $layer->fill(TRANS_IMAGE_FILL); # Ajout du texte my $fontname = "-paradise-arnoldboecklin-extrabold-r-normal--0-0-0-0-p-0-iso8859-1"; $layer->text_fontname(20, 20, "ABC", 0, # border 1, # antialiasing 100, PIXELS, $fontname) -> anchor; Gimp->gimp_undo_push_group_end($image); Palette->set_foreground($fg); Palette->set_background($bg); return $image; };
En fait, il n'est pas nécessaire de créer un calque, Gimp peut s'en charger tout seul, si on précise « -1 » comme numéro de calque (mais comme cela me pose d'autres problèmes, j'éviterai cette solution).
my $layer = $image->text_fontname(-1, 20, 20, "ABC", 0, 1, 100, PIXELS, $fontname); $layer->set_name("Text layer");
Il est possible de récupérer la taille du texte avant de le tracer, par exemple pour le centrer.
my($w,$h) = Gimp->gimp_text_get_extents_fontname("ABC",100,PIXELS,$fontname); $layer->text_fontname(($image->width-$w)/2, ($image->height-$h)/2, "ABC", 0, 1, 100, PIXELS, $fontname);
Voici un exemple un peu moins trivial : on a rajouté une ombre.
my $shadow = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "first layer", 100, NORMAL_MODE); $image->add_layer($shadow, 0); $shadow->fill(TRANS_IMAGE_FILL); my($w,$h) = Gimp->gimp_text_get_extents_fontname("ABC",100,PIXELS,$fontname); $shadow->text_fontname(($image->width-$w)/2, ($image->height-$h)/2, "ABC", 0, # border 1, # antialiasing 100, PIXELS, $fontname) -> anchor; $shadow->set_name("Shadow"); $image->selection_clear; my $text = $shadow->copy(1); $image->add_layer($text,-1); $text->set_name("Text"); $shadow->plug_in_gauss_iir(10,1,1); $shadow->set_offsets(10,10); # On colorie le texte en rouge. $text->set_preserve_trans(1); $image->selection_all(); Palette->set_foreground("red"); $text->bucket_fill(FG_IMAGE_FILL,NORMAL_MODE,100,0,0,0,0);
Ces scripts peuvent accepter divers arguments, qui pourront être demandés à l'utilisateur de manière interactive.
register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [[PF_RADIO, "choose", "Choose one of these", 0, [A=>1, B=>2, C=>3]], [PF_VALUE, "number", "Give me a number", 50], [PF_SLIDER, "number", "Yet another number", 0, [-100,100,1]], [PF_INT8, "number", "again...", 0], [PF_COLOR, "color", "Choose a color", [255,0,0]], [PF_TOGGLE, "twice", "Do it twice?" , 0], [PF_FONT, "font", "What font type to use - size will be ignored", $fontname], [PF_STRING, "string", "Text string to typeset", "ABCabc"], [PF_DRAWABLE, "source", "What drawable shall we use?"], [PF_INT32, "angle", "Angle, 0 is left", 120], ], sub { print "Les arguments étaient les suivants\n"; my $i=0; while( scalar @_ ){ $i++; $_=shift @_; print "$i: $_\n"; } }; exit main;
Reprenons le même programme, avec comme arguments, le texte à imprimer et comme arguments facultatifs la couleur et la fonte.
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; Gimp::set_trace(TRACE_ALL); my $fontname = "-paradise-arnoldboecklin-extrabold-r-normal--0-0-0-0-p-0-iso8859-1"; register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [ [PF_STRING, "texte", "texte à écrire", "ABC"], [PF_COLOR, "couleur", "couleur du texte", [255,0,0]], [PF_FONT, "fonte", "fonte de caractères à utiliser", $fontname], [PF_SLIDER, "taille", "taille du texte", 100, [10,300,1]], ], sub { my ($t, $col, $f, $size) = @_; my $image = new Image(256, 256, RGB); Gimp->gimp_undo_push_group_start($image); my $fg = Palette->get_foreground(); my $bg = Palette->get_background(); Palette->set_foreground("black"); Palette->set_background("white"); my $background = $image->layer_new($image->width, $image->height, RGB_IMAGE, "Background", 100, NORMAL_MODE); $image->add_layer($background, 0); $background->drawable_fill(BG_IMAGE_FILL); # Colorier le fond $background->plug_in_plasma(1236, 2); $background->plug_in_gauss_iir(50,1,1); my $bump = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "bumps", 100, NORMAL_MODE); $image->add_layer($bump,0); $bump->fill(TRANS_IMAGE_FILL); $bump->plug_in_plasma(1234,2); $bump->desaturate(); $background->plug_in_bump_map($bump, 135, 45, 10, # Profondeur, 0, 0, 0, 0, 1, # Compensate for darkening 0, LINEAR); $bump->remove_layer(); $background->levels(VALUE_LUT, 0, 255, # In 1, # Gamma correction 150, 255); # Out my $shadow = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "first layer", 100, NORMAL_MODE); $image->add_layer($shadow, 0); $shadow->fill(TRANS_IMAGE_FILL); my($w,$h) = Gimp->gimp_text_get_extents_fontname($t,$size,PIXELS,$f); $shadow->text_fontname(($image->width-$w)/2, ($image->height-$h)/2, "ABC", 0, # border 1, # antialiasing 100, PIXELS, $fontname) -> anchor; $shadow->set_name("Shadow"); $image->selection_clear; my $text = $shadow->copy(1); $image->add_layer($text,-1); $text->set_name("Text"); $shadow->plug_in_gauss_iir(10,1,1); $shadow->set_offsets(10,10); # On colorie le texte en rouge. $text->set_preserve_trans(1); $image->selection_all(); Palette->set_foreground($col); $text->bucket_fill(FG_IMAGE_FILL,NORMAL_MODE,100,0,0,0,0); # On réactive la commande Undo Gimp->gimp_undo_push_group_end($image); # On restaure les couleurs Palette->set_foreground($fg); Palette->set_background($bg); # On renvoie l'image nouvellement créée (qui va s'afficher) return $image; }; exit main;
Il est possible de donner ces arguments en ligne de commande.
perl 13.pl XYZ
Mais alors, l'image créée n'est plus affichée : c'est au script de prendre garde à la sauvegarder sur le disque.
Il est possible de sauvegarder les images au format XCF (propre à Gimp, permet de garder les calques et la transparence) ou en des formats plus courrants (PNG, JPEG), mais il faudra prendre garde à « applatir » l'image (ie, fusionner tous les calques visibles) avant de la sauvegarer, car on ne peut sauvegarder qu'un seul calque.
my $flat = $image->flatten; $flat->file_jpeg_save("toto.jpg", "toto.jpg", .75, 1, 1, 1, "Created with the Gimp", 0,1,0,0);
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; Gimp::set_trace(TRACE_ALL); my $fontname = "-paradise-arnoldboecklin-extrabold-r-normal--0-0-0-0-p-0-iso8859-1"; register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [ [PF_STRING, "fichier", "fichier (JPEG) contenant l'image à modifier", "chateau.jpg"], ], sub { my ($f) = @_; my $image = Gimp->file_jpeg_load($f,$f); my $layer = $image->get_layers; $layer->desaturate; my $courbe = []; for(my $i=0; $i<256; $i++){ push @$courbe, ( $i < 128 ) ? (2*$i) : (255-2*$i); } $layer->curves_explicit(VALUE_LUT, 3, $courbe); $layer->color_balance(SHADOWS,1, 25,-30,-65); Gimp->gimp_undo_push_group_start($image); my $fg = Palette->get_foreground(); my $bg = Palette->get_background(); Palette->set_foreground("black"); Palette->set_background("white"); # On sauvegarde l'image my $flat = $image->flatten; $flat->file_jpeg_save("toto.jpg", "toto.jpg", .75, 1, 1, 1, "Created with the Gimp", 0,1,0,0); # On réactive la commande Undo Gimp->gimp_undo_push_group_end($image); # On restaure les couleurs Palette->set_foreground($fg); Palette->set_background($bg); # On renvoie l'image nouvellement créée (qui va s'afficher) return $image; }; exit main;
Si on veut mettre du texte un peu plus compliqué, on peut passer par LaTeX et inclure le fichier PostScript.
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; Gimp::set_trace(TRACE_ALL); sub latex { my ($words) = @_; open(LATEX, ">tmp.tex") || die "Cannot open tmp.tex for writing: $!"; print LATEX '\documentclass[12pt]{article}\usepackage[T1]{fontenc}\usepackage[latin1]{inputenc}' ."\n"; print LATEX '\usepackage{amsfonts,amsmath}\usepackage[dvips,all]{xy}' ."\n"; print LATEX '\pagestyle{empty}'; print LATEX '\begin{document}'; print LATEX $words; print LATEX '\end{document}'; close LATEX; system 'latex', '--interaction=batchmode', 'tmp.tex'; system qw/dvips -E -o tmp.eps tmp.dvi/; } register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [ [PF_STRING, "fichier", "fichier (JPEG) contenant l'image à modifier", "chateau.jpg"], ], sub { my ($f) = @_; my $image = Gimp->file_jpeg_load($f,$f); my $layer = $image->get_layers; # On éclaircit l'image de fond (pour pouvoir écrire dessus) $layer->levels(VALUE_LUT, 0, 255, # In 1, # Gamma correction 150, 255); # Out # On calcule le texte que l'on va lui superposer latex('\huge$x^2 + y^2 = 1$'); my $text_image = Gimp->file_ps_load("tmp.eps", "tmp.eps"); my $text_layer = $text_image->get_layers; # On ajoute le texte à l'image $text_layer->edit_copy(); my $text = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "LaTeX", 100, MULTIPLY_MODE); $image->add_layer($text, 0); $text->fill(TRANS_IMAGE_FILL); $text->edit_paste(0)->anchor; return $image; }; exit main;
Mais on n'a pas un très bon contrôle sur la taille de l'image : on peut convertir le fichier PS en fichier PPM soi même, en précisant la résolution.
sub latex { # Création du fichier PostScript my ($words) = @_; my $tmp = "tmp"; open(LATEX, ">$tmp.tex") || die "Cannot open $tmp.tex for writing: $!"; print LATEX '\documentclass[12pt]{article}\usepackage[T1]{fontenc}\usepackage[latin1]{inputenc}' ."\n"; print LATEX '\usepackage{amsfonts,amsmath}\usepackage[dvips,all]{xy}' ."\n"; print LATEX '\pagestyle{empty}'; print LATEX '\begin{document}'; print LATEX $words; print LATEX '\end{document}'; close LATEX; system 'latex', '--interaction=batchmode', "$tmp.tex"; system qw/dvips -E -D 600 -o tmp.eps/, "$tmp.dvi"; # Lecture de la Bounding Box my ($bbx,$bby,$bbw,$bbh); open(PS,"$tmp.eps"); while (<PS>) { if (/^%%BoundingBox:\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)/) { $bbx = 0-$1; $bby = 0-$2; $bbw = $3+$bbx; $bbh = $4+$bby; last if /^%%EndComments/; } } close(PS); # Création du fichier *.ppm my $res = 4; $bbw *= $res; $bbh *= $res; my $r = $res*72; open(GS, "|gs -q -dNOPAUSE -dNO_PAUSE -sDEVICE=ppmraw -g${bbw}x${bbh} -r$r -sOutputFile=$tmp.ppm"); print GS "$bbx $bby translate\n"; print GS "($tmp.eps) run\n"; print GS "showpage\n"; print GS "quit\n"; close(GS); } (...) latex('\huge\bfseries\LaTeX'); my $text_image = Gimp->file_pnm_load("tmp.ppm", "tmp.ppm"); (...)
sub { my ($f) = @_; my $image = Gimp->file_jpeg_load($f,$f); my $layer = $image->get_layers; # On calcule le texte que l'on va lui superposer latex('\huge\bfseries\LaTeX'); my $text_image = Gimp->file_pnm_load("tmp.ppm", "tmp.ppm"); my $text_layer = $text_image->get_layers; # On crée un nouveau calque my $text = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "LaTeX", 100, MULTIPLY_MODE); $image->add_layer($text, 0); $text->fill(TRANS_IMAGE_FILL); # On ajoute le texte à l'image $text_layer->edit_copy(); # Si on ne précise pas d'offsets, l'image est centrée. # On la met en haut à gauche, à 40 pixels du bord my $border = 20; my $a = $text->edit_paste(0); $a->set_offsets(2*$border, $image->height - $text_image->height - 2*$border); $a->anchor; # On sélectionne un rectangle, 20 pixels autour de ce texte, dans l'image de fond $image->rect_select($border, $image->height - $text_image->height - 3*$border, $text_image->width+2*$border, $text_image->height+2*$border, REPLACE, 0, 0); # On éclaircit l'image de fond (pour pouvoir écrire dessus) $layer->levels(VALUE_LUT, 0, 255, # In 1, # Gamma correction 150, 255); # Out my $flat = $image->flatten; $flat->file_jpeg_save("toto.jpg", "toto.jpg", .75, 1, 1, 1, "Created with the Gimp", 0,1,0,0); return $image; };
$image->rect_select($border, $image->height - $text_image->height - 3*$border, $text_image->width+2*$border, $text_image->height+2*$border, REPLACE, 1, $border, # feather );
On peut vouloir utilise le texte LaTeX exactement comme du texte provenant de Gimp : en l'occurrence, avoir du texte noir sur un fond transparent. On peut le faire avec des masques.
# Le fond my $background = $image->layer_new($image->width, $image->height, RGB_IMAGE, "Background", 100, NORMAL_MODE); $image->add_layer($background, 0); $background->drawable_fill(BG_IMAGE_FILL); # Un nouveau calque, transparent my $layer = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "LaTeX", 100, NORMAL_MODE); $image->add_layer($layer, 0); $layer->fill(TRANS_IMAGE_FILL); # Calcul du texte latex('\huge\bfseries\LaTeX'); my $text_image = Gimp->file_pnm_load("tmp.ppm", "tmp.ppm"); my $text_layer = $text_image->get_layers; $text_layer->add_alpha; # On ajoute le texte à l'image $text_layer->edit_copy(); $layer->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); # On crée un masque my $mask = $layer->create_mask(WHITE_MASK); $layer->add_layer_mask($mask); $mask->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); $mask->gimp_invert(); $layer->remove_layer_mask(APPLY);
$layer->add_alpha; my $mask = $layer->create_mask(WHITE_MASK); $layer->add_layer_mask($mask); $layer->edit_copy(); $mask->edit_paste(0)->anchor; $mask->gimp_invert(); $layer->remove_layer_mask(APPLY);
Il est possible d'entrelacer des lettres (avec des masques), mais c'est plus facile à la souris qu'en Perl.
Lettres vieillies
# $layer's background is white $layer->plug_in_spread(5,5); $layer->plug_in_spread(5,5); $layer->plug_in_gauss_iir(5,1,1); $layer->threshold(175,255);
Lettres transparentes
sub { my ($f) = @_; my $image = Gimp->file_jpeg_load($f,$f); my $layer = $image->get_layers; my $fg = Palette->get_foreground(); my $bg = Palette->get_background(); Palette->set_foreground("black"); Palette->set_background("white"); latex('\huge\bfseries\LaTeX'); my $text_image = Gimp->file_pnm_load("tmp.ppm", "tmp.ppm"); my $text_layer = $text_image->get_layers; # On copie le fond (en ajoutant un channel alpha) my $copy = $layer->copy(1); $image->add_layer($copy,-1); # On l'éclaircit $copy->levels(VALUE_LUT, 0, 255, # In 1, # Gamma correction 150, 255); # Out # On lui ajoute un masque my $mask = $copy->create_mask(WHITE_MASK); $copy->add_layer_mask($mask); # On met le texte dans ce masque $text_layer->edit_copy(); $mask->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); $mask->gimp_invert(); # On applique ce masque $layer->remove_layer_mask(APPLY); my $flat = $image->flatten; $flat->file_jpeg_save("toto.jpg", "toto.jpg", .75, 1, 1, 1, "Created with the Gimp", 0,1,0,0); return $image; };
On peut améliorer l'exemple précédent pour qu'il y ait un bord noir autour des lettres.
# On rajoute le bord du texte my $bord = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "contour", 100, MULTIPLY_MODE); $image->add_layer($bord, 0); $bord->fill(BG_IMAGE_FILL); $text_layer->edit_copy(); $bord->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); #$bord->plug_in_sobel(1,1,1); $bord->plug_in_edge(3,1); $bord->gimp_invert();
Reprenons le même exemple, en transformant le blanc du calque du haut (celui contenant le bord des lettres) en transparent.
my $m = $bord->create_mask(WHITE_MASK); $bord->add_layer_mask($m); $bord->edit_copy(); $m->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); $m->gimp_invert(); $bord->remove_layer_mask(APPLY);
Avec des images très en couleurs, on peut mettre les lettres en couleur sur un fond noir et blanc ou le contraire.
On peut aussi inverser le texte.
On peut aussi le solariser de deux manières différentes.
# On solarise les deux calques de manière différente. my $courbe = []; for(my $i=0; $i<256; $i++){ push @$courbe, ( $i < 128 ) ? (2*$i) : (255-2*$i); } $copy->curves_explicit(VALUE_LUT, 3, $courbe); $copy->color_balance(SHADOWS,1, 25,-30,-65); $courbe = []; for(my $i=0; $i<256; $i++){ push @$courbe, ( $i < 128 ) ? (255-2*$i) : (2*$i-256); } $layer->curves_explicit(VALUE_LUT, 3, $courbe); #$layer->color_balance(SHADOWS,1, 25,-30,-65);
On peut récupérer l'une des images précédentes et la cabosser en suivant le texte.
my $flat = $image->flatten; my $bump = $image->layer_new($image->width, $image->height, RGBA_IMAGE, "bumps", 100, NORMAL_MODE); $image->add_layer($bump,0); $bump->fill(BG_IMAGE_FILL); $bump->edit_paste(0); gimp_floating_sel_anchor(gimp_image_floating_selection($image)); $bump->desaturate(); $flat->plug_in_bump_map($bump, 135, 45, 10, # Profondeur, 0, 0, 0, 0, 1, # Compensate for darkening 0, LINEAR); $bump->remove_layer();
Considérons le programme suivant, appelé latex_string.pl, sui transforme du code LaTeX en une sélection flottante.
#! /share/nfs/users1/umr-tge/zoonek/gnu/Linux/bin/perl -w use strict; use Gimp qw(:auto N_); use Gimp::Fu; use Gimp::Util; #Gimp::set_trace(TRACE_ALL); register "latex_string", "Convert LaTeX code into floating selection", "Convert LaTeX code into floating selection", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Image>/Filters/Render/LaTeX String", "", [ [PF_STRING, "text", "LaTeX code to be compiled", "\\LaTeX"], [PF_STRING, "preamble", "Lines to add in the preamble", ""], [PF_INT32, "magnification", "TeX's \\magnification, around 4000 or 8000",4000], ], sub { my ($image, $drawable, $words, $preamble, $mag) = @_; # Création du fichier PostScript my $tmp = "tmp"; open(LATEX, ">$tmp.tex") || die "Cannot open $tmp.tex for writing: $!"; print LATEX '\documentclass[12pt]{article}\usepackage[T1]{fontenc}\usepackage[latin1]{inputenc}' ."\n"; print LATEX '\usepackage{amsfonts,amsmath}\usepackage[dvips,all]{xy}' ."\n"; print LATEX '\pagestyle{empty}'; print LATEX "\n$preamble\n"; print LATEX '\begin{document}'; print LATEX $words; print LATEX '\end{document}'; close LATEX; system 'latex', '--interaction=batchmode', "$tmp.tex"; # -E : EPSF # -D 600 : 600 dpi # -x 1000 : \magnification=1000 system qw/dvips -x/, $mag, qw/-E -D 600 -o tmp.eps/, "$tmp.dvi"; # Lecture de la Bounding Box my ($bbx,$bby,$bbw,$bbh); open(PS,"$tmp.eps"); while (<PS>) { if (/^%%BoundingBox:\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)/) { $bbx = 0-$1; $bby = 0-$2; $bbw = $3+$bbx; $bbh = $4+$bby; last if /^%%EndComments/; } } close(PS); # Création du fichier *.ppm my $res = 1; $bbw *= $res; $bbh *= $res; my $r = $res*72; open(GS, "|gs -q -dNOPAUSE -dNO_PAUSE -sDEVICE=ppmraw -g${bbw}x${bbh} -r$r -sOutputFile=$tmp.ppm"); print GS "$bbx $bby translate\n"; print GS "($tmp.eps) run\n"; print GS "showpage\n"; print GS "quit\n"; close(GS); # Lecture du fichier *.ppm my $text_image = Gimp->file_pnm_load("$tmp.ppm","$tmp.ppm"); my $text_layer = $text_image->get_layers; # On transforme le blanc en transparent $text_layer->add_alpha; my $text_mask = $text_layer->create_mask(WHITE_MASK); $text_layer->add_layer_mask($text_mask); $text_layer->edit_copy(); $text_mask->edit_paste(0)->anchor; $text_mask->gimp_invert(); $text_layer->remove_layer_mask(APPLY); # Copie du texte sur l'image $text_image->get_layers->edit_copy(); $drawable->edit_paste(0); return $image; }; exit main;
On peut l'installer de la manière suivante.
gimptool --install-admin-bin latex_string.pl
Pour une installation personnelle :
gimptool --install-bin latex_string.pl
Pour créer une animation, il suffit de mettre plusieurs calques, chacun avec un nom se terminant par « (1000ms) » (avec les parnthèses) : l'image GIF ainsi créée affichera les calques un par un (en superposant chaque calque aux précédents), à raison d'un toutes les 100 milisecondes.
for(...){ $layer = $layer->copy(1); $layer->set_name("frame $i (1000ms)"); $image->add_layer($layer,0); ... } ... $image->convert_indexed(1, WEB_PALETTE, 256, 1, 1, ""); $layer->file_gif_save('toto.gif', 'toto.gif', 1, 1, 1000, 2);
#! perl -w use strict; use Gimp; use Gimp::Fu; use Gimp::Util; #Gimp::set_trace(TRACE_ALL); sub max ($$) { my ($a, $b) = @_; return $a > $b ? $a : $b; } register "essai", "Premier essai", "Ceci est un premier essai de script en Perl pour Gimp", "Vincent Zoonekynd", "zoonek\@math.jussieu.fr", "0.1", "<Toolbox>/Xtns/Essais/1", "", [ [PF_STRING, "fichier", "fichier (JPEG) contenant l'image de gauche"], [PF_STRING, "fichier", "fichier (JPEG) contenant l'image de droite"], [PF_STRING, "fichier", "fichier (JPEG) qui contiendra le résultat", "resultat .jpg"], ], sub { my ($file_left, $file_right, $resultat) = @_; # Lecture des fichiers my $left = Gimp->file_jpeg_load($file_left, $file_left); my $left_layer = $left->get_layers; my $right = Gimp->file_jpeg_load($file_right, $file_right); my $right_layer = $right->get_layers; # Création d'une nouvelle image my $image = new Image( $left->width + $right->width, max($left->height, $right->height), RGB); my $background = $image->layer_new($image->width, $image->height, RGB_IMAGE, "Background", 100, NORMAL_MODE); $image->add_layer($background, 0); $background->drawable_fill(BG_IMAGE_FILL); # Copie des deux fichiers dans la nouvelle image # (si on ne précise pas d'offset, l'image des centrée) $left_layer->edit_copy(); my $a = $background->edit_paste(0); $a->set_offsets(0, 0); $a->anchor; $right_layer->edit_copy(); my $b = $background->edit_paste(0); $b->set_offsets($left->width, 0); $b->anchor; # Sauvegarde du fichier my $flat = $image->flatten; $flat->file_jpeg_save($resultat, $resultat, .75, 1, 1, 1, "Created with the Gimp", 0,1,0,0); }; # Ne pas oublier cette dernière ligne... exit main;
...
Au prompt du shell, taper perldl puis demo demo pdl demo 3d demo 3d2 demo 3dgal perldoc Gimp::PDL use Gimp; use Gimp::PDL; use PDL; $region = $drawable->get->pixel_rgn (0,0, 100,100, 1,0); $pixel = $region->get_pixel (5,7); # fetches the pixel from (5|7) print $pixel; # outputs something like # [255, 127, 0], i.e. in # RGB format ;) $region->set_pixel ($pixel * 0.5, 5, 7);# darken the pixel $rect = $region->get_rect (3,3,70,20); # get a horizontal stripe $rect = $rect->hclip(255/5)*5; # clip and multiply by 5 $region->set_rect($rect); # and draw it! undef $region; # and update it!
...
Vincent Zoonekynd
<zoonek@math.jussieu.fr>
Octobre 2000
latest modification on ven mar 22 15:43:46 CET 2002