Chapter 11. More on Images

Objective

In the previous section, we came across Gtk2::Gdk::Pixbuf and Gtk2::Gdk::Pixmap. This in itself does not display an image on the screen, you have to use the Gtk2::Image widget. Gtk2::Gdk::Pixbuf is used to manipulate images. You can scale them, grab pieces of them, change their color, saturation, add alpha channels, the list goes on. These methods are all documented on Gtk2::Gdk::Pixbuf's man page or online in the POD.

11.1. Image manipulation

In this lesson, we will turn our eyes to one of modern music's real heroes, Mr Robert Zimmerman aka Bob Dylan.

We will take an image of him, and scale it. We will add him to our Gtk2::Stock, as a final exercise, we will cut out his head and take a closer look at it.

Note

If you DO NOT need any image manipulation, and just want to display an image "as is", you can use the <new|set>_from_file methods available in the Gtk2::Image class.

Table 11-1. Gtk2 object classes used

Gtk2 Class Name
Gtk2::Window
Gtk2::VBox
Gtk2::HBox
Gtk2::Button
Gtk2::Frame
Gtk2::Image
Gtk2::Label
Gtk2::Stock
Gtk2::IconSet
Gtk2::IconFactory

Table 11-2. Gtk2::Gdk object classes used

Gtk2::Gdk Class Name
Gtk2::Gdk::Pixbuf
Gtk2::Gdk::PixbufLoader

11.1.1. The Screenshot.

Figure 11-1. Images

11.1.2. The Code.

