Shallow Thoughts : : gimp
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Thu, 22 Oct 2015
I went to a night sky photography talk on Tuesday. The presenter
talked a bit about tips on camera lenses, exposures; then showed
a raw image and prepared to demonstrate how to process it to bring
out the details.
His slides disappeared, the screen went blank, and then ... nothing.
He wrestled with his laptop for a while. Finally he said "Looks like
I'm going to need a network connection", left the podium and headed
out the door to find someone to help him with that.
I'm not sure what the networking issue was:
the nature center has open wi-fi, but you know how it is during talks:
if anything can possibly go wrong with networking, it will, which is
why a good speaker tries not to rely on it. And I'm not blaming this
speaker, who had clearly done plenty of preparation and thought
he had everything lined up.
Eventually they got the network connection, and he connected to Adobe.
It turns out the problem was that Adobe Photoshop is now cloud-based.
Even if you have a local copy of the software, it insists on checking
in with Adobe at least every 30 days. At least, that's the theory.
But he had used the software on that laptop earlier that same day,
and thought he was safe. But that wasn't good enough, and Photoshop
picked the worst possible time -- a talk in front of a large audience
-- to decide it needed to check in before letting him do anything.
Someone sitting near me muttered "I'd been thinking about buying that,
but now I don't think I will." Someone else told me afterward that
all Photoshop is now cloud-based; older versions still work,
but if you buy Photoshop now, your only option is this cloud version
that may decide ... at the least opportune moment ... that you can't
use your software any more.
I'm so glad I use Free software like GIMP. Not that things can't go
wrong giving a GIMP talk, of course. Unexpected problems or bugs can
arise with any software, and you take that risk any time you give a
But at least with Free, open source software like GIMP, you know you
own the software and it's not suddenly going to refuse to run without
a license check. That sort of freedom is what makes the difference
between free as in beer, and Free as in speech.
You can practice your demo carefully before the talk
to guard against most bugs and glitches; but all the practice in the
world won't guard against software that won't start.
I talked to the club president afterward and offered to give a GIMP
talk to the club some time soon, when their schedule allows.
[ 10:24 Oct 22, 2015
More gimp |
permalink to this entry |
Sun, 04 Oct 2015
For the animations
I made from the lunar eclipse last week, the hard part was aligning
all the images so the moon (or, in the case of the moonrise image, the
hillside) was in the same position in every time.
This is a problem that comes up a lot with astrophotography, where
multiple images are stacked for a variety of reasons: to increase
contrast, to increase detail, or to take an average of a series of images,
as well as animations like I was making this time.
And of course animations can be fun in any context, not just astrophotography.
In the tutorial that follows, clicking on the images will show a full
sized screenshot with more detail.
Load all the images as layers in a single GIMP image
The first thing I did was load up all the images as layers in a single image:
File->Open as Layers...
, then navigate to where the images are
and use shift-click to select all the filenames I wanted.
Work on two layers at once
By clicking on the "eyeball" icon in the Layers dialog, I could
adjust which layers were visible. For each pair of layers, I made
the top layer about 50% opaque by dragging the opacity slider (it's
not important that it be exactly at 50%, as long as you can see both
Then use the Move tool to drag the top image on top of the bottom image.
But it's hard to tell when they're exactly aligned
"Drag the top image on top of the bottom image":
easy to say, hard to do. When the images are dim and red like that,
and half of the image is nearly invisible, it's very hard to tell when
they're exactly aligned.
Use a Contrast display filter
What helped was a Contrast filter.
and in the dialog that pops up,
click on Contrast
, and click on the right arrow to move it to
The Contrast filter changes the colors so that dim red moon is fully
visible, and it's much easier to tell when the layers are
approximately on top of each other.
Use Difference mode for the final fine-tuning
Even with the Contrast filter, though, it's hard to see when the
images are exactly on top of each other. When you have them within a few
pixels, get rid of the contrast filter (you can keep the dialog up but
disable the filter by un-checking its checkbox in Active Filters
Then, in the Layers dialog, slide the top layer's Opacity back to 100%,
go to the Mode
selector and set the layer's mode to
In Difference mode, you only see differences between the two layers.
So if your alignment is off by a few pixels, it'll be much easier to see.
Even in a case like an eclipse where the moon's appearance is changing
from frame to frame as the earth's shadow moves across it, you can still
get the best alignment by making the Difference between the two layers
as small as you can.
Use the Move tool and the keyboard: left, right, up and down arrows move
your layer by one pixel at a time. Pick a direction, hit the arrow key
a couple of times and see how the difference changes. If it got bigger,
use the opposite arrow key to go back the other way.
When you get to where there's almost no difference between the two layers,
you're done. Change Mode back to Normal, make sure Opacity is at 100%,
then move on to the next layer in the stack.
It's still a lot of work. I'd love to find a program that looks for
circular or partially-circular shapes in successive images and does
the alignment automatically. Someone on GIMP suggested I might be
able to write something using OpenCV, which has circle-finding
primitives (I've written briefly before about
a wrapper that makes OpenCV easy to use from Python).
But doing the alignment by hand in GIMP, while somewhat tedious,
didn't take as long as I expected once I got the hang of using the
Contrast display filter along with Opacity and Difference mode.
Creating the animation
Once you have your layers, how do you turn them into an animation?
The obvious solution, which I originally intended to use, is to save
as GIF and check the "animated" box. I tried that -- and discovered
that the color errors you get when converting an image to indexed make
a beautiful red lunar eclipse look absolutely awful.
a series of JPEGs. That meant that I needed to export all the layers
from my GIMP image to separate JPG files.
GIMP doesn't have a built-in way to export all of an image's layers to
separate new images. But that's an easy plug-in to write, and a web
search found lots of plug-ins already written to do that job.
The one I ended up using was Lie Ryan's Python script in
to save different layers of a design in separate files;
though a couple of others looked promising (I didn't try them), such as
You can see the final animation here:
Lunar eclipse of
September 27, 2015: Animations.
[ 09:44 Oct 04, 2015
More gimp |
permalink to this entry |
Sat, 07 Mar 2015
I needed to turn some small black-on-white icons to blue-on-white.
Simple task, right? Except, not really. If there are intermediate
colors that are not pure white or pure black -- which you can see
if you magnify the image a lot, like this 800% view of a 20x20 icon --
it gets trickier.
You can't use anything like
Color to Alpha or Bucket Fill, because all those grey antialiased
pixels will stay grey, as you see in the image at left.
And the Hue-Saturation dialog, so handy for changing the hue of a sky,
a car or a dress, does nothing at all -- because changing hue
has no effect when saturation is zero, as for black, grey or white.
So what can you do?
I fiddled with several options, but the best way I've found is the
Screen layer mode. It works like this:
In the Layers dialog, click the New Layer button and accept the
defaults. You'll get a new, empty layer.
Set the foreground color to your chosen color.
Drag the foreground color into the image, or do Edit->Fill with
Now it looks like your whole image is the new color. But don't panic!
Use the menu at the top of the Layers dialog to change the top layer's
mode to Screen.
Layer modes specify how to combine two layers. (For a lot more information,
see my book, Beginning GIMP).
Multiply mode, for example, multiplies each pixel in the two layers,
which makes light colors a lot more intense while not changing dark
colors very much.
Screen mode is sort of the opposite of Multiply mode: GIMP inverts
each of the layers, multiplies them together, then inverts them again.
All those white pixels in the image, when inverted, are black (a value
of zero), so multiplying them doesn't change anything. They'll still be
white when they're inverted back. But black pixels, in Screen mode,
take on the color of the other layer -- exactly what I needed here.
Intensify the effect with contrast
One place I use this Screen mode trick is with pencil sketches.
For example, I've made a lot of
sketches of Mars
over the years, like this sketch of Lacus Solis, the "Eye of Mars".
But it's always a little frustrating: Mars is all shades
of reddish orange and brown, not grey like a graphite pencil.
Adding an orange layer in Screen mode helps, but it has another problem:
it washes out the image. What I need is to intensify the image underneath:
increase the contrast, make the lights lighter and the darks darker.
Fortunately, all you need to do is bump up the contrast of the sketch
layer -- and you can do that while keeping the orange Screen layer in
Just click on the sketch layer in the Layers dialog, then run
This sketch needed the brightness reduced a lot, plus a little more
contrast, but every image will be different. Experiment!
[ 18:22 Mar 07, 2015
More gimp |
permalink to this entry |
Thu, 06 Nov 2014
The split between Save and Export that GIMP introduced in version 2.8
has been a matter of much controversy. It's been over two years now,
and people are still complaining on the gimp-users list.
Early on, I wrote a simple Python plug-in called
Clean, which saved over an image's current save or export filename
regardless of whether the filename was XCF (save) or a different format
(export). The idea was that you could bind Ctrl-S to the plug-in and
not be pestered by needing to remember whether it was XCF, JPG or what.
Save-Export Clean has been widely cited, and I hope it's helped some
people who were bothered by the Save/Export split. But personally I
didn't like it very much. It wasn't very flexible -- there was no
way to change the filename, for one thing, and it was awfully easy
to overwrite an original image without knowing that you'd done it.
I went back to using GIMP's separate Save and Export, but in the
back of my mind I was turning over ideas, trying to understand
my workflow and what I really wanted out of a GIMP Save plug-in.
The result of that was a new Python plug-in called Saver.
I first wrote it a year ago, but I've been tweaking it and using it
since then, with Ctrl-S bound to Saverand Ctrl-Shift-S bound to
I wanted to make sure that it was useful and working reliably ...
and somehow I never got around to writing it
up and announcing it formally ... until now.
Saver, like Save/Export Clean, will overwrite your chosen filename,
whether XCF or another format, and will mark the image as saved so
GIMP won't pester you when you exit.
What's different? Mainly, three things:
- A Saver as... option so you can change the filename
or file type.
- Merges multiple layers so they'll show up properly in your
JPG or PNG image.
- An option to save as .xcf or .xcf.gz and, at the same time, export
a copy in another format, possibly scaled down. So you can maintain
your multi-layer XCF image but also update the JPG copy that you're
going to put on the web.
I've been using Saver for nearly all my saving for the past year.
If I'm just making a quick edit of a JPEG camera image, Ctrl-S
overwrites it without questioning me. If I'm editing an elaborate
multi-layer GIMP project, Ctrl-S overwrites the .xcf.gz. If I'm
planning to export that image for the web, I Ctrl-Shift-S to bring
up the Saver As... dialog, make sure the main filename is
.xcf.gz, set a name (ending in .jpg) for the exported copy; and
from then on, Ctrl-S will save both the XCF and the JPG copy.
Saver is available on my github page, with installation instructions here:
GIMP Saver and
Save/Export Clean Plug-ins. I hope you find it useful.
[ 12:57 Nov 06, 2014
More gimp |
permalink to this entry |
Fri, 13 Sep 2013
Someone on the gimp-developers list asked whether there was
documentation of GIMP's menu hooks.
I wasn't sure what they meant by "hooks", but GIMP menus do have
an interesting feature that plug-in writers should know about:
Placeholders let you group similar types of actions together.
For instance, iever notice that in the image window's File menu,
all the things that Open images are grouped together? There's Open,
Open as Layers..., Open Location... and Open Recent. And then
there's a group of Save actions all grouped together -- Save, Save
As..., Save a Copy... and so forth. That's because there's a
placeholder for Open in the File menu, and another placeholder
When you write your own plug-ins, you can take advantage of these
placeholders. For instance, I want my Save/Export clean plug-in to
show up next to the other Save menu items, not somewhere else down
near the bottom of the menu -- so when I register it, I pass
menu = "<Image>/File/Save/" so GIMP knows to group
it with the other Save actions, even though it's directly in the File
menu, not a submenu called Save..
Pretty slick, huh? But how do you know what placeholders are available?
I took a look at the source.
In the menus/ subdirectory are all the menu definitions in XML,
and they're pretty straightforward.
In image-menu.xml you'll see things like
<placeholder name="Open">, <placeholder name="Save">
So to get a list of all the menu placeholders, you just need to
find all the "
grep '<placeholder' menus/*.xml
That's not actually so useful, though, because it doesn't tell you
what submenu contains the placeholder. For instance, Acquire is a
placeholder but you need to know that it's actually
File->Create->Acquire. So let's be a little more clever.
We want to see <menu lines as well as <placeholders,
but not <menuitem since those are just individual menu entries.
egrep '<(placeholder|menu) will do that.
Then pass it through some sed expressions to clean up the output,
loop over all the XML files, and I ended up with:
for f in *.xml; do
egrep '<(placeholder|menu) ' $f | sed -e 's_<placeholder *name="_** _' -e 's_<menu.*name="__' -e 's_"/*>__'
It isn't perfect: a few lines still show up that
shouldn't -- but it'll get you the list you need. Fortunately the
GIMP developers are very good about things like code formatting,
so the identation of the file shows
which placeholder is inside which submenu.
I only found placeholders in the image window menu, plus a single
placeholder, "Outline", in the selection menu popup.
I'm a little confused about that menu file: it seems to duplicate
the existing Select menu in the image-menu.xml, except that
the placeholder items in question -- feather, sharpen, shrink, grow,
and border -- are in a placeholder called Outline in
selection-menu.xml, but in a placeholder called Modify
Anyway, here's the full list of placeholders, cleaned up for readability.
Placeholders are in bold and followed with an asterisk *.
===== image-menu.xml =====
Color Profile *
Light and Shadow
Recently Closed Docks
===== selection-menu.xml =====
[ 19:06 Sep 13, 2013
More gimp |
permalink to this entry |
Wed, 27 Feb 2013
I was printing out a map for a new trail we wanted to hike.
I wanted to fill the paper with the map -- Google maps' print and
Firefox's print, while fine for most map printing, weren't what I wanted.
So I took a screenshot of the maximized browser window with the map in it
and imported it into GIMP. In the Crop tool, I constrained Aspect-ratio
to 11:8.5 and cropped the image so it would just fit on a page, in
landscape format -- wider in east-west than in north-south.
Then I chose File->Print.
Since printing defaults to Portrait orientation,
I went to the Page Setup tab and changed Orientation to Landscape.
(It's so nice to have that as part of the dialog. I'm forever amazed
at how some apps, like Firefox, make you use a separate dialog first
to change the print's orientation.
How can anyone possibly see that as sensible UI design?)
Unfortunately, When I went to the Image Settings tab to check ,
I discovered that GIMP hadn't adjusted the image size when I changed
to Landscape. It had Width listed as 8.500, Height as 6.567, and the
image only took up part of the page.
I went to the Width field and replaced 8.500 with 11, and hit
Tab. Whoops! The field reverted to 8.500. The same thing happened
if I tried typing 8.5 into the Height field.
These fields aren't plain text entries -- they're "spin boxes", with
a text entry plus up and down arrows.
It turned out that under GIMP 2.8 and earlier, round-off errors sometimes
prevent you from setting a spin box's maximum value. I could type 10.999
and it would work fine, but 11 or 11.0 failed.
Of course, 10.999 would have been fine -- I don't mind a little margin
on a printed map. It's also trivial in GIMP to rotate a landscape photo
90 degrees and print it in portrait orientation. But by this point
I was into stubborn mode -- by gosh, I wanted a way to fix this!
The best workaround, it turns out, is to use the spin box's up-arrow.
Holding the mouse down over the up arrow will eventually get to the
maximum value. But there's a faster way: right-clicking
on the up-arrow goes straight to the maximum value. A nice trick!
The problem doesn't exist in GIMP 2.9 -- I reported it as
and the awesome GIMP team fixed it very quickly.
The spin boxes work beautifully now. (Thanks, Mitch!)
But as long as 2.8 is around, or for any other app using spin boxes,
I'm glad to know about right-clicking on the spin box arrows.
[ 12:26 Feb 27, 2013
More gimp |
permalink to this entry |
Sun, 02 Sep 2012
In a discussion on Google+arising from my
clean plug-in, someone said to the world in general
PLEASE provide an option to select the size of the export. Having to
scale the XCF then export then throw out the result without saving is
I thought, What a good idea! Suppose you're editing a large image, with
layers and text and other jazz, saving in GIMP's native XCF format,
but you want to export a smaller version for the web. Every time you
make a significant change, you have to: Scale (remembering the scale
size or percentage you're targeting);
Save a Copy (or Export in GIMP 2.8);
then Undo the Scale.
If you forget the Undo, you're in deep trouble and might end up
overwriting the XCF original with a scaled-down version.
If I had a plug-in that would export to another file type (such
as JPG) with a scale factor, remembering that scale factor
so I didn't have to, it would save me both effort and risk.
And that sounded pretty easy to write,
using some of the tricks I'd learned from my Save/Export Clean
So I wrote export-scaled.py
It's still brand new, so if anyone tries it, I'd appreciate knowing
if it's useful or if you have any problems with it.
Geeky programming commentary
(Folks not interested in the programming details can stop reading now.)
Linked input fields
One fun project was writing a set of linked text entries for the dialog:
|Scale to: ||Percentage 100 %
||Width: 640 ||Height: 480
Change any one of the three, and the other two change automatically.
There's no chain link between width and height:
It's assumed that if you're exporting a scaled copy, you won't want
to change the image's aspect ratio, so any one of the three is enough.
That turned out to be surprisingly hard to do with GTK SpinBoxes:
I had to read their values as strings and parse them,
because the numeric values kept snapping back
to their original values as soon as focus went to another field.
Another fun challenge was how to save the scale ratio, so the second
time you call up the plug-in on the same image it uses whatever values
you used the first time. If you're going to scale to 50%, you don't
want to have to type that in every time. And of course, you want it
to remember the exported file path, so you don't have to navigate
there every time.
For that, I used GIMP parasites: little arbitrary pieces of data you
can attach to any image. I've known about parasites for a long time,
but I'd never had occasion to use them in a Python plug-in before.
I was pleased to find that they were documented in the
Python documentation, and they worked just as documented.
It was easy to test them, too: in the Python console
(Filters->Python->Console...), type something like
img = gimp_image_list()
and so forth. Nice!
Not prompting for JPG settings
My plug-in was almost done. But when I ran it and told it to save to
filenamecopy.jpg, it prompted me with that annoying JPEG
Okay, being prompted once isn't so bad. But then
when I exported a second time, it prompted me again,
and didn't remember the values from before.
So the question was, what controls whether the settings dialog is
shown, and how could I prevent it?
Of course, I could prompt the user for JPEG quality, then call
jpeg-save-file directly -- but what if you want to export to PNG
or GIF or some other format? I needed something more general
Turns out, nobody really remembers how this works, and it's not
documented anywhere. Some people thought that passing
run_mode=RUN_WITH_LAST_VALS when I called
pdb.gimp_file_save() would do the trick, but it didn't help.
So I guessed that there might be a parasite that was storing those
settings: if the JPEG save plug-in sees the parasite, it uses those
values and doesn't prompt. Using the Python console technique I just
mentioned, I tried checking the parasites on a newly created image
and on an image read in from an existing JPG file, then saving each
one as JPG and checking the parasite list afterward.
Bingo! When you read in a JPG file, it has a parasite called
'jpeg-settings'. (The new image doesn't have this, naturally).
But after you write a file to JPG from within GIMP, it has not
only 'jpeg-settings' but also a second parasite, 'jpeg-save-options'.
So I made the plug-in check the scaled image after saving it,
looking for any parasites with names ending in either
-save-options; any such parasites are copied to the
original image. Then, the next time you invoke Export Scaled, it does
the same search, and copies those parasites to the scaled image before
That darned invisible JPG settings dialog
One niggling annoyance remained.
The first time you get the JPG settings dialog, it
pops up invisibly, under the Export dialog you're using. So if
you didn't know to look for it by moving the dialog, you'd think the
plug-in had frozen. GIMP 2.6 had a bug where that happened every time
I saved, so I assumed there was nothing I can do about it.
GIMP 2.8 has fixed that bug -- yet it still happened
when my plug-in called gimp_file_save: the JPG dialog popped
up under the currently active dialog, at least under Openbox.
There isn't any way to pass window IDs through gimp_file_save so
the JPG dialog pops up as transient to a particular window. But a few
days after I wrote the export-scaled, I realized there was still
something I could do: hide the dialog when the user clicks Save.
Then make sure that I show it again if any errors occur during saving.
Of course, it wasn't quite that simple. Calling
by itself does nothing, because X is asynchronous and things don't happen
in any predictable order. But it's possible to force X to sync the display:
I'm not sure how robust this is going to be -- but it seems to work well
in the testing I've done so far, and it's really nice to get that huge
GTK file chooser dialog out of the way as soon as possible.
[ 18:34 Sep 02, 2012
More gimp |
permalink to this entry |
Tue, 21 Aug 2012
In GIMP 2.8, the developers changed the way you save files. "Save" is
now used only for GIMP's native format, XCF (and compressed variants
like .xcf.gz and .xcf.bz2). Other formats that may lose information on
layers, fonts and other aspects of the edited image must be "Exported"
rather than saved.
This has caused much consternation and flameage on the gimp-user
mailing list, especially from people who use GIMP primarily for
simple edits to JPEG or PNG files.
I don't particularly like the new model myself. Sometimes I use GIMP
in the way the developers are encouraging, adding dozens of layers,
fonts, layer masks and other effects. Much more often, I use GIMP
to crop and rescale a handful of JPG photos I took with my camera on a hike.
While I found it easy enough to adapt to using
Ctrl-E (Export) instead of Ctrl-S (Save), it was annoying that when I
exited the app, I'd always get am "Unsaved images" warning, and it was
impossible to tell from the warning dialog which images were safely
exported and which might not have been saved or exported at all.
But flaming on the mailing lists, much as some people seem to enjoy it
(500 messages on the subject and still counting!)
wasn't the answer. The developers have stated very clearly that they're
not going to change the model back. So is there another solution?
Yes -- a very simple solution, in fact. Write a plug-in that saves or
exports the current image back to its current file name, then marks it
as clean so GIMP won't warn about it when you quit.
It turned out to be extremely easy to write, and you can get it here:
clean plug-in. If it suits your GIMP workflow, you can even
bind it to Ctrl-S ... or any other key you like.
Warning: I deliberately did not add any "Are you sure you want
to overwrite?" confirmation dialogs. This plug-in will overwrite
your current file, without asking for permission. After all, that's its
job. So be aware of that.
How it's written
Here are some details about how it works.
Non software geeks can skip the rest of this article.
When I first looked into writing this, I was amazed at how simple it was:
really just two lines of Python (plus the usual plug-in registration
pdb.gimp_file_save(img, drawable, img.filename, img.filename)
The first line saves the image back to its current filename.
(The gimp-file-save PDB call still handles all types, not just XCF.)
The second line marks the image as clean.
Both of those are PDB calls, which means that people who don't have
GIMP Python could write script-fu to do this part.
So why didn't I use script-fu? Because I quickly found that if I bound
the plug-in to Ctrl-S, I'd want to use it for new images -- images that
don't have a filename yet. And for that, you need to pop up some sort
of "Save as" dialog -- something Python can do easily, and Script-fu
can't do at all.
A Save-as dialog with smart directory default
I couldn't use the
standard GIMP save-as dialog: as far as I can tell, there's
no way to call that dialog from a plug-in.
But it turned out the GTK save-as dialog has no default directory to
start in: you have to set the starting directory every time. So I
needed a reasonable initial directory.
I didn't want to come up with some desktop twaddle like ~/My Pictures
or whatever -- is there really anyone that model fits? Certainly not me.
I debated maintaining a preference you could set, or saving the last
used directory as a preference, but that complicates things and I
wasn't sure it's really that helpful for most people anyway.
So I thought about where I usually want to save images in a GIMP session.
Usually, I want to save them to the same directory where I've been saving
other images in the same session, right?
I can figure that out by looping through all currently open images
for img in gimp.image_list() : and checking
os.path.dirname(img.filename) for each one.
Keep track of how many times each directory is being used;
whichever is used the most times is probably where the user wants
to store the next image.
Keeping count in Python
Looping through is easy, but what's the cleanest, most Pythonic way
of maintaining the count for each directory and finding the most
popular one? Naturally, Python has a class for that,
Once I've counted everything, I can ask for the most common path.
The code looks a bit complicated because
most_common(1) returns a one-item list of a tuple of the single
most common path and the number of times it's been used -- for instance,
[ ('/home/akkana/public_html/images/birds', 5) ].
So the path is the first element of the first element, or
most_common(1). Put it together:
counts = collections.Counter()
for img in gimp.image_list() :
if img.filename :
counts[os.path.dirname(img.filename)] += 1
So that's the only tricky part of this plug-in.
The rest is straightforward, and you can read the code on
[ 12:26 Aug 21, 2012
More gimp |
permalink to this entry |