9.6. Imágenes

Las Images (Imágenes) son estructuras de datos que contienen dibujos. Estos dibujos se pueden usar en varios sitios.

Las Images (Imágenes) se pueden crear a partir de Pixbufs, Pixmaps, archivos que contengan información de imagen (por ejemplo. XPM, PNG, JPEG, TIFF, etc.), incluso ficheros de animación.

Las Images (Imágenes) se crean usando la función:

  image = gtk.Image()

Después se carga la imágen usando alguno de los siguientes métodos:

  image.set_from_pixbuf(pixbuf)
  image.set_from_pixmap(pixmap, mask)
  image.set_from_image(image)
  image.set_from_file(filename)
  image.set_from_stock(stock_id, size)
  image.set_from_icon_set(icon_set, size)
  image.set_from_animation(animation)

Donde pixbuf es un GdkPixbuf; pixmap y mask son GdkPixmaps; image es una GdkImage; stock_id es el nombre de un GtkStockItem; icon_set es un GtkIconSet; y, animation es una GdkPixbufAnimation. el argumento size (tamaño) es uno de:

 ICON_SIZE_MENU
 ICON_SIZE_SMALL_TOOLBAR
 ICON_SIZE_LARGE_TOOLBAR
 ICON_SIZE_BUTTON
 ICON_SIZE_DND
 ICON_SIZE_DIALOG

La forma más fácil de crear una imagen es usar el método set_from_file() que automáticamente determina el tipo de imagen y la carga.

El programa images.py muestra cómo cargar varios tipos de imagen (goalie.gif, apple-red.png, chaos.jpg, important.tif, soccerball.gif) en imagenes que se colocan dentro de botones:

Figura 9.5. Ejemplo de Imágenes en Botones

Ejemplo de Imágenes en Botones

El código fuente es:

    1	#!/usr/bin/env python
    2	
    3	# example images.py
    4	
    5	import gtk
    6	
    7	class ImagesExample:
    8	    # when invoked (via signal delete_event), terminates the application.
    9	    def close_application(self, widget, event, data=None):
   10	        gtk.mainquit()
   11	        return gtk.FALSE
   12	
   13	    # is invoked when the button is clicked.  It just prints a message.
   14	    def button_clicked(self, widget, data=None):
   15	        print "button %s clicked" % data
   16	
   17	    def __init__(self):
   18	        # create the main window, and attach delete_event signal to terminating
   19	        # the application
   20	        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   21	        window.connect("delete_event", self.close_application)
   22	        window.set_border_width(10)
   23	        window.show()
   24	
   25	        # a horizontal box to hold the buttons
   26	        hbox = gtk.HBox()
   27	        hbox.show()
   28	        window.add(hbox)
   29	
   30	        pixbufanim = gtk.gdk.PixbufAnimation("goalie.gif")
   31	        image = gtk.Image()
   32	        image.set_from_animation(pixbufanim)
   33	        image.show()
   34	        # a button to contain the image widget
   35	        button = gtk.Button()
   36	        button.add(image)
   37	        button.show()
   38	        hbox.pack_start(button)
   39	        button.connect("clicked", self.button_clicked, "1")
   40	        
   41	        # create several images with data from files and load images into
   42	        # buttons
   43	        image = gtk.Image()
   44	        image.set_from_file("apple-red.png")
   45	        image.show()
   46	        # a button to contain the image widget
   47	        button = gtk.Button()
   48	        button.add(image)
   49	        button.show()
   50	        hbox.pack_start(button)
   51	        button.connect("clicked", self.button_clicked, "2")
   52	
   53	        image = gtk.Image()
   54	        image.set_from_file("chaos.jpg")
   55	        image.show()
   56	        # a button to contain the image widget
   57	        button = gtk.Button()
   58	        button.add(image)
   59	        button.show()
   60	        hbox.pack_start(button)
   61	        button.connect("clicked", self.button_clicked, "3")
   62	
   63	        image = gtk.Image()
   64	        image.set_from_file("important.tif")
   65	        image.show()
   66	        # a button to contain the image widget
   67	        button = gtk.Button()
   68	        button.add(image)
   69	        button.show()
   70	        hbox.pack_start(button)
   71	        button.connect("clicked", self.button_clicked, "4")
   72	
   73	        image = gtk.Image()
   74	        image.set_from_file("soccerball.gif")
   75	        image.show()
   76	        # a button to contain the image widget
   77	        button = gtk.Button()
   78	        button.add(image)
   79	        button.show()
   80	        hbox.pack_start(button)
   81	        button.connect("clicked", self.button_clicked, "5")
   82	
   83	
   84	def main():
   85	    gtk.main()
   86	    return 0
   87	
   88	if __name__ == "__main__":
   89	    ImagesExample()
   90	    main()

