Archivo por meses: diciembre 2012

Programando con GIMP II. Pintar pixels en la pantalla

La verdad es que no hay mucha información y ejemplos para programar plugins con GIMP. Pero lo cierto es que la librería está bien documentada y se entiende bastante rápido si uno está familiarizado con la programación de otras APIs y con los conceptos de GIMP (capas, brushes,…).

GIMP Library Reference Manual:

A modo de ejemplo vamos a hacer lo que consideramos más básico: pintar pixels individuales sobre la pantalla. Del anterior enlace haremos un repaso a las diferentes posibilidades que nos ofrece la librería y nos fijamos en la siguiente entrada:

gimppixelfetcher — Functions for operating on pixel regions:

y aquí tenemos unas pocas funciones, concretamente la que necesitaremos para pintar pixels es

void gimp_pixel_fetcher_put_pixel (GimpPixelFetcher *pf,
gint x,
gint y,
const guchar *pixel);

el primer argumento es un puntero a un objeto GimpPixelFetcher que hemos inicializado previamente.

\tGimpPixelFetcher *pf;
\tpf = gimp_pixel_fetcher_new (drawable,FALSE);

Se inicializa a partir del drawable, que representa la capa sobre la que queremos pintar. Por tanto este puntero nos da un espacio de memoria que podem asociar a un pixel de una capa.

Los argumentos x, y son evidenmente las coordenadas donde queremos escribir el pixel.

Finalmente el puntero *pixel contiene la información del pixel, concretamente los 3 componentes del color.

Seguidamente mostramos la función principal pintar_pixel() de nuestro plugin, que lo que hace es pintar 5 pixels por pantalla, en las posiciones (20,0),…, (24,0). El código (fitxer gimp_pixel_fetcher_put_pixel.c) lo puedes descargar de la wiki, aunque está un poco sucio. El primer pixel tendrá el mismo color que el foreground que tengo seleccionado en ese momento; para el segundo pixel establezco un color con la función gimp_rgb_set(); el tercer pixel será igual que el pixel de la posición (0,0), utilizo la función gimp_pixel_fetcher_get_pixel(); para los cuarto y quinto pixel pongo directamente las coordenadas RGB del color.

Para compilar:

$ gimptool-2.0 –install gimp_pixel_fetcher_put_pixel.c

y el código:

static void pintar_pixel (GimpDrawable *drawable)
{
\tGimpPixelFetcher *pf;
\tgint x1, y1;
\tguchar *px; //pixel is an array of bpp bytes.
\tGimpRGB color;

\tx1=0;
\ty1=0;

\tpf = gimp_pixel_fetcher_new (drawable,FALSE);
\tpx = g_new (guchar, 1);

\t//1. escribo un pixel con el color del foreground
\tgimp_context_get_foreground (&color);
\t//g_message («%d,%d,%d»,(int)(&color)->r,(int)(&color)->g,(int)(&color)->b);
\tpx[0] = 255*(&color)->r; //rojo (0-255)
\tpx[1] = 255*(&color)->g; //verde (0-255)
\tpx[2] = 255*(&color)->b; //azul (0-255)
\tgimp_pixel_fetcher_put_pixel (pf, x1+20, y1, px);

\t//2. escribo un pixel y digo qué color quiero con la función gimp_rgb_set
\tgimp_rgb_set (&color, 0.0, 1.0, 1.0);
\tpx[0] = 255*(&color)->r; //rojo (0-255)
\tpx[1] = 255*(&color)->g; //verde (0-255)
\tpx[2] = 255*(&color)->b; //azul (0-255)
\tgimp_pixel_fetcher_put_pixel (pf, x1+21, y1, px);

\t//3. escribo un pixel igual que el de la posición (0,0)
\tgimp_pixel_fetcher_get_pixel (pf,x1, y1, px);
\t//g_message («%d,%d,%d»,(int)px[0],(int)px[1],(int)px[2]); //puedo obtener información del pixel (componentes RGB)
\tgimp_pixel_fetcher_put_pixel (pf, x1+22, y1, px);

\t//4. escribo un pixel y digo qué color quiero
\tpx[0] = 255; //rojo (0-255)
\tpx[1] = 0; //verde (0-255)
\tpx[2] = 0; //azul (0-255)
\tgimp_pixel_fetcher_put_pixel (pf, x1+23, y1, px);
\t// o bé
\t*px=0; //rojo (0-255)
\t*(px+1)=0; //verde (0-255)
\t*(px+2)=255; //azul (0-255)
\tgimp_pixel_fetcher_put_pixel (pf, x1+24, y1, px);

\tg_free (px);

\tgimp_pixel_fetcher_destroy (pf);

\tgimp_drawable_flush (drawable);
\tgimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
\tgimp_drawable_update (drawable->drawable_id,20,0,5,1);

}

Programando con GIMP I. Ejecutar plugins desde la consola

