Add Your Own GIMP Features: Dive Into The Code Base of The GNU Image Manipulation Program
Add Your Own GIMP Features: Dive Into The Code Base of The GNU Image Manipulation Program
Dive into the code base of the GNU Image Manipulation Program
The GNU Image Manipulation Program (GIMP) is a robust application for editing and
manipulating digital images. Because it's open source software, any developer is allowed to
modify and extend it with even more features. In this article, you will learn how to get started
with the GIMP code, how to build the project from the Git repositories, and how to find your
way around the code tree. And you will build an example application that creates a whole new
painting tool for the program.
Why GIMP?
One of the most compelling reasons for using free or open source software is that it provides
an opportunity for the user of the product to add whatever features he wants or needs. But the
ability to add features is constrained by a project's size and complexity, and the nature of available
documentation. So, while GIMP is one of the most well-known and successful open source
software projects, its huge code base can be intimidating.
To follow along, you should be familiar with the C programing language. You should also know or
be prepared to learn about the Git versioning tool. The example in this article was created using
GIMP V2.7 on a Linux® environment (note that V2.7 is a development branch and not a stable
release). The spring 2009 version of Mandriva Linux was used in this article, but any version of
Linux should work fine (see Resources).
You will be creating a tool based on an existing painting tool. The tool created in this article is
purely for instructional purposes. For it to become an actual project that would be used as part of
the GIMP distribution, it would have to be thoroughly vetted by the core GIMP developers and the
UI architect.
Getting started
The first step toward working with GIMP is getting GIMP to build. While it is trivial to look at the
code by simply uncompressing a source tarball, and even easier using the Git Web interface to the
code repository, but getting it to actually build can be tricky.
Considering the size of the source code, GIMP is nicely maintained and consistent to build.
However, you will have to deal with the issue of needed dependencies. When you run software
like GIMP, a lot of libraries are transparently installed on your system. When you want to build
the software, more information than just the library binaries is needed. Most Linux distributions
package these dependencies separately from the main packages. Aside from the libraries, you will
also need the compiler itself and the associated tool chains. In most popular Linux distributions,
you just have to type a few commands to get everything ready.
For the GIMP source code itself, you should get one of the development versions from Git. Getting
a Git tree is preferable, even if you will be working on the code of the stable version. This allows
you to easily track your own changes to the code. Git is a decentralized version-control software,
which can be used to keep GIMP code on the main repository. It is designed to be used from the
command line, although graphic interfaces exist.
You have to get familiar with Git anyway, even if you don't plan on contributing back your code. It
can make your life a lot easier, even if you are only using it to track the changes you've made to
the code base. For example, at any given moment, you can see all the changes you have made to
the code base just by typing git diff.
Using Git properly allows you to create local branches where you can develop different features
and at any time have them updated with changes in the GIMP.
Building GIMP
To get a build of the GIMP development branch — the Git master — you will need the recent
versions of the libraries shown in Listing 1 and their headers installed. These headers usually
come in Linux packages named *-dev or *-devel.
Before starting, you should take a look at the HACKING file that comes with the GIMP source files,
which specifies the rules for the development of the project.
Listing 1. Libraries you should get for building current Git master
glib 2.24.0
gtk 2.20.0
babl, 0.1.2
gegl, 0.1.2
libpng 1.2.34
cairo 1.6.0
pango 1.20.1
fontconfig 2.2.0
gtkdoc 1.0
Besides those mandatory libraries, you will want to have the following extra libraries (see Listing
2). If they are not found, you will have missing functionality and you will have to pass options for
the build system to ignore them. For example, you will have to call the autogen.sh with autogen.sh
--prefix=<prefix> --without-libpng if you don't have the development package for libpng
installed.
On Mandriva Linux, you can use the --buildrequires option of URPMI: urpmi --buildrequires
gimp. You will have to configure a source rpm repository first.
For OpenSuSE, you may want to check the documentation on the zypper command.
On Fedora, Redhat, CentOS, and SuSe and most other distributions, you have to install the -
devel packages manually. Don't worry about forgetting any of them; the build system will stop and
ask you for it. A misleading message is printed in this case, which will say that you are missing
library x. However, a quick check will reveal that you do have library x installed on your system.
The cross-distribution way of checking library versions is the pkg-config command. For example,
pkg-config --modversion gtk+-2.0 will display the installed version of GTK+ V2.x.
If the build system complains about an old version, you will need a newer one on your new GIMP
prefix. If it says the library is missing, more likely what is missing are the C header files that the
software uses so those libraries can be compiled. These header files are usually in separate
packages — the ones ending in -dev or -devel, according to your distribution. That is, even if you
have GTK V2.20 installed on your system, you will want to install the gtk2-devel package.
The outdated or missing libraries should be fetched from the latest stable tarball for each library.
Normally, the first hit on library x download when searching on the Web will lead you to the
download page for each library. You may prefer to fetch the Git version instead of the tarball, which
is acceptable practice, but it's best to be conservative and fetch Git-stable branches for each
library and not use unstable versions.
One exception is the GEGL library, which requires you to fetch the Git master (unstable) branch to
build the GIMP master, instead of the latest stable branch. GEGL is in the process of replacing the
core-compositing and image operations in GIMP itself. Retrieve its code with git clone git://
git.gnome.org/gegl.
For each library you have to install in this way (and for GIMP itself), you will have to take care
not to overwrite the library that came installed in your distribution. To prevent this, you should
build them in another directory prefix. I usually use the /opt prefix. Other ways to accomplish this
besides passing the --prefix option to the configure (or autogen.sh) script, involve creating the
following variables, as shown in Listing 3.
Before installing the first library in this way, be sure the /opt/share/aclocal directory exists; if not,
create it.
Most of the needed components use the make system and can be compiled and installed on your
system by switching to the directory of the unpacked source code, as shown in Listing 4.
For libraries you fetched with Git, replace the first command in Listing 4, /configure, with ./
autogen.sh --prefix=<xxx>. Also, if you are building GTK+, include the option --with-xinput=yes
on the autogen or configure command line. This will enable tablets and other pressure-sensitive
devices to work with GIMP.
Compiling GIMP
Once you have the prerequisites in place, compiling GIMP is straightforward. Set the same
environment variables from Listing 4 so that GIMP can fetch the newer libraries in the different
prefix you picked and get GIMP built in that prefix as well. This will avoid conflict with the system-
installed stable GIMP itself (see Listing 5).
Make a script with these settings and run it with the source shell command. You will need to set
these variables each time you build GIMP. Then switch to the GIMP source base directory and
type the code in Listing 6.
If there are any error messages about missing libraries, proceed as described in the "Outdated or
missing libraries on your distribution repository" section.
Among the program features you should check are the ability to tag resources like brushes,
palettes, gradients, layer groups, on-canvas text editing, and the new paint dynamics. Each of
these could easily fill a chapter in a GIMP book. Because they are being actively developed,
keep in mind that if you choose to modify these sections, you are better off collaborating with the
developers closely, lest your changes be rendered useless later.
And finally, all the application code itself is contained within the app directory. There are a few C
files here, along with 20 directories where the application itself is distributed. Some of the names
are descriptive of what the code inside should be doing, such as dialogs or xcf; others are more
general, such as core, base, actions.
One of the best ways to find where the code for a feature you saw in the program resides is to
use the grep command. grep is a standard UNIX® command-line utility to search for a text pattern
inside one or several files. One sure way to look for a feature is to search for any text it presents
on the UI itself. Of course, you have to be running GIMP in English for that, or all text shown on the
screen is on the string-translation files, in the po/ dir (outside the app tree).
Suppose you want to find the code responsible for toggling a GIMP window into full-screen mode.
First you verify that the tooltip for it is Toggle fullscreen view (on GIMP's View menu). Switching
to the app directory, you can type grep -i "toggle fullscreen view" ‛find -name "*c" ‛.
The -i switch tells grep to be case-insensitive, and the subcommand ‛find -name "*c" (note that
it is enclosed in backward quotes, which is essential because the command won't work with other
kinds of quotes), returns a list of all C files in the directory tree you are searching. So grep runs
through all C files looking for the text pattern that it was given. The reply will be as follows:
./actions/view-actions.c: NC_("view-action", "Toggle fullscreen view"),
To look into the file, I suggest using the less command. If you want a more detailed look inside this
file, use the text editor of your choice (see Listing 7).
So, even without understanding all that this file does, you can anticipate the next step. The only
thing the action entry does is associate it with a function named view_fullscreen_cmd_callback
and nothing else. So your next step is to run grep again. As far as you know by now, this function
could be anywhere on the tree:
grep -i "view_fullscreen_cmd_callback" ‛find -name "*c" ‛
This returns two hits: One of them is the entry you just saw on the actions.c file itself; the other one
is inside the file ./actions/view-commands.c. When peeking inside that file, you finally see some
code. There is a C function that checks if a window exists, retrieves the active image, and calls a
function named gimp_image_window_set_fullscreen. You guessed it; that is our next grep target:
grep -i gimp_image_window_set_fullscreen ‛find -name "*c" ‛
This leads us straight to the file app/display/gimpimagewindow.c, shown in Listing 8. When you
look at the contents of this file, you will see what this function does. It turns out to be rather simple:
just a call to the GTK+ function to maximize the window.
Listing 8. app/display/gimpimagewindow.c
gimp_image_window_set_fullscreen (GimpImageWindow *window,
gboolean fullscreen)
{
g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
Even though the maximizer function itself is quite simple, by viewing the contents of this file, you
can get a good sense of GIMP's inner working. The code responsible for displaying the top window
and keeping its attributes is present in this file. If you are using the GIMP V2.7 tree, you can see
a lot of newly written code used to manage the dockable dialogs when GIMP is in the new single-
window mode.
At this point, you can also get a good idea of what the actions and commands files in the actions
do. You do not need to fully understand them to realize that they create callable commands
as actions from the users. The actions themselves streamline that further, aggregating meta-
information such as tooltips, display text, translation hints, etc. Once an action is named, it can be
used straight from an XML file to be added to an application menu, for example. The XML files that
create the menus from the actions in the app/actions directory are all on the menu directory on the
project root directory. Reordering GIMP's menus is a simple matter of editing an XML file.
To see that, just open the app/display/gimpimagewindow.c file above for editing and on the first
line inside the gimp_image_window_set_fullscreen function, add a return; statement. Rebuild
your GIMP application by typing make. There is no need to re-run autogen.sh. You can also run the
resulting gimp-2.7 binary file in the app directory, instead of reinstalling it. This version of GIMP
won't have the full-screen feature.
Object-oriented programing in C
C is not ordinarily thought of as an object-oriented (OO) language, but OO is more about a way
of building applications than it is intrinsic to languages. Just as it is possible to code non-OO
applications in languages that force you to use a class/instance syntax, it is also possible to write
OO code without the syntax niceties provided by higher-level languages.
That is the case with GIMP: It is based on the GObject framework, which allows for C code to
be written in an OO way and behave OO-like at runtime. The drawback is that it requires some
boilerplate code to create new classes and manipulating objects around. On the other hand, it just
works.
One of the gains of having OO libraries written in C is that you can have language bindings for
other languages like Python, Ruby, the Java programming language, etc. Libraries closely tied to
GIMP, such as GTK+, GEGL, and many others, also use the GObject system.
Among the possible combinations of paint dynamics, animated brushes, painting modes, and
existing tools, a lot of combinations can be achieved. One thing that is not currently possible,
for example, is to have a single paint stroke vary its color in a radial way so that the center of
the brush shows up in one color and the outer part of the brush mask uses another color. Color
selection for the stroke would follow the active gradient, as it works for the "color from gradient"
painting option.
To our dismay, these are just small files with what is mostly boilerplate code to create the tool as
a GObject class. Going back to the command line, in the app directory, you can perform a grep for
paintbrush to check if there is any other place that could contain the relevant code.
This time, a somewhat larger listing containing several files and some points inside each file
is returned. The good news is that you got results. The not-so-good news is that since you are
intending to clone the paintbrush tool, you will have to visit most of these files and their header (.h)
counterparts and either copy them or add references to your new tool just as there are references
to the current paintbrush tool.
The files listed when performing the grep are shown in Listing 9.
It turns out that there is another file named gimpaintbrush.c without the tool suffix. Open it for
editing. This one looks promising. Its last function, _gimp_paintbrush_motion, actually makes a
series of function calls to retrieve a buffer area to be painted, the current brush to be used, the
color to be applied from the painting options and painting dynamic system, and fills in the pixels of
the buffer to be painted. It commits the stroke by calling gimp_brush_core_paste_canvas.
Experimenting a bit
The best part is that you only have to have a basic familiarity with C code to understand what is
going on. The large function names and object system now show their worth. The code is easy to
understand. You can check what some of the function calls do by using grep to find the functions
and take a look at their code, as well.
Now you can play around, even if you only force a particular painting mode or opacity when
painting, just to see the changes. You could do that by replacing the contents of the opacity
variable to a fixed number, before any function calls it, for example.
For the new files to be compiled when running make, you have to add then to the Makefile.am file
in the directory they are in. This will be enough for them to get compiled and linked into the GIMP
executable when a build is performed.
This only creates a new GIMP core, which does nothing yet; it has to be integrated into a new tool
and registered.
And, of course, when everything is in place, you have to make the desired changes to the painting
function itself so it performs the desired task: painting using a radial color gradient along the brush.
(Listing 10 below has the code for this function.)
Almost all the needed changes from here on involve editing most of the files that include the term
paintbrush. If it is a file listing all the other paint tools, just copy the lines making reference to the
paintbrush and rewrite them so they act on the gradientbrush.
Note that because no new icons or tool cursors were created in this example, these occurrences of
paintbrush were kept as they are: GIMP_STOCK_TOOL_PAINTBRUSH, GIMP_TOOL_CURSOR_PAINTBRUSH.
The code on the paint directory is responsible for actually updating the image with the various
tools. Code on the tools directory is responsible for tying a tool functionality, like paintbrush or
bucket-fill, to the use interface. Both directories have files to be updated to create a new tool.
1. Copy the files gimppaintbrush.c and gimppaintbrush.h to gimpgradientbrush.*, and rename all
occurrences of paintbrush to gradientbrush in them (preserving the case).
2. In Makefile.am, add references to both gimpgradientbrush.h and gimpgradientbrush.c.
3. In gimp-paint.c, add include clause to the header file gimpgradientbrush.h; add the function
gimp_gradientbrush_register to the listing in the gimp_paint_init function.
4. In paint-types.h, dd a typedef line analog to the one used for GimpPaintbrush.
That should do the trick. Now, when building, you should have one extra paintbrush icon available
in the toolbox, as illustrated in Figure 1.
For the code itself, the changes are a little more extensive. Listing 10 shows the code for the
_gimp_gradientbrush_motion in the app/paint/gimpgradientbrush.c file. It is the only place where
new code had to be written for creating the new tool.
paint_appl_mode = GIMP_PAINT_INCREMENTAL;;
area_data = temp_buf_get_data(area);
cx = area->width / 2;
cy = area->height / 2;
for (x = 0; x < area->width; x++)
for (y = 0; y < area->height; y++)
{
u = (gint)sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)) * MAX_CHANNELS;
v = (x + y * area->width) * area->bytes;
if (area->bytes >= 3)
{
area_data[v + RED] = colors[u + RED];
area_data[v + GREEN] = colors[u + GREEN];
area_data[v + BLUE] = colors[u + BLUE];
if (area->bytes == 4)
area_data[v + ALPHA] = colors[u + ALPHA];
}
else
{
/* FIXME: get color value instead; */
area_data[v] = colors[u + RED];
if (area->bytes == 2)
area_data[v] = colors[u + ALPHA];
}
}
/* finally, let the brush core paste the colored area on the canvas */
gimp_brush_core_paste_canvas (brush_core, drawable,
coords,
The _gimp_gradientbrush_motion function is called for each paint stroke of the painting tool. It
creates an internal buffer with half the size of the diagonal of the rectangle containing the brush
that is being used to paint in GIMP and populates it with the colors extracted from the active
gradient. It then fills the area with a mapping, which is an image buffer used to color up the
painting area of each stroke. Instead of making a function call to fill it with a solid color, which the
original function in gimppaintbrush.c did, the new function walks through each pixel, assigning it a
color according to its distance from the center of the brush.
Replace the code for _gimp_gradientbrush_motion for the code in Listing 10. When building GIMP
with these changes, type make, then when it is done, type make install as root and you should
have a fully functional new tool in GIMP.
Figure 2 shows a quick draft made with the new tool and the paint dynamics system, set to track
painting direction, and a high-aspect ratio brush.
Before deciding to create a new tool, you should also consider writing a plug-in for GIMP. It is an
easier process than making changes to the core. Plug-ins have limited functionality, however, such
as not allowing the user to interact on the image window itself. Any previews or user interactions
have to be drawn apart from the main application. On the other hand, if you write a plug-in, it can
be distributed by itself, without the need for a custom version of GIMP for other people to use.
Conclusion
You should now have a solid understanding of how to retrieve the GIMP source code and
dependencies, and how to build GIMP in a Linux system. Through the paintbrush example, you
learned how to navigate the source tree and use grep to find to find the code that implements the
features you want to modify. You also saw what it takes to create a new tool for GIMP. Perhaps
someday your new feature will find its way into the GIMP source for the millions of users worldwide
to enjoy.
Downloadable resources
Description Name Size
Article source code os-gimp-add.gradientbrush.tool.zip 5KB