9.6.1. Pixmaps

Los Pixmaps son estructuras de datos que contienen dibujos. Estos dibujos se pueden usar en varios sitios, pero lo más común es usarlos como iconos en un escritorio X, o como cursores.

Un pixmap con sólo 2 colores se llama bitmap, y hay unas cuantas rutinas adicionales para trabajar con este caso especial.

Para entender los pixmaps, es de ayuda entender cómo funciona el sistema X Window. En X, las aplicaciones no necesitan ejecutarse en el mismo ordenador que interactua con el usuario. En cambio, estas aplicaciones, llamadas "clientes", se comunican con un programa que muestra los gráficos y maneja el teclado y el ratón. Este programa que interactua directamente con el usuario se llama un "servidor de visualización" o "servidor X". Ya que la comunicación puede tener lugar sobre una red, es importante mantener alguna información en el servidor X. Los Pixmaps, por ejemplo, se almacenan en la memoria del servidor X. Esto significa que una vez que los valores de un pixmap se establecen, no hay que seguir transmitiendolos por la red; en lugar de eso, se envía un comando para "mostrar el pixmap número XYZ aqui." Incluso si no estás usando X con GTK simultáneamente, usando construcciones como Pixmaps hará que tus programas funcionen en X.

Para usar pixmaps en PyGTK, primero debemos construir un GdkPixmap usando las funciones de gtk.gdk en PyGTK. Los Pixmaps se pueden crear a partir de datos en memoria, o a partir de datos leidos de un fichero. Veamos cada una de las llamadas usadas para crear un pixmap.

  pixmap = gtk.gdk.pixmap_create_from_data(window, data, width, height, fg, bg)

Esta rutina se usa para crear un pixmap con la profundidad de color dada por el argumento window a partir de los datos data en memoria. Cada pixel usa un número de bits de datos para representar el color que es igual a la profundidad de color. El width(ancho) y el height (alto) son en pixeles. El argumento window (ventana) debe referirse a una GdkWindow realizada, ya que los recursos de un pixmap sólo tienen sentido en el contexto de la pantalla donde se va a visualizar. fg y bg son los colores de frente y fondo del pixmap.

Pixmaps can be created from XPM files using:

  pixmap, mask = gtk.gdk.pixmap_create_from_xpm(window, transparent_color, filename)

El formato XPM es una representación legible de pixmap para el Sistema de Ventanas X. Es usado ampliamente y hay muchas utilidades disponibles para crear ficheros de imágenes en este formato. En la función pixmap_create_from_xpm() el primer argumento es un GdkWindow . (La mayoría de los controles GTK tienen una GdkWindow subyacente que se puede obtener usando el atributo window (ventana) del control.) El fichero se especificar con filename que debe contener una imagen en formato XPM el cual se carga en la estructura del pixmap . La mask (máscara) es un bitmap que especifica que bits del pixmap son opacos; se crea con la función. Todos los demás pixeles se colorean con el color especificado por transparent_color. Un ejemplo del uso de esta función a continuación:

Los Pixmaps también puede crearse a partir de datos en memoria usando la función:

  pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window, transparent_color, data)