Con este artículo quiero empezar una serie de posts sobre la programación con GIMP. No es un tutorial para aprender a programar GIMP, tan sólo es poner en orden unas cuantas ideas enfocadas a un futuro proyecto, que básicamente es desarrollar un framework para poder explicar historias mientras dibujas sobre la pantalla con una wacom, y donce se suceden múltiples efectos visuales y sonoros. Si esta serie de posts se acaba, en el último podremos ver cómo se toca una melodía donde el pentagrama está dibujado sobre el GIMP y las notes las dibujo con el ratón o la wacom.
Ante todo necesitamos las librerías de desarrollo del GIMP:

$ sudo apt-get install libgimp2.0-dev

y aprendemos a programar un plugin a partir de un tutorial que si buscas por Google seguro que encuentras:

Con este tutorial, que implementa un blur (difuminador) aprendemos los conceptos básicos de la programación con GIMP. Nuestros plugins los programaremos en lenguage C. Para compilar el plugin haremos:

$ gimptool-2.0 –install myblur.c

Para ejecutar el plugin lo haremos des de dentro del GIMP con Filtros > Difumina > My Blur. O también lo podemos hacer con un script Script-Fu: Filtros > Script-Fu > Consola

(plug-in-myblur run-mode image drawable)

donde sustituimos run-mode, image i drawable por los valores correctos. Por ejemplo:

(plug-in-myblur RUN-NONINTERACTIVE 1 2)

Pero a mi lo que me interesa es ejecutar plugins desde fuera del GIMP, desde la consola. La primera manera de hacerlo es con el lenguatge de script propio del GIMP, el lenguaje Scheme.

example_script.scm:

(
define (example-script inputFilename outputFileName)
(
let* (
(image (car (gimp-file-load RUN-NONINTERACTIVE inputFilename inputFilename)))
(drawable (car (gimp-image-get-active-layer image)))
)
(plug-in-myblur RUN-NONINTERACTIVE image drawable)
(gimp-file-save RUN-NONINTERACTIVE image drawable outputFileName outputFileName)
)
)

Los scripts los he de guardar en la carpeta de scripts del GIMP: ~/.gimp-2.6/scripts. Para ejecutarlo puedo invocar al GIMP en modo comando (opción -b):

$ gimp -i -b «(example-script \\»confirmacion.jpg\\» \\»confirmacion_out.jpg\\»)» -b «(gimp-quit 0)»
batch command executed successfully

Pero todavía no me convence esta manera de hacer. Yo lo que quiero es poder aplicar un plugin a una imagen abierta del GIMP, ejecutando el plugin desde la consola, no desde dentro del GIMP. I la clave está en saber que el GIMP tiene un servidor, el servidor Script-Fu, que trabaja por defecte por el puerto 10008 i que escucha las peticiones TCP que le llegan de la red (socket). Primero de todo hemos de arrancar el servidor:

Filtres > Script-Fu > Inicia el servidor

y efectivamente puedo conectarme al servidor:

$ telnet localhost 10008

pero esto no sirve de nada si no sé el protocolo para comunicarme con este servidor. Este protocolo está explicado en este enlace:

no es un protocolo difícil de entender o implementar. Por suerte, en Google encontramos el script servertest.py que implementa este protocolo. Por ejemplo lo podemos encontrar en uno de estos enlaces:

Ahora ya puedo ejecutar mi plugin desde la consola:

$ python servertest.py
Trying ::1.
Trying 127.0.0.1.
Script-Fu-Remote – Testclient
> (plug-in-myblur RUN-NONINTERACTIVE 1 2)
(OK): Success
>

servertest.py trabaja de forma interactiva. No me convence. Hago una modificación de manera que pueda trabajar de forma totalment desatendida: script servertest_v2.py (http://wiki.joanillo.org/index.php/Programaci%C3%B3_GIMP#Servidor_Script-Fu)

$ python servertest_v2.py localhost 10008 «(plug-in-myblur RUN-NONINTERACTIVE 1 2)»
HOST: localhost
PORT: 10008
COMMAND: (plug-in-myblur RUN-NONINTERACTIVE 1 2)
Trying ::1.
Trying 127.0.0.1.
(plug-in-myblur RUN-NONINTERACTIVE 1 2)
(OK): Success

Es decir, ejecuto el anterior comando desde la consola, y de forma mágica la imagen que tengo abierta en el GIMP queda difuminada.

Ahora sólo falta ejecutar esta comando no desde la consola, sino desde un ejecutable de C, que es mi lenguaje de referencia para desarrollar futuros proyectos:

// gcc -o execute_blur execute_blur.c
int main(int argc, char *argv[])
{
\tsystem(«python servertest_v2.py localhost 10008 \\»(plug-in-myblur RUN-NONINTERACTIVE 1 2)\\»»);
}

$ ./execute_blur

HOST: localhost
PORT: 10008
COMMAND: (plug-in-myblur RUN-NONINTERACTIVE 1 2)
Trying ::1.
Trying 127.0.0.1.
(plug-in-myblur RUN-NONINTERACTIVE 1 2)
(OK): Success

y la imagen que tengo abierta en el GIMP queda difuminada.