The program can be found here: 'Image Manipulation'

	
  1 #! /usr/bin/perl -w
  2 
  3 use strict;
  4 use Glib qw/TRUE FALSE/;
  5 use Gtk2 '-init';
  6 use Gtk2::Gdk::Keysyms;
  7 
  8 #create the stock item
  9 &create_stock_item;
 10  
 11 #standard window creation, placement, and signal connecting
 12 my $window = Gtk2::Window->new('toplevel');
 13 $window->signal_connect('delete_event' => sub { Gtk2->main_quit; });
 14 $window->set_border_width(5);
 15 $window->set_position('center_always');
 16 
 17 #this vbox will return the bulk of the gui
 18 my $vbox = &ret_vbox();
 19 
 20 #add and show the vbox
 21 $window->add($vbox);
 22 $window->show();
 23 
 24 
 25 #our main event-loop
 26 Gtk2->main();
 27 
 28 sub create_stock_item {
 29 #this sub will add a stockitem:
 30 
 31 # the stock id our stock item will be accessed with
 32 my $stock_id = 'dylan';
 33 
 34 # add a new entry to the stock system with our id
 35 Gtk2::Stock->add ({
 36 		stock_id => $stock_id,
 37 		label    => '_Dylan - Stock image sizes',
 38 		modifier => [],
 39 		keyval   => $Gtk2::Gdk::Keysyms{D},
 40 		translation_domain => 'gtk2_image',
 41 	});
 42 	
 43 	# create an icon set, with only one member in this particular case
 44 	my $icon_set = Gtk2::IconSet->new_from_pixbuf (
 45 		Gtk2::Gdk::Pixbuf->new_from_file ("./pix/dylan.jpg"));
 46 		
 47 # create a new icon factory to handle rendering the image at various sizes...
 48 my $icon_factory = Gtk2::IconFactory->new;
 49 # add our new stock icon to it...
 50 $icon_factory->add ($stock_id, $icon_set);
 51 # and then add this custom icon factory to the list of default places in
 52 # which to search for stock ids, so any gtk+ code can find our stock icon.
 53 $icon_factory->add_default;
 54 
 55 }
 56 
 57 
 58 sub ret_vbox {
 59 
 60 my $vbox = Gtk2::VBox->new(FALSE,5);
 61 
 62 #the stock images
 63 	my $frame = Gtk2::Frame->new();
 64 		#to prove that a Gtk2::Frame can contain something else
 65 		
 66 	$frame->set_shadow_type ('out');
 67 	#method of Gtk2::Container
 68 	$frame->set_border_width(5);
 69 	
 70 		my $btn_dylan = Gtk2::Button->new_from_stock('dylan');
 71 	
 72 	$frame->set_label_widget ($btn_dylan);
 73 	
 74 		#create a hbox that will contain the various stock image sizes
 75 		my $hbox_stock = Gtk2::HBox->new(FALSE,5);
 76 		my @sizes =qw/menu small-toolbar large-toolbar button dnd dialog /;
 77 		foreach my $size(@sizes){
 78 		$hbox_stock->pack_start(Gtk2::Label->new($size.":"),FALSE,FALSE,0);
 79 			my $img_stock = Gtk2::Image->new_from_stock('dylan',$size);	
 80 		$hbox_stock->pack_start($img_stock,FALSE,FALSE,0);
 81 		}	
 82 	$frame->add($hbox_stock);
 83 	
 84 $vbox->pack_start($frame,FALSE,FALSE,0);
 85 
 86 #scaling the image
 87 	$frame = Gtk2::Frame->new('Fetching the image from a file, and scaling the original:');
 88 	$frame->set_shadow_type ('out');
 89 	#method of Gtk2::Container
 90 	$frame->set_border_width(5);
 91 	
 92 		#create a hbox that will contain the original and scaled images
 93 		my $hbox_scale = Gtk2::HBox->new(FALSE,5);
 94 		
 95 			my $lbl_type = Gtk2::Label->new("original\n(100x100):");
 96 		$hbox_scale->pack_start($lbl_type,FALSE,FALSE,0);
 97 			
 98 	#________
 99 	#the Gtk2::Gdk::PixbufLoader is used in
100 	# the acquisition of images in "raw" format.
101 	#This will typically be data from a database
102 			my $pixbufloader = Gtk2::Gdk::PixbufLoader->new;
103 				my $raw_data = `cat ./pix/dylan.jpg`;
104 			$pixbufloader->write($raw_data);
105 			$pixbufloader->close;		
106 			my $pixbuf = $pixbufloader->get_pixbuf;
107 			 
108 			my $img_orig = Gtk2::Image->new_from_pixbuf($pixbuf);	
109 		$hbox_scale->pack_start($img_orig,FALSE,FALSE,0);
110 			
111 		$lbl_type = Gtk2::Label->new("Scale\n(150x150):");
112 		$hbox_scale->pack_start($lbl_type,FALSE,FALSE,0);
113 							
114 			my $pixbuf_larger = $pixbuf->scale_simple(150,150,'bilinear');
115 			my $img_larger = Gtk2::Image->new_from_pixbuf($pixbuf_larger);
116 		$hbox_scale->pack_start($img_larger,FALSE,FALSE,0);
117 		
118 		$lbl_type = Gtk2::Label->new("Scale\n(50x50):");
119 		$hbox_scale->pack_start($lbl_type,FALSE,FALSE,0);
120 							
121 			my $pixbuf_smaller = $pixbuf->scale_simple(50,50,'bilinear');
122 			my $img_smaller = Gtk2::Image->new_from_pixbuf($pixbuf_smaller);
123 		$hbox_scale->pack_start($img_smaller,FALSE,FALSE,0);
124 			
125 	$frame->add($hbox_scale);
126 			
127 $vbox->pack_start($frame,FALSE,FALSE,0);
128 
129 #cut and zoom
130 $frame = Gtk2::Frame->new('Fetching a piece of a pixbuff, and scaling it:');
131 	$frame->set_shadow_type ('out');
132 	#method of Gtk2::Container
133 	$frame->set_border_width(5);
134 	
135 	my $pixbuf_head = $pixbuf->new_subpixbuf (13, 11, 50, 50);
136 	my $pixbuf_head_large = $pixbuf_head->scale_simple(150,150,'bilinear');
137 	
138 	#create a hbox that will contain the original and scaled head images
139 	my $hbox_head_scale = Gtk2::HBox->new(0,5);
140 		
141 		$lbl_type = Gtk2::Label->new("Original head:");
142 	$hbox_head_scale->pack_start($lbl_type,FALSE,FALSE,0);
143 		my $img_head = Gtk2::Image->new_from_pixbuf($pixbuf_head);
144 	$hbox_head_scale->pack_start($img_head,FALSE,FALSE,0);
145 	
146 	$lbl_type = Gtk2::Label->new("Scaled head:");
147 	$hbox_head_scale->pack_start($lbl_type,FALSE,FALSE,0);
148 		my $img_head_large = Gtk2::Image->new_from_pixbuf($pixbuf_head_large);
149 	$hbox_head_scale->pack_start($img_head_large,FALSE,FALSE,0);
150 			
151 	$frame->add($hbox_head_scale);
152 	
153 $vbox->pack_start($frame,FALSE,FALSE,0);	
154 	
155 $vbox->show_all();
156 return $vbox;
157 }