Imagenes pequeñas se pueden incorporar a un programa como datos en el formato XPM usando la función anterior. Un pixmap se crea usando estos datos, en lugar de leerlo de un fichero. Un ejemplo de este tipo de datos es:

  xpm_data = [
  "16 16 3 1",
  "       c None",
  ".      c #000000000000",
  "X      c #FFFFFFFFFFFF",
  "                ",
  "   ......       ",
  "   .XXX.X.      ",
  "   .XXX.XX.     ",
  "   .XXX.XXX.    ",
  "   .XXX.....    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .XXXXXXX.    ",
  "   .........    ",
  "                ",
  "                "
  ]

La última forma para crear un pixmap en blanco disponible para operaciones de dibujo es:

  pixmap = gtk.gdk.Pixmap(window, width, height, depth=-1)

window es o una GdkWindow o None. Si window es una GdkWindow entonces depth puede ser -1 para indicar que la profundidad se obtiene de la ventana. Si window es None entonces depth debe especificarse.

El programa pixmap.py es un ejemplo del uso de un pixmap en un botón. La figura Figura 9.6. Ejemplo de Pixmap en un Botón muestra el resultado:

Figura 9.6. Ejemplo de Pixmap en un Botón

Ejemplo de Pixmap en un Botón

El código fuente es:

    1   #!/usr/bin/env python
    2   
    3   # example pixmap.py
    4   
    5   import gtk
    6   
    7   # XPM data of Open-File icon
    8   xpm_data = [
    9   "16 16 3 1",
   10   "       c None",
   11   ".      c #000000000000",
   12   "X      c #FFFFFFFFFFFF",
   13   "                ",
   14   "   ......       ",
   15   "   .XXX.X.      ",
   16   "   .XXX.XX.     ",
   17   "   .XXX.XXX.    ",
   18   "   .XXX.....    ",
   19   "   .XXXXXXX.    ",
   20   "   .XXXXXXX.    ",
   21   "   .XXXXXXX.    ",
   22   "   .XXXXXXX.    ",
   23   "   .XXXXXXX.    ",
   24   "   .XXXXXXX.    ",
   25   "   .XXXXXXX.    ",
   26   "   .........    ",
   27   "                ",
   28   "                "
   29   ]
   30   
   31	class PixmapExample:
   32	    # when invoked (via signal delete_event), terminates the application.
   33	    def close_application(self, widget, event, data=None):
   34	        gtk.mainquit()
   35	        return gtk.FALSE
   36	
   37	    # is invoked when the button is clicked.  It just prints a message.
   38	    def button_clicked(self, widget, data=None):
   39	        print "button clicked"
   40	
   41	    def __init__(self):
   42	        # create the main window, and attach delete_event signal to terminating
   43	        # the application
   44	        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
   45	        window.connect("delete_event", self.close_application)
   46	        window.set_border_width(10)
   47	        window.show()
   48	
   49	        # now for the pixmap from XPM data
   50	        pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(window.window,
   51	                                                        None,
   52	                                                        xpm_data)
   53	
   54	        # an image widget to contain the pixmap
   55	        image = gtk.Image()
   56	        image.set_from_pixmap(pixmap, mask)
   57	        image.show()
   58	
   59	        # a button to contain the image widget
   60	        button = gtk.Button()
   61	        button.add(image)
   62	        window.add(button)
   63	        button.show()
   64	
   65	        button.connect("clicked", self.button_clicked)
   66	
   67	def main():
   68	    gtk.main()
   69	    return 0
   70	
   71	if __name__ == "__main__":
   72	    PixmapExample()
   73	    main()

Una desventaja de usar pixmaps es que que el objeto mostrado siempre es rectangular, da igual la imagen. Nos gustaría crear escritorios y aplicaciones con iconos que tengan formas más naturales. Por ejemplo, para el interfaz de un juego, nos gustaría tener botones redondos para pulsar. La forma de hacer esto es usar ventanas con forma.

