Add your own GIMP features

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.

João Bueno is a GIMP contributor since 2004, being, among other roles, translation manager for Brazilian Portuguese. He lives in Brazil and works for-hire projects in the Python programing language or involving graphics software. He is a director and board member for the Brazilian Python Association and teaches part time as associate professor at FATEC Americana.

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.

Building GIMP on Windows

Building GIMP on a Microsoft® Windows® system is a lot trickier, as
the build takes for granted a lot of programs and libraries that are installed by default on a Linux system. If you are on Windows, it is recommended that you get a Linux install on a virtual machine to set up your build environment. It is possible to compile GIMP for Windows from the Linux virtual machine using Mingw32 tools (see Resources).

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.

Getting GIMP source code

To retrieve the latest development version, just type git clone
git://git.gnome.org/gimp from the command line. After a few minutes, you will have the complete GIMP code. Things are well organized, making it relatively easy to find your way around the more than 3,000 downloaded files.

A note on using Git

When making changes, you don't have to worry about losing any of your original files, or even your changes, in case you decide to preserve them for your customizations, thanks to the Git system. For example, to reset any file to the way it is in GIMP repository, just type git checkout <filename>.

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

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.

Listing 2. Other important libraries

Making sure the libraries on your system are up to date

For the libraries already up to date on your system, the package-managing system of your Linux distribution can automatically fetch the needed libraries and their devel packages.

On Ubuntu and Debian, simply type sudo apt-get build-dep gimp.

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.

Outdated or missing libraries on your distribution repository

Not all the libraries outlined above will be up to date for you to build GIMP on
your Linux distribution. This is especially true if you try to build GIMP
master — the development version. But it can happen on older
systems when trying to build a stable GIMP, as well. To build the
development GIMP, you will typically have to build at least the GEneric Graphics Library (GEGL)
library from Git.

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.

Listing 3. Variables for building

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.

Listing 4. Compiling and installing components using make

./configure --prefix=<xxx>
make
sudo make install

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).

Listing 5. Setting environmental variables

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.

Looking around the source

Now that you have successfully built GIMP, it's time to take a look at what is new inside the GIMP source code.

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.

The source tree

GIMP source starts with 29 directories, seven of which are just for the translation
files of the other components (the po.* directories). Nine are for modularized
libraries, which contain specific functions and constants that can be used from within
GIMP itself or from plug-ins written in C. Other noteworthy directories include the
plug-ins directory, where the code for all plug-ins that come with GIMP, including the
scheme (script-fu) and Python extensions for writing plug-in and scripts, resides.

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.

Finding your way in the source

As a large project, every feature in GIMP is nicely separated, so the code that deals
with the same set of features is grouped together. Most C files are stored in the /app
directory and are linked together in the single GIMP-executable binary when the
project is built. There are more than 900 C files in here and almost that number of header files (.h), so you have to prepare yourself to do some searching when looking for where a feature is coded.

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:

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.

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.

Modifying the GIMP source code

Now that you have an idea of how to find features inside the source tree, it's time to
make some changes. At this stage, you should try some minor change just to see that it works. Let's start by disabling the full-screen functionality by commenting out a function call above and rebuilding GIMP.

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.

Creating a new tool

Now let's move on to making a real change to the program. In the example for this
article, you are creating a painting tool that can be selected from the toolbox.
Please keep in mind that before creating a new tool, you must review the functionality that already exists in the program.

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.

Finding what to change

The first step is to identify which files you need to copy, modify, and add to the build system so the application gets an extra tool for painting that behaves as described above. The first place to look is in the app/tools directory, at the gimppaintbrushtool.h and gimppaintbrushtool.c files.

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.

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.

Making the relevant changes

To move forward, once you decide that proper changes in the paintbrush file can achieve
the desired effect, you should make a copy of this file and rename it. It's a good idea to have a name chosen for the new tool as you do so. For this example, you are using gradientbrush.

Copy app/paint/paintbrush.c and app/paint/paintbrush.h files to gradientbrush.c and
gradientbrush.h on the same directory. Edit the files, and perform a replace operation
so that everything that reads either paintbrush, Paintbrush, PAINTBRUSH, etc. is
respectively changed to the new name, gradientbrush. It's important to respect case-sensitivity in all intstances. This creates a new GObject class for your tool.

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.

To add a copy of the paintbrush tool to the paint directory:

Copy the files gimppaintbrush.c and gimppaintbrush.h to gimpgradientbrush.*, and rename
all occurrences of paintbrush to gradientbrush in them (preserving the
case).

In Makefile.am, add references to both gimpgradientbrush.h and gimpgradientbrush.c.

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.

In paint-types.h, dd a typedef line analog to the one used for GimpPaintbrush.

To add a copy of the paintbrush to the tool directory:

Copy the files gimppaintbrushtool (c and h) to gimpgradientbrushtool versions and
rename internal references to the new tool name.

In Makefile.am, add references to the new gimpgradientbrushtool files.

In gimp-tools.c, add include clause to the header file gimpgradientbrushtool.h. Add
the function gimp_gradientbrush_register to the listing in
the gimp_tools_init function. And in the function gimp_tools_register, add an else if block
analog to the one used for the paintbrush. Wet the paint_code_name to gimp-gradientbrush in
there.

That should do the trick. Now, when building, you should have one extra paintbrush icon
available in the toolbox, as illustrated in Figure 1.

Figure 1. GIMP's toolbox featuring the newly created tool

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.

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.

Figure 2. Example of usage of the gradientbrush tool

You just created your own tool for GIMP

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.

The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.