11.1.3. Discussing the program.

Gtk2::Stock

We will start our discussion by looking at Gtk2::Stock. Up to now, we only used available stock items. Stock items can be used in various places, is a nice way to standardize, and eases internationalization.

Tip

If you expect to see the standard stock icons stored somewhere in your file system, you are in for a surprise. These icons are data structures, compiled into Gtk+.

Gtk2::Stock has the ability to add new stock items to it. These new items will only be available while the program run, and is destroyed as soon as it terminates. We follow a few standard steps to create a stock item.

  • To add the new stock item, we use the add method, and supply data to a hash of key/value pairs

    # add a new entry to the stock system with our id
    Gtk2::Stock->add ({
    		stock_id => $stock_id,
    		label    => '_Dylan - Stock image sizes',
    		modifier => [],
    		keyval   => $Gtk2::Gdk::Keysyms{D},
    		translation_domain => 'gtk2_image',
    	});
    		

    Two important hash keys are "stock_id" and "label". The rest are used for more advanced functions, that will not be needed in our program. At this stage the new stock item is ready to be used. If you want to incorporate an icon with it (like we want to) you need a few extra steps.

  • Create a Gtk2::IconSet, with only one member in this particular case.

    my $icon_set = Gtk2::IconSet->new_from_pixbuf (
    		Gtk2::Gdk::Pixbuf->new_from_file ("./pix/dylan.jpg"));
    The data for the pixbuf can be from various sources, in our example we opt for an image file.

  • Create a new Gtk2::IconFactory factory to handle rendering the image at various sizes.

    my $icon_factory = Gtk2::IconFactory->new;
    We will show in our program the various sizes available for stock icons.

  • Add our new stock icon to it.

    $icon_factory->add ($stock_id, $icon_set);
    This will tie the icon to the stock item.

  • Then add this custom Gtk2::IconFactory to the list of default places in which to search for stock ids, so any Gtk+ code can find our stock icon.

    $icon_factory->add_default;
    This finish the steps to add the icon to the Gtk2::Stock item.

Getting image data

Sometimes the images you want to show in your application can not be fetched using the typical 'from_file' methods. Images from a database is a classic example. Rather than writing them to a temp file, and reading the temp file, we can directly use them. In our sample program we simulate this situation.

#the Gtk2::Gdk::PixbufLoader is used in
# the acquisition of images in "raw" format.
#This will typically be data from a database
		my $pixbufloader = Gtk2::Gdk::PixbufLoader->new;
			my $raw_data = `cat ./pix/dylan.jpg`;
		$pixbufloader->write($raw_data);
		$pixbufloader->close;		
	my $pixbuf = $pixbufloader->get_pixbuf;
			 
my $img_orig = Gtk2::Image->new_from_pixbuf($pixbuf);	

Image manipulation

In our program, we use available methods of Gtk2::Gdk::Pixbuf to manipulate an image.

  • To scale a image we use:

    pixbuf = $src->scale_simple ($dest_width, $dest_height, $interp_type) 
    This allow various values for "$interp_type", but most end results are the same. We used 'bilinear'.

  • To grab only a piece of an exitsing Gtk2::Gdk::Pixbuf:

     pixbuf = $src_pixbuf->new_subpixbuf ($src_x, $src_y, $width, $height) 
    All the arguments should be easy to understand.

General

Remember that manipulating a Gtk2::Gdk::Pixbuf does not show it on screen. To do that, we have to show it in a Gtk2::Image widget.

When displaying stock images, you need to supply the size of the image. Our program list, and show all available sizes for stock images.