Una ventana con forma es simplemente un pixmap en el que los pixeles de fondo son transparentes. De esta forma, cuando la imágen de fondo se colorea, no la sobreescribimos con un borde rectangular y que no encaja, de nuestro icono. El programa de ejemplo wheelbarrow.p muestra una imagen completa en el escritorio. La figura Figura 9.7. Ejemplo de Ventana con Forma muestra la imagen sobre una ventana de terminal:

Figura 9.7. Ejemplo de Ventana con Forma

Ejemplo de Ventana con Forma

The source code for wheelbarrow.py is:

    1   #!/usr/bin/env python
    2   
    3	# example wheelbarrow.py
    4	
    5	import gtk
    6	
    7	# XPM
    8	WheelbarrowFull_xpm = [
    9	"48 48 64 1",
   10	"       c None",
   11	".      c #DF7DCF3CC71B",
   12	"X      c #965875D669A6",
   13	"o      c #71C671C671C6",
   14	"O      c #A699A289A699",
   15	"+      c #965892489658",
   16	"@      c #8E38410330C2",
   17	"#      c #D75C7DF769A6",
   18	"$      c #F7DECF3CC71B",
   19	"%      c #96588A288E38",
   20	"&      c #A69992489E79",
   21	"*      c #8E3886178E38",
   22	"=      c #104008200820",
   23	"-      c #596510401040",
   24	";      c #C71B30C230C2",
   25	":      c #C71B9A699658",
   26	">      c #618561856185",
   27	",      c #20811C712081",
   28	"<      c #104000000000",
   29	"1      c #861720812081",
   30	"2      c #DF7D4D344103",
   31	"3      c #79E769A671C6",
   32	"4      c #861782078617",
   33	"5      c #41033CF34103",
   34	"6      c #000000000000",
   35	"7      c #49241C711040",
   36	"8      c #492445144924",
   37	"9      c #082008200820",
   38	"0      c #69A618611861",
   39	"q      c #B6DA71C65144",
   40	"w      c #410330C238E3",
   41	"e      c #CF3CBAEAB6DA",
   42	"r      c #71C6451430C2",
   43	"t      c #EFBEDB6CD75C",
   44	"y      c #28A208200820",
   45	"u      c #186110401040",
   46	"i      c #596528A21861",
   47	"p      c #71C661855965",
   48	"a      c #A69996589658",
   49	"s      c #30C228A230C2",
   50	"d      c #BEFBA289AEBA",
   51	"f      c #596545145144",
   52	"g      c #30C230C230C2",
   53	"h      c #8E3882078617",
   54	"j      c #208118612081",
   55	"k      c #38E30C300820",
   56	"l      c #30C2208128A2",
   57	"z      c #38E328A238E3",
   58	"x      c #514438E34924",
   59	"c      c #618555555965",
   60	"v      c #30C2208130C2",
   61	"b      c #38E328A230C2",
   62	"n      c #28A228A228A2",
   63	"m      c #41032CB228A2",
   64	"M      c #104010401040",
   65	"N      c #492438E34103",
   66	"B      c #28A2208128A2",
   67	"V      c #A699596538E3",
   68	"C      c #30C21C711040",
   69	"Z      c #30C218611040",
   70	"A      c #965865955965",
   71	"S      c #618534D32081",
   72	"D      c #38E31C711040",
   73	"F      c #082000000820",
   74	"                                                ",
   75	"          .XoO                                  ",
   76	"         +@#$%o&                                ",
   77	"         *=-;#::o+                              ",
   78	"           >,<12#:34                            ",
   79	"             45671#:X3                          ",
   80	"               +89<02qwo                        ",
   81	"e*                >,67;ro                       ",
   82	"ty>                 459@>+&&                    ",
   83	"$2u+                  ><ipas8*                  ",
   84	"%$;=*                *3:.Xa.dfg>                ",
   85	"Oh$;ya             *3d.a8j,Xe.d3g8+             ",
   86	" Oh$;ka          *3d$a8lz,,xxc:.e3g54           ",
   87	"  Oh$;kO       *pd$%svbzz,sxxxxfX..&wn>         ",
   88	"   Oh$@mO    *3dthwlsslszjzxxxxxxx3:td8M4       ",
   89	"    Oh$@g& *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B*     ",
   90	"     Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&   ",
   91	"      Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM*  ",
   92	"       OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
   93	"        2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
   94	"        :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
   95	"         +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
   96	"          *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&en",
   97	"           p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
   98	"           OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
   99	"            3206Bwxxszx%et.eaAp77m77mmmf3&eeeg* ",
  100	"             @26MvzxNzvlbwfpdettttttttttt.c,n&  ",
  101	"             *;16=lsNwwNwgsvslbwwvccc3pcfu<o    ",
  102	"              p;<69BvwwsszslllbBlllllllu<5+     ",
  103	"              OS0y6FBlvvvzvzss,u=Blllj=54       ",
  104	"               c1-699Blvlllllu7k96MMMg4         ",
  105	"               *10y8n6FjvllllB<166668           ",
  106	"                S-kg+>666<M<996-y6n<8*          ",
  107	"                p71=4 m69996kD8Z-66698&&        ",
  108	"                &i0ycm6n4 ogk17,0<6666g         ",
  109	"                 N-k-<>     >=01-kuu666>        ",
  110	"                 ,6ky&      &46-10ul,66,        ",
  111	"                 Ou0<>       o66y<ulw<66&       ",
  112	"                  *kk5       >66By7=xu664       ",
  113	"                   <<M4      466lj<Mxu66o       ",
  114	"                   *>>       +66uv,zN666*       ",
  115	"                              566,xxj669        ",
  116	"                              4666FF666>        ",
  117	"                               >966666M         ",
  118	"                                oM6668+         ",
  119	"                                  *4            ",
  120	"                                                ",
  121	"                                                "
  122	]
  123	
  124	class WheelbarrowExample:
  125	    # When invoked (via signal delete_event), terminates the application
  126	    def close_application(self, widget, event, data=None):
  127	        gtk.mainquit()
  128	        return gtk.FALSE
  129	
  130	    def __init__(self):
  131	        # Create the main window, and attach delete_event signal to terminate
  132	        # the application.  Note that the main window will not have a titlebar
  133	        # since we're making it a popup.
  134	        window = gtk.Window(gtk.WINDOW_POPUP)
  135	        window.connect("delete_event", self.close_application)
  136	        window.set_events(window.get_events() | gtk.gdk.BUTTON_PRESS_MASK)
  137	        window.connect("button_press_event", self.close_application)
  138	        window.show()
  139	
  140	        # Now for the pixmap and the image widget
  141	        pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
  142	            window.window, None, WheelbarrowFull_xpm)
  143	        image = gtk.Image()
  144	        image.set_from_pixmap(pixmap, mask)
  145	        image.show()
  146	
  147	        # To display the image, we use a fixed widget to place the image
  148	        fixed = gtk.Fixed()
  149	        fixed.set_size_request(200, 200)
  150	        fixed.put(image, 0, 0)
  151	        window.add(fixed)
  152	        fixed.show()
  153	
  154	        # This masks out everything except for the image itself
  155	        window.shape_combine_mask(mask, 0, 0)
  156	    
  157	        # show the window
  158	        window.set_position(gtk.WIN_POS_CENTER_ALWAYS)
  159	        window.show()
  160	
  161	def main():
  162	    gtk.main()
  163	    return 0
  164	
  165	if __name__ == "__main__":
  166	    WheelbarrowExample()
  167	    main()

Para hacer la imagen sensible, conectamos la señal "button_press_event" para hacer que el programa finalice. Las lineas 137-138 hacen el dibujo sensible a una pulsación de un botón del ratón y lo conectan al método close_application() .