Shallow Thoughts : tags : gimp

Akkana's Musings on Open Source Computing and Technology, Science, and Nature.

Tue, 23 Jul 2019

360 Panoramas with Povray and/or ImageMagick

This is Part IV of a four-part article on ray tracing digital elevation model (DEM) data. The goal: render a ray-traced image of mountains from a digital elevation model (DEM).

Except there are actually several more parts on the way, related to using GRASS to make viewsheds. So maybe this is actually a five- or six-parter. We'll see.

The Easy Solution

Skipping to the chase here ... I had a whole long article written about how to make a sequence of images with povray, each pointing in a different direction, and then stitch them together with ImageMagick.

But a few days after I'd gotten it all working, I realized none of it was needed for this project, because ... ta-DA — povray accepts this argument inside its camera section:

    angle 360

Duh! That makes it so easy.

You do need to change povray's projection to cylindrical; the default is "perspective" which warps the images. If you set your look_at to point due south -- the first and second coordinates are the same as your observer coordinate, the third being zero so it's looking southward -- then povray will create a lovely strip starting at 0 degrees bearing (due north), and with south right in the middle. The camera section I ended up with was:

camera {
    cylinder 1

    location <0.344444, 0.029620, 0.519048>
    look_at  <0.344444, 0.029620, 0>

    angle 360
with the same light_source and height_field as in Part III.

[360 povray panorama from Overlook Point]

There are still some more steps I'd like to do. For instance, fitting names of peaks to that 360-degree pan.

The rest of this article discusses some of the techniques I would have used, which might be useful in other circumstances.

A Script to Spin the Observer Around

Angles on a globe aren't as easy as just adding 45 degrees to the bearing angle each time. You need some spherical trigonometry to make the angles even, and it depends on the observer's coordinates.

Obviously, this wasn't something I wanted to calculate by hand, so I wrote a script for it: Run it with the name of a DEM file and the observer's coordinates: demfile.png 35.827 -106.1803
It takes care of calculating the observer's elevation, normalizing to the image size and all that. It generates eight files, named outfileN.png, outfileNE.png etc.

Stitching Panoramas with ImageMagick

To stitch those demproj images manually in ImageMagick, this should work in theory:

convert -size 3600x600 xc:black \
    outfile000.png -geometry +0+0 -composite \
    outfile045.png -geometry +400+0 -composite \
    outfile090.png -geometry +800+0 -composite \
    outfile135.png -geometry +1200+0 -composite \
    outfile180.png -geometry +1600+0 -composite \
    outfile225.png -geometry +2000+0 -composite \
    outfile270.png -geometry +2400+0 -composite \
    outfile315.png -geometry +2800+0 -composite \
or simply
convert outfile*.png +smush -400 out-smush.png

Adjusting Panoramas in GIMP

But in practice, some of the images have a few-pixel offset, and I never did figure out why; maybe it's a rounding error in my angle calculations.

I opened the images as layers in GIMP, and used my GIMP script Pandora/ to lay them out as a panorama. The cylindrical projection should make the edges match perfectly, so you can turn off the layer masking.

Then use the Move tool to adjust for the slight errors (tip: when the Move tool is active, the arrow keys will move the current layer by a single pixel).

If you get the offsets perfect and want to know what they are so you can use them in ImageMagick or another program, use GIMP's Filters->Python-Fu->Console. This assumes the panorama image is the only one loaded in GIMP, otherwise you'll have to inspect gimp.image_list() to see where in the list your image is.

>>> img = gimp.image_list()[0]
>>> for layer in img.layers:
...     print, layer.offsets

Tags: , , , ,
[ 15:28 Jul 23, 2019    More mapping | permalink to this entry | ]

Tue, 05 Jul 2016

GIMP at Texas LinuxFest

I'll be at Texas LinuxFest in Austin, Texas this weekend. Friday, July 8 is the big day for open source imaging: first a morning Photo Walk led by Pat David, from 9-11, after which Pat, an active GIMP contributor and the driving force behind the PIXLS.US website and discussion forums, gives a talk on "Open Source Photography Tools". Then after lunch I'll give a GIMP tutorial. We may also have a Graphics Hackathon/Q&A session to discuss all the open-source graphics tools in the last slot of the day, but that part is still tentative. I'm hoping we can get some good discussion especially among the people who go on the photo walk.

Lots of interesting looking talks on Saturday, too. I've never been to Texas LinuxFest before: it's a short conference, just two days, but they're packing a lot into those two days and but it looks like it'll be a lot of fun.

Tags: , ,
[ 18:37 Jul 05, 2016    More conferences | permalink to this entry | ]

Fri, 19 Feb 2016

GIMP ditty: change font size and face on every text layer

A silly little GIMP ditty:
I had a Google map page showing locations of lots of metal recycling places in Albuquerque. The Google map shows stars for each location, but to find out the name and location of each address, you have to mouse over each star. I wanted a printable version to carry in the car with me.

I made a screenshot in GIMP, then added text for the stars over the places that looked most promising. But I was doing this quickly, and as I added text for more locations, I realized that it was getting crowded and I wished I'd used a smaller font. How do you change the font size for ALL font layers in an image, all at once?

Of course GIMP has no built-in method for this -- it's not something that comes up very often, and there's no reason it would have a filter like that. But the GIMP PDB (Procedural DataBase, part of the GIMP API) lets you change font size and face, so it's an easy script to write.

In the past I would have written something like this in script-fu, but now that Python is available on all GIMP platforms, there's no reason not to use it for everything.

Changing font face is just as easy as changing size, so I added that as well.

I won't bother to break it down line by line, since it's so simple. Here's the script: Mass change font face and size in all GIMP text layers.

Tags: , ,
[ 11:11 Feb 19, 2016    More gimp | permalink to this entry | ]

Wed, 06 Jan 2016

Speaking at SCALE 14x

I'm working on my GIMP talk for SCALE 14x, the Southern California Linux Expo in Pasadena.

[GIMP] My talk is at 11:30 on Saturday, January 23: Stupid GIMP tricks (and smart ones, too).

I'm sure anyone reading my blog knows that GIMP is the GNU Image Manipulation Program, the free open-source photo and image editing program which just celebrated its 20th birthday last month. I'll be covering an assortment of tips and tricks for beginning and intermediate GIMP users, and I'll also give a quick preview of some new and cool features that will be coming in the next GIMP release, 2.10.

I haven't finished assembling the final talk yet -- if you have any suggestions for things you'd love to see in a GIMP talk, let me know. No guarantees, but if I get any requests I'll try to accommodate them.

Come to SCALE! I've spoken at SCALE several times in the past, and it's a great conference -- plenty of meaty technical talks, but it's also the most newbie-friendly conference I've been to, with talks spanning the spectrum from introductions to setting up Linux or introductory Python programming all the way to kernel configuration and embedded boot systems. This year, there's also an extensive "Ubucon" for Ubuntu users, including a keynote by Mark Shuttleworth. And speaking of keynotes, the main conference has great ones: Cory Doctorow on Friday and Sarah Sharp on Sunday, with Saturday's keynote yet to be announced.

In the past, SCALE been held at hotels near LAX, which is about the ugliest possible part of LA. I'm excited that the conference moving to Pasadena this year: Pasadena is a much more congenial place to be, prettier, closer to good restaurants, and it's even close to public transportation.

And best of all, SCALE is fairly inexpensive compared to most conferences. Even more so if you use the promo-code SPEAK for a discount when registering.

Tags: , , , ,
[ 16:32 Jan 06, 2016    More conferences | permalink to this entry | ]

Fri, 04 Dec 2015

Distclean part 2: some useful zsh tricks

I wrote recently about a zsh shell function to run make distclean on a source tree even if something in autoconf is messed up. In order to save any arguments you've previously passed to configure or, my function parsed the arguments from a file called config.log.

But it might be a bit more reliable to use config.status -- I'm guessing this is the file that make uses when it finds it needs to re-run However, the syntax in that file is more complicated, and parsing it taught me some useful zsh tricks.

I can see the relevant line from config.status like this:

$ grep '^ac_cs_config' config.status
ac_cs_config="'--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'"

--enable-foo --disable-bar are options I added purely for testing. I wanted to make sure my shell function would work with multiple arguments.

Ultimately, I want my shell function to call --prefix=/usr/local/gimp-git --enable-foo --disable-bar The goal is to end up with $args being a zsh array containing those three arguments. So I'll need to edit out those quotes and split the line into an array.

Sed tricks

The first thing to do is to get rid of that initial ac_cs_config= in the line from config.status. That's easy with sed:

$ grep '^ac_cs_config' config.status | sed -e 's/ac_cs_config=//'
"'--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'"

But since we're using sed anyway, there's no need to use grep to get the line: we can do it all with sed. First try:

sed -n '/^ac_cs_config/s/ac_cs_config=//p' config.status

Search for the line that starts with ac_cs_config (^ matches the beginning of a line); then replace ac_cs_config= with nothing, and p print the resulting line. -n tells sed not to print anything except when told to with a p.

But it turns out that if you give a sed substitution a blank pattern, it uses the last pattern it was given. So a more compact version, using the search pattern ^ac_cs_config, is:

sed -n '/^ac_cs_config=/s///p' config.status

But there's also another way of doing it:

sed '/^ac_cs_config=/!d;s///' config.status

! after a search pattern matches every line that doesn't match the pattern. d deletes those lines. Then for lines that weren't deleted (the one line that does match), do the substitution. Since there's no -n, sed will print all lines that weren't deleted.

I find that version more difficult to read. But I'm including it because it's useful to know how to chain several commands in sed, and how to use ! to search for lines that don't match a pattern.

You can also use sed to eliminate the double quotes:

sed '/^ac_cs_config=/!d;s///;s/"//g' config.status
'--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'
But it turns out that zsh has a better way of doing that.

Zsh parameter substitution

I'm still relatively new to zsh, but I got some great advice on #zsh. The first suggestion:

sed -n '/^ac_cs_config=/s///p' config.status | IFS= read -r; args=( ${(Q)${(z)${(Q)REPLY}}} ); print -rl - $args

I'll be using final print -rl - $args for all these examples: it prints an array variable with one member per line. For the actual distclean function, of course, I'll be passing the variable to, not printing it out.

First, let's look at the heart of that expression: the args=( ${(Q)${(z)${(Q)REPLY}}}.

The heart of this is the expression ${(Q)${(z)${(Q)x}}} The zsh parameter substitution syntax is a bit arcane, but each of the parenthesized letters does some operation on the variable that follows.

The first (Q) strips off a level of quoting. So:

$ x='"Hello world"'; print $x; print ${(Q)x}
"Hello world"
Hello world

(z) splits an expression and stores it in an array. But to see that, we have to use print -l, so array members will be printed on separate lines.

$ x="a b c"; print -l $x; print "....."; print -l ${(z)x}
a b c

Zsh is smart about quotes, so if you have quoted expressions it will group them correctly when assigning array members:

x="'a a' 'b b' 'c c'"; print -l $x; print "....."; print -l ${(z)x} 'a a' 'b b' 'c c' ..... 'a a' 'b b' 'c c'

So let's break down the larger expression: this is best read from right to left, inner expressions to outer.

${(Q) ${(z) ${(Q) x }}}
   |     |     |   \
   |     |     |    The original expression, 
   |     |     |   "'--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'"
   |     |     \
   |     |      Strip off the double quotes:
   |     |      '--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'
   |     \
   |      Split into an array of three items
    Strip the single quotes from each array member,
    ( --prefix=/usr/local/gimp-git --enable-foo --disable-bar )

For more on zsh parameter substitutions, see the Zsh Guide, Chapter 5: Substitutions.

Passing the sed results to the parameter substitution

There's still a little left to wonder about in our expression, sed -n '/^ac_cs_config=/s///p' config.status | IFS= read -r; args=( ${(Q)${(z)${(Q)REPLY}}} ); print -rl - $args

The IFS= read -r seems to be a common idiom in zsh scripting. It takes standard input and assigns it to the variable $REPLY. IFS is the input field separator: you can split variables into words by spaces, newlines, semicolons or any other character you want. IFS= sets it to nothing. But because the input expression -- "'--prefix=/usr/local/gimp-git' '--enable-foo' '--disable-bar'" -- has quotes around it, IFS is ignored anyway.

So you can do the same thing with this simpler expression, to assign the quoted expression to the variable $x. I'll declare it a local variable: that makes no difference when testing it in the shell, but if I call it in a function, I won't have variables like $x and $args cluttering up my shell afterward.

local x=$(sed -n '/^ac_cs_config=/s///p' config.status); local args=( ${(Q)${(z)${(Q)x}}} ); print -rl - $args

That works in the version of zsh I'm running here, 5.1.1. But I've been warned that it's safer to quote the result of $(). Without quotes, if you ever run the function in an older zsh, $x might end up being set only to the first word of the expression. Second, it's a good idea to put "local" in front of the variable; that way, $x won't end up being set once you've returned from the function. So now we have:

local x="$(sed -n '/^ac_cs_config=/s///p' config.status)"; local args=( ${(Q)${(z)${(Q)x}}} ); print -rl - $args

You don't even need to use a local variable. For added brevity (making the function even more difficult to read! -- but we're way past the point of easy readability), you could say:

args=( ${(Q)${(z)${(Q)"$(sed -n '/^ac_cs_config=/s///p' config.status)"}}} ); print -rl - $args
or even
print -rl - ${(Q)${(z)${(Q)"$(sed -n '/^ac_cs_config=/s///p' config.status)"}}}
... but that final version, since it doesn't assign to a variable at all, isn't useful for the function I'm writing.

Tags: , , , ,
[ 13:25 Dec 04, 2015    More linux/cmdline | permalink to this entry | ]

Fri, 27 Nov 2015

Getting around make clean or make distclean aclocal failures

Keeping up with source trees for open source projects, it often happens that you pull the latest source, type make, and get an error like this (edited for brevity):

$ make
cd . && /bin/sh ./missing --run aclocal-1.14
missing: line 52: aclocal-1.14: command not found
WARNING: aclocal-1.14' is missing on your system. You should only need it if you modified acinclude.m4' or'. You might want to install the Automake' and Perl' packages. Grab them from any GNU archive site.

What's happening is that make is set up to run ./ (similar to running ./configure except it does some other stuff tailored to people who build from the most current source tree) automatically if anything has changed in the tree. But if the version of aclocal has changed since the last time you ran or configure, then running configure with the same arguments won't work.

Often, running a make distclean, to clean out all local configuration in your tree and start from scratch, will fix the problem. A simpler make clean might even be enough. But when you try it, you get the same aclocal error.

Whoops! make clean runs make, which triggers the rule that configure has to run before make, which fails.

It would be nice if the make rules were smart enough to notice this and not require configure or autogen if the make target is something simple like clean or distclean. Alas, in most projects, they aren't.

But it turns out that even if you can't run with your usual arguments -- e.g. ./ --prefix=/usr/local/gimp-git -- running ./ by itself with no extra arguments will often fix the problem.

This happens to me often enough with the GIMP source tree that I made a shell alias for it:

alias distclean="./ && ./configure && make clean"

Saving your configure arguments

Of course, this wipes out any arguments you've previously passed to autogen and configure. So assuming this succeeds, your very next action should be to run autogen again with the arguments you actually want to use, e.g.:

./ --prefix=/usr/local/gimp-git

Before you ran the distclean, you could get those arguments by looking at the first few lines of config.log. But after you've run distclean, config.log is gone -- what if you forgot to save the arguments first? Or what if you just forget that you need to re-run again after your distclean?

To guard against that, I wrote a somewhat more complicated shell function to use instead of the simple alias I listed above.

The first trick is to get the arguments you previously passed to configure. You can parse them out of config.log:

$ egrep '^  \$ ./configure' config.log
  $ ./configure --prefix=/usr/local/gimp-git --enable-foo --disable-bar

Adding a bit of sed to strip off the beginning of the command, you could save the previously used arguments like this:

    args=$(egrep '^  \$ ./configure' config.log | sed 's_^  \$ ./configure __')

(There's a better place for getting those arguments, config.status -- but parsing them from there is a bit more complicated, so I'll follow up with a separate article on that, chock-full of zsh goodness.)

So here's the distclean shell function, written for zsh:

distclean() {
    setopt localoptions errreturn

    args=$(egrep '^  \$ ./configure' config.log | sed 's_^  \$ ./configure __')
    echo "Saved args:" $args
    make clean

    echo "==========================="
    echo "Running ./ $args"
    sleep 3
    ./ $args

The setopt localoptions errreturn at the beginning is a zsh-ism that tells the shell to exit if there's an error. You don't want to forge ahead and run configure and make clean if your didn't work right. errreturn does much the same thing as the && between the commands in the simpler shell alias above, but with cleaner syntax.

If you're using bash, you could string all the commands on one line instead, with && between them, something like this: ./ && ./configure && make clean && ./ $args Or perhaps some bash user will tell me of a better way.

Tags: , , ,
[ 13:33 Nov 27, 2015    More programming | permalink to this entry | ]

Thu, 22 Oct 2015

Non-free software can mean unexpected surprises

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 live demo.

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.

Tags: , , ,
[ 10:24 Oct 22, 2015    More gimp | permalink to this entry | ]

Sun, 04 Oct 2015

Aligning images to make an animation (or an image stack)

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.

[Upper layer 50% opaque to align two layers]

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

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. View->Display Filters... and in the dialog that pops up, click on Contrast, and click on the right arrow to move it to Active Filters.

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

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 SimpleCV, 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.

So I threw together a Javascript script to animate images by loading 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 How to save different layers of a design in separate files; though a couple of others looked promising (I didn't try them), such as gimp-plugin-export-layers and save_all_layers.scm.

You can see the final animation here: Lunar eclipse of September 27, 2015: Animations.

Tags: , ,
[ 09:44 Oct 04, 2015    More gimp | permalink to this entry | ]

Thu, 01 Oct 2015

Lunar eclipse animations

[Eclipsed moon rising] The lunar eclipse on Sunday was gorgeous. The moon rose already in eclipse, and was high in the sky by the time totality turned the moon a nice satisfying deep red.

I took my usual slipshod approach to astrophotography. I had my 90mm f/5.6 Maksutov lens set up on the patio with the camera attached, and I made a shot whenever it seemed like things had changed significantly, adjusting the exposure if the review image looked like it might be under- or overexposed, occasionally attempting to refocus. The rest of the time I spent socializing with friends, trading views through other telescopes and binoculars, and enjoying an apple tart a la mode.

So the images I ended up with aren't all they could be -- not as sharply focused as I'd like (I never have figured out a good way of focusing the Rebel on astronomy images) and rather grainy.

Still, I took enough images to be able to put together a couple of animations: one of the lovely moonrise over the mountains, and one of the sequence of the eclipse through totality.

Since the 90mm Mak was on a fixed tripod, the moon drifted through the field and I had to adjust it periodically as it drifted out. So the main trick to making animations was aligning all the moon images. I haven't found an automated way of doing that, alas, but I did come up with some useful GIMP techniques, which I'm in the process of writing up as a tutorial.

Once I got the images all aligned as layers in a GIMP image, I saved them as an animated GIF -- and immediately discovered that the color error you get when converting to an indexed GIF image loses all the beauty of those red colors. Ick!

So instead, I wrote a little Javascript animation function that loads images one by one at fixed intervals. That worked a lot better than the GIF animation, plus it lets me add a Start/Stop button.

You can view the animations (or the source for the javascript animation function) here: Lunar eclipse animations

Tags: , , ,
[ 12:55 Oct 01, 2015    More science/astro | permalink to this entry | ]

Sun, 27 Sep 2015

Make a series of contrasting colors with Python

[PyTopo with contrasting color track logs] Every now and then I need to create a series of contrasting colors. For instance, in my mapping app PyTopo, when displaying several track logs at once, I want them to be different colors so it's easy to tell which track is which.

Of course, I could make a list of five or ten different colors and cycle through the list. But I hate doing work that a computer could do for me.

Choosing random RGB (red, green and blue) values for the colors, though, doesn't work so well. Sometimes you end up getting two similar colors together. Other times, you get colors that just don't work well, because they're so light they look white, or so dark they look black, or so unsaturated they look like shades of grey.

What does work well is converting to the HSV color space: hue, saturation and value. Hue is a measure of the color -- that it's red, or blue, or yellow green, or orangeish, or a reddish purple. Saturation measures how intense the color is: is it a bright, vivid red or a washed-out red? Value tells you how light or dark it is: is it so pale it's almost white, so dark it's almost black, or somewhere in between? (A similar model, called HSL, substitutes Lightness for Value, but is similar enough in concept.)

[GIMP color chooser] If you're not familiar with HSV, you can get a good feel for it by playing with GIMP's color chooser (which pops up when you click the black Foreground or white Background color swatch in GIMP's toolbox). The vertical rainbow bar selects Hue. Once you have a hue, dragging up or down in the square changes Saturation; dragging right or left changes Value. You can also change one at a time by dragging the H, S or V sliders at the upper right of the dialog.

Why does this matter? Because once you've chosen a saturation and value, or at least ensured that saturation is fairly high and value is somewhere in the middle of its range, you can cycle through hues and be assured that you'll get colors that are fairly different each time. If you had a red last time, this time it'll be a green, or yellow, or blue, depending on how much you change the hue.

How does this work programmatically?

PyTopo uses Python-GTK, so I need a function that takes a gtk.gdk.Color and chooses a new, contrasting Color. Fortunately, gtk.gdk.Color already has hue, saturation and value built in. Color.hue is a floating-point number between 0 and 1, so I just have to choose how much to jump. Like this:

def contrasting_color(color):
    '''Returns a gtk.gdk.Color of similar saturation and value
       to the color passed in, but a contrasting hue.
       gtk.gdk.Color objects have a hue between 0 and 1.
    if not color:
        return self.first_track_color;

    # How much to jump in hue:
    jump = .37

    return gtk.gdk.color_from_hsv(color.hue + jump,

What if you're not using Python-GTK?

No problem. The first time I used this technique, I was generating Javascript code for a company's analytics web page. Python's colorsys module works fine for converting red, green, blue triples to HSV (or a variety of other colorspaces) which you can then use in whatever graphics package you prefer.

Tags: , ,
[ 13:27 Sep 27, 2015    More programming | permalink to this entry | ]

Sat, 07 Mar 2015

GIMP: Turn black to another color with Screen mode

[20x20 icon, magnified 8 times] 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.

[Bucket fill doesn't work for this] 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:

[Make a new layer] In the Layers dialog, click the New Layer button and accept the defaults. You'll get a new, empty layer.

[Set the foreground color] Set the foreground color to your chosen color.

[Set the foreground color] Drag the foreground color into the image, or do Edit->Fill with FG Color.

Now it looks like your whole image is the new color. But don't panic!

[Use screen mode] 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

[Mars sketch, colorized orange] 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.

[Colorized Mars sketch, enhanced  with brightness/contrast] 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 place.

Just click on the sketch layer in the Layers dialog, then run Colors->Brightness/Contrast...

This sketch needed the brightness reduced a lot, plus a little more contrast, but every image will be different. Experiment!

Tags: ,
[ 18:22 Mar 07, 2015    More gimp | permalink to this entry | ]

Thu, 06 Nov 2014

New GIMP Save/Export plug-in: Saver

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 Save-Export 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.

[Screenshot: GIMP Saver-as... 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 Saver as...). 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:

  1. A Saver as... option so you can change the filename or file type.
  2. Merges multiple layers so they'll show up properly in your JPG or PNG image.
  3. 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

GIMP menu placeholders

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.

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 for Save.

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
  echo $f
  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 in image-menu.xml.

Anyway, here's the full list of placeholders, cleaned up for readability. Placeholders are in bold and followed with an asterisk *.

===== image-menu.xml =====
        Acquire *
      Open *
      Open Recent
        Files *
      Save *
      Export *
      Send *
      Info *
      Undo *
      Cut *
      Copy *
      Paste *
      Paste as
      Clear *
      Fill *
      Stroke *
      Preferences *
      Modify *
      New *
        Color Profile *
        Flip *
        Rotate *
      Resize *
      Scale *
      Crop *
      Structure *
      Arrange *
      New *
      Structure *
      Text *
        Select *
        Position *
        Modify *
        Properties *
        Selection *
        Modify *
        Selection *
        Flip *
        Rotate *
        Layer Mode
      Resize *
      Scale *
      Crop *
      Invert *
        Colormap *
      Modify *
      Recently Used
        Plug-Ins *
        Motion *
      Light and Shadow
        Light *
        Shadow *
        Glass *
        Animators *
      Menus *
      Languages *
      Extensions *
    Menus *
      Recently Closed Docks
      Dockable Dialogs
      Images *
      Docks *
      Programming *

===== selection-menu.xml =====
    Outline *

Tags: ,
[ 19:06 Sep 13, 2013    More gimp | permalink to this entry | ]

Wed, 27 Feb 2013

Printing in Landscape orientation in GIMP (and some spinbutton tips)

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.

[GIMP printing dialog] 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 bug 694477, 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.

Tags: ,
[ 12:26 Feb 27, 2013    More gimp | permalink to this entry | ]

Sun, 02 Sep 2012

GIMP plug-in to export scaled-down versions of images

In a discussion on Google+arising from my Save/Export 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 really awkward.

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 and wallpaper scripts. So I wrote

Update: Please consider using Saver instead. Saver integrates the various functions I used to have in different save/export plug-ins; it should do everything does and more, and is no longer maintained. If you need something does that saver doesn't do as well, please let me know.

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

[screenshot: 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.

Image parasites

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 official GIMP 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()[0]
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 settings dialog. 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 -settings or -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 calling gimp-file-save.

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 chooser.hide() 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: chooser.get_display().sync().

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.

Tags: , ,
[ 18:34 Sep 02, 2012    More gimp | permalink to this entry | ]

Tue, 21 Aug 2012

GIMP: Re-uniting Save and Export

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: GIMP: Save/export 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 boilerplate).

    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 with 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, collections.Counter.

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)[0][0]. Put it together:

    counts = collections.Counter()
    for img in gimp.image_list() :
        if img.filename :
            counts[os.path.dirname(img.filename)] += 1
    try :
        return counts.most_common(1)[0][0]
    except :
        return None

So that's the only tricky part of this plug-in. The rest is straightforward, and you can read the code on GitHub:

Tags: , ,
[ 12:26 Aug 21, 2012    More gimp | permalink to this entry | ]

Tue, 07 Jun 2011

Make your own Saturn sketching template with GIMP

My SJAA Ephemeris planetary astronomy column for next month will discuss Saturn, among other topics, since Saturn is the main planet visible in the evening sky right now.

Saturn has some storms visible right now in the north polar and equatorial bands, and a great way to focus your attention to see more detail through a telescope, especially on subtle details like Saturnian storms, is to take pencil and paper and sketch what you see. I've recommended sketching in my column many times before, but don't talk about it on the blog very often.

When sketching Saturn, it helps to start with a template, so you can concentrate on the interesting details of the rings and bands rather than fussing over trying to get the exact width of the rings right. Saturn's tilt changes with time -- right now it's tilted at 8° to observers here on Earth -- so sometimes the rings are open wide, sometimes they're narrow, and sometimes (as last year) they're edge-on and invisible to us. That's a hassle to try to get right in a sketch, when you'd rather be focusing on the gaps in the rings and the pastel colors of the cloud bands on the planet.

ALPO, the Association of Lunar and Planetary Observers, makes templates for sketching Saturn; but I had trouble finding any online that showed a tilt appropriate for this month's Saturn. You can get observing materials by joining ALPO, but sheesh! you shouldn't have to join an organization just to get a simple sketching template. And I wanted one for my column. Besides, the ALPO templates fill in too much detail -- they don't really give you a chance to do your own ring sketch.

So here's an easy way to make a Saturn sketching template with GIMP.

[Saturn sketch template]

Start with an image

You can calculate the aspect ratio you need for the planet from the ring tilt, but why go to all that trouble? I started with an image of Saturn I got by running XEphem. Call up View->Saturn, then make the window as big as you can. Of course, you may substitute any planetarium program of your choosing, as long as it shows Saturn with the right ring tilt.

I used GIMP's screenshot facility to open this as an image: File->Create->Screenshot..., then Select a region to grab.

You can also use a recent photo of Saturn. The point here is to get something that's the right shape: it doesn't matter if it's beautiful or large.

Fix the rotation and size

You want the rings horizontal, if they're not already. Use GIMP's Free Rotate tool to do that. You can eyeball it to make it approximately right, or if you want to be more accurate, use the Measure tool (the icon looks like a drawing compass) to measure from one edge of the rings to the other and note the angle in the status bar at the bottom of the window. Then when you use Free Rotate, type in the number you measured.

You'll be printing this out on sketching paper, so if the original image is small, use Image->Scale to expand it. Remember, you won't be looking at this original image -- it's just for tracing -- so don't worry if the image comes out fuzzy after you scale it up. I made mine about 1000 pixels wide.

Make a white background layer

Layer->New Layer... to make a new layer; check "white" in the dialog. Then click the eyeball icon next to it in the Layers dialog to make it invisible. You'll want it later.

Outline the planet on its own layer

Layer->New Layer... to make a new layer; this time make it transparent, not white. I named mine "planet", since this is where I'll draw the ellipse for the planet. (Yes, Saturn is an ellipse, not a sphere. So is the Earth, for that matter, but Saturn is a lot less spherical than Earth is.)

Choose the ellipse selection tool and drag out a selection that matches the outer edges of the planet. Use the resize handles to adjust the selection until it fits as closely as you can manage.

In the Toolbox or the Brushes dialog, choose the smallest hard brush, "Circle (01)".

Then Edit->Stroke Selection.... Click "Stroke with a paint tool", and click Stroke.

Tip: You may notice my template ended up with very jaggy lines. That's a common artifact of GIMP's Stroke Selection. I'm not worried about it for a sketching template, but if the jaggies bother you, you can get a much smoother line by converting the selection to a path and stroking the path instead of the selection.

Preview your work so far

Go back to the Layers dialog and make that white layer visible again, so you can see the outline you just made. You may want to do Select->None and click on some tool other than ellipse select, so the selection outline disappears and you can see the line better.

If you're not happy with your planet outline, Edit->Undo and repeat with a different selection, a thicker line or whatever.

Outline the rings on their own layer

Repeat what you just did for the planet, this time for the rings. I recommend using a new layer for just the rings (you'll see why in the next step).

I outlined just the outside of the rings, so the sketch can show the ring thickness. ALPO's templates don't do this, but how much ring you can see can vary based on seeing conditions. If you want the inner edge of the ring on your template, add it now.

Erase the hidden parts of the ring and planet outlines

You can't see the rings where they go behind the planet, or the part of the planet hidden by the rings. And you don't want your template lines spoiling your sketch in those regions. So use GIMP's eraser tool and a large brush to erase the appropriate parts.

This is a little easier if you used separate layers for the rings and planet: you won't have to be as careful with the eraser. But it's not a big deal: this is a template, not a finished artwork, and you're going to be drawing over it anyway. So don't sweat it too much.

Optionally, make the lines fainter

I made the template lines fainter using the Opacity slider in the Layers dialog on the planet and ring layers. Of course, you can just draw in grey in the first place, but I like being able to decide afterward what color I want, or change it later.

Label the template

Trust me, you'll be really annoyed if you decide in 2026 that you want to make another Saturn sketch, find your old template but can't remember what ring tilt it's for. So use the Text tool to label either the current date or the approximate ring tilt. Or put that information in an image comment under Image->Image Properties..., or in the filename.

Save your template as XCF.gz, save a copy in some other format like jpg, png or gif, and you're ready to print templates on paper. Then go out and sketch Saturn!

Tags: , ,
[ 15:13 Jun 07, 2011    More science/astro | permalink to this entry | ]

Wed, 13 Apr 2011

GIMP: Build-it

Are you a GIMP user or Summer of Code student who's been wanting to get involved, but having trouble building, or a bit intimidated by the build process?

I'll be running a session on IRC to help anyone build GIMP on Linux, as part of the OpenHatch "Build it" project.

The session will take place on #gimp on (also known as GimpNet), on Fri, Apr 15, 0300 UTC -- that's Thursday night in the Americas. To convert to your time zone, run this command on your local machine:

$ date -d 'Fri Apr 15 03:00 UTC'
Thu Apr 14 20:00:00 PDT 2011
Or try this link: world time server.

This is a time that's usually fairly quiet on #gimp -- European users don't fret, since it's pretty easy to get help there during more Europe-friendly time zones. I'll hang around for at least two hours; that should be plenty of time to build GIMP and all its prerequisites.

For folks new to IRC, note that is its own server -- this is not the #gimp channel on Freenode. You can learn more about IRC on the LinuxChix IRC for Beginners page, or, if you have trouble getting an IRC client configured, try this link for mibbit web chat.

Note: The #gimp IRC channel was recently under attack by trolls, and it's possible that it may not be usable at the time of the session. In that case, I will update this blog page with the name of an alternate channel to use, and any other necessarily details.


If you want to get your system set up ahead of time, I've put the instructions needed to build on Ubuntu Lucid and other older Linux distros here: Gimp Building Tips (for Linux). I might be able to offer a little help with building on Macs, but no guarantees.

Mac and Windows users, or people running a very old Linux distro (more than a year old) might want to consider an alternate approach: install Virtualbox or VMware and install Ubuntu "Natty Narwhal" (currently still in beta) in a virtual machine.

Of course, this isn't the only time you can get help with building GIMP. There are folks around on #gimp most of the time who are happy to help with problems. But if you've been meaning to get started and want a good excuse, or you've been holding off on asking for help ... come hang out with us and try it!

Tags: , ,
[ 12:50 Apr 13, 2011    More gimp | permalink to this entry | ]

Sat, 19 Feb 2011

GIMP: Don't get confused by the Auto button

A couple of people recently have appeared on GIMP IRC channels wondering why no filters or layer operations seemed to work in GIMP, even though they had an image open.

In at least one case, it was a setting most of us had forgotten about: the Auto button. It's easy to miss, but if you turn it on accidentally, you may be unable to do anything in GIMP until you realize what's happened. [Normal layers dialog, auto]

The Auto button is the one at the upper right of your Layers dialog. It's on by default, and what it does is ensure that dialogs like Layers, and GIMP's notion of the currently active layer, follow the active image. Open a new image, or click in a different image window, and your Layers dialog switches images -- so whatever you do next will apply to the image you just chose. [Layers dialog with Auto off]

If you turn Auto off, then by default, no image and no layer is active. Notice, in the screenshot at left, how no image is shown in the option menu just left of the Auto button.

Even if you open a new image, you can't do anything with it until you explicitly choose an image from the menu.

I'm sure you can see why this could be confusing. So why have that button at all?

Well, it's useful when you're working with lots of images -- for instance, if you want to drag a layer from one image into another image, you can use the menu to switch quickly among images and layers without needing to bring those image windows to the front. I don't find I need it, but for those who do, I guess it can be a real time-saver.
[that pesky GIMP Auto menu]

Just to make it even more confusing, not everyone even has the Auto button or the menu next to it. You can turn it off (and gain a little extra vertical space for your layers dialog) with the tiny menu button right above the mode menu. "Show Image Selection" controls whether the image option menu, and the Auto button next to it, will be displayed. "Auto Follow Active Image" is the same toggle as the Auto button itself.

So if you ever get stuck and the Layers dialog doesn't seem to be showing layers from your image, and you can't figure out why ... remember that pesky Auto button. It might just be the problem.

(If not, try quitting GIMP and moving your profile aside. That works for curing all manner of mysterious ills -- including this one. Come to think of it, that deserves an article of its own. Coming soon!)

Tags: ,
[ 11:04 Feb 19, 2011    More gimp | permalink to this entry | ]

Fri, 18 Feb 2011

New GIMP Arrow Designer

[arrow] While writing a blog post on GIMP's confusing Auto button (to be posted soon), I needed some arrows, and discovered a bug in my Arrow Designer script when making arrows that are mostly vertical.

So I fixed it. You can get the new Arrow Designer 0.5 on my GIMP Arrow Designer page.

It's purely a coincidence that I discovered this a week before SCALE, where I'll be speaking on Writing GIMP Scripts and Plug-Ins. Arrow Designer is one of my showpieces for making interactive plug-ins with GIMP-Python, so I'm glad I noticed the bug when I did.

Tags: , ,
[ 21:28 Feb 18, 2011    More gimp | permalink to this entry | ]

Sat, 25 Dec 2010

Happy Holidays to All!

[Happy holidays with a shroom] Happy holidays to everyone! Merry Christmas, if you celebrate it, and if you don't -- just go ahead and be merry anyway, okay?

Tags: ,
[ 17:18 Dec 25, 2010    More misc | permalink to this entry | ]

Thu, 23 Dec 2010

Editing Batches of Photos with GIMP and David's Batch Processor

[David's Batch Processor]

Have a lot of images to edit, but confused by command-line tools like ImageMagick? Try David's Batch Processor, a GIMP plug-in that lets you apply multiple operations like resize, rotate, or brightness/contrast to groups of photos.

The article is on Linux Planet: Editing Batches of Photos Easily on Linux.

Tags: ,
[ 11:07 Dec 23, 2010    More gimp | permalink to this entry | ]

Mon, 15 Nov 2010

More advanced GIMP tricks for cutting parts out of photos

[Butterfly in space, screenshot]

My previous Linux Planet article covered beginner tips for cutting foreground objects out of photographs. Part 2, from last week, covers some more flexible advanced techniques you'll want to use as your GIMP skills increase.

Find out how to put a butterfly in space!

Read it here: More GIMP tricks for cutting objects of photos

Tags: ,
[ 15:14 Nov 15, 2010    More gimp | permalink to this entry | ]

Thu, 28 Oct 2010

GIMP tricks for isolating parts of photos

[GIMP screenshot] Today's Linux Planet article covers some basic tips for how to cut a foreground object out of a photograph, so you can grab that penguin or flower or motorcycle and paste it somewhere else.

Read it here: GIMP tricks for isolating parts of photos

This is mostly beginner stuff, for people who haven't done this at all. Part II, in two weeks, will cover more advanced techniques.

Tags: ,
[ 15:37 Oct 28, 2010    More gimp | permalink to this entry | ]

Sun, 26 Sep 2010

GIMP Wallpaper script improvements

Dave was using some old vacation photos to test filesystem performance, and that made me realize that I had beautiful photos from the same trip that I hadn't yet turned into desktop backgrounds.

Sometimes I think that my GIMP Wallpaper script is the most useful of the GIMP plug-ins I've written. It's such a simple thing ... but I bet I use it more than any of my other plug-ins, and since I normally make backgrounds for at least two resolutions (my 1680x1050 desktop and my 1366x768 laptop), it certainly saves me a lot of time and hassle.

But an hour into my background-making, I started to have nagging doubts. I wasn't renaming these images, just keeping the original filenames from the camera, like pict0828.jpg. What if if some of these were overwriting images of the same name? The one thing my script doesn't do is check for that, and gimp_file_save doesn't pop up any warnings. I've always meant to add a check for it.

Of course, once the doubts started, I had to stop generating backgrounds and start generating code. And I'm happy with the result: warns and won't let you save over an old background image, but keeps all the logic in one dialog rather than popping up extra warnings.

[ overwrite warning dialog]

Now I can generate backgrounds without worrying that I'm stomping on earlier ones.

Tags: , ,
[ 22:25 Sep 26, 2010    More gimp | permalink to this entry | ]

Thu, 29 Jul 2010

How to save on modeling fees

[Terrible's ad] At the Terrible's Sands Regency in Reno, Dave noticed this ad on the table in the room. "Wait -- isn't that the same guy, twice?"

Sure enough -- not just the same person, but the same photo, with different hair and neck pixeled in.

I guess Photoshop/GIMP artists are cheaper than photo models these days.

We spotted the same model in other ads around the hotel, sometimes masquerading as other races as well.

Tags: , ,
[ 17:28 Jul 29, 2010    More gimp | permalink to this entry | ]

Sat, 10 Jul 2010

Interactive arrow design in GIMP

How many times have you wanted an easy way of making arrows in GIMP?

I need arrows all the time, for screenshots and diagrams. And there really isn't any easy way to do that in GIMP. There's a script-fu for making arrows in the Plug-in registry, but it's fiddly and always takes quite a few iterations to get it right. More often, I use a collection of arrow brushes I downloaded from somewhere -- I can't remember exactly where I got my collection, but there are lots of options if you google gimp arrow brushes -- then use the free rotate tool to rotate the arrow in the right direction.

[GIMP Arrow Designer] The topic of arrows came up again on #gimp yesterday, and Alexia Death mentioned her script-fu in GIMP Fx Foundary that "abuses the selection" to make shapes, like stars and polygons. She suggested that it would be easy to make arrows the same way, using the current selection as a guide to where the arrow should go.

And that got me thinking about Joao Bueno's neat Python plug-in demo that watches the size of the selection and updates a dialog every time the selection changes. Why not write an interactive Python script that monitors the selection and lets you change the arrow by changing the size of the selection, while fine-tuning the shape and size of the arrowhead interactively via a dialog?

Of course I had to write it. And it works great! I wish I'd written this five years ago.

This will also make a great demo for my OSCON 2010 talk on Writing GIMP Scripts and Plug-ins, Thursday July 22. I wish I'd had it for Libre Graphics Meeting last month.

It's here: GIMP Arrow Designer.

Tags: , , ,
[ 11:25 Jul 10, 2010    More gimp | permalink to this entry | ]

Thu, 10 Jun 2010

GIMP 3-D, 3 Ways

I'm back from Europe (and still recovering from a cold picked up right after I got back). And today I have a GIMP quickie on Linux Planet discussing three ways to add three-dimensional looks to otherwise flat images in GIMP:

GIMP 3-D, 3 Ways.

Tags: ,
[ 10:36 Jun 10, 2010    More gimp | permalink to this entry | ]

Sun, 14 Mar 2010

Finally -- Tapered lines in GIMP! How to make them (in 2.7).

[grass brush example] So many times I've wanted a way to make tapered lines in GIMP. It doesn't come up that often, but when it does, it's frustrating that it's so difficult.

For instance, when I was working on the animated brush section of Beginning GIMP, I wanted to make a brush that looked like grass, because that's something I've found quite difficult to do by hand in GIMP. But to make each blade of grass, I ended up drawing a green line of fixed width, zoom way in, then using the lasso selection tool to select and clear the edges of the end of each stroke. What a pain!

[tapered lines in GIMP] Imagine my excitement when I saw GIMP developer Alexia Death talking about how she'd added taper to GIMP's Paint Dynamics in the development version of GIMP. I had to try it.

But I needed some help figuring out how to do it, and I know I'll forget; so I wrote up a tutorial, both for myself and to help anyone else who needs tapered lines.

Alas, this feature is brand new and only works in recent development builds. But if you aren't that current with GIMP, it's something to look forward to. I'll keep this tutorial updated in case methods change.

GIMP Tutorial: Tapered lines

Tags: ,
[ 20:26 Mar 14, 2010    More gimp | permalink to this entry | ]

Wed, 23 Dec 2009

Fixing holiday photos with GIMP

Third in my GIMP-for-the-holidays series on Linux Planet: Fixing holiday photos with GIMP

Happy holidays, everybody ... and happy holiday photos!

Tags: , ,
[ 19:44 Dec 23, 2009    More gimp | permalink to this entry | ]

Thu, 17 Dec 2009

Print your custom-made greeting cards

[Sample greeting card] A followup to last week's article on making custom greeting cards with GIMP, today's Linux Planet tutorial discusses how to get those cards printed -- even if you don't own a decent color printer.

On Linux Planet: Printing Holiday Cards Even if you Don't Have a Printer.

Tags: , ,
[ 19:50 Dec 17, 2009    More gimp | permalink to this entry | ]

Thu, 10 Dec 2009

GIMP Tutorial: Make your own holiday greeting cards

[Sample greeting card] Today's Linux Planet tutorial is a simple walkthrough showing you how to make custom greeting cards in GIMP:

Make Your Own Holiday Cards with GIMP.

Have fun!

Part 2, next week, will offer tips on printing, whether on a home inkjet or using other services.

Tags: ,
[ 15:19 Dec 10, 2009    More gimp | permalink to this entry | ]

Tue, 15 Sep 2009

GTK dialogs in GIMP (and updated wallpaper script)

[Grosvenor Arch] I've been getting tired of my various desktop backgrounds, and realized that I had a lot of trip photos, from fabulous places like Grosvenor Arch (at right), that I'd never added to my background collection.

There's nothing like lots of repetitions of the same task to bring out the shortcomings of a script, and the wallpaper script I threw together earlier this year was no exception. I found myself frequently irritated by not having enough information about what the script was doing or being able to change the filename. Then I could have backgrounds named grosvenor.jpg rather than img2691.jpg.

Alas, I can't use the normal GIMP Save-as dialog, since GIMP doesn't make that dialog available to plug-ins. (That's a deliberate choice, though I've never been clear on the reason behind it.) If I wanted to give that control to the user, I'd have to make my own dialogs.

It's no problem to make a GTK dialog from Python. Just create a gtk.Dialog, add a gtk.Entry to it, call, then check the return value and get the entry's text to see if it changed. No problem, right?

Ha! If you think that, you don't work with computers. The dialog popped up fine, it read the text entry fine ... but it wouldn't go away afterward. So after the user clicked OK, the plug-in tried to save and GIMP popped up the JPEG save dialog (the one that has a quality slider and other controls, but no indication of filename) under my text entry dialog, which remained there.

All attempts at calling dialog.hide() and dialog.destroy() and similar mathods were of no avail. A helpful person on #pygtk worked with me but ended up as baffled as I was. What was up?

The code seemed so simple -- something like this:

    response =
    if response == gtk.RESPONSE_OK :
        pathname = pathentry.get_text()
        pdb.gimp_file_save(newimg, newimg.active_layer, pathname, pathname,

In the end, GIMP guru Sven pointed me to the answer. The problem was that my dialog wasn't part of the GTK main loop. In retrospect, this makes sense: the plug-in is an entirely different process, so I shouldn't be surprised that it would have its own main loop. So when I hide() and destroy(), those events don't happen right away because there's no loop in the plug-in process that would see them.

The plug-in passes control back to GIMP to do the gimp_file_save(). GIMP's main loop doesn't have access to the hide and destroy signals I just sent. So the gimp_file_save runs, popping up its own dialog (under mine, because the JPEG save dialog is transient to the original image window while my python dialog isn't). That finishes, returns control to the plug-in, the plug-in exits and at that point GTK cleans up and finally destroys the dialog.

The solution is to loop over GTK events in the plug-in before calling gimp_file_save, like this:

    response =
    if response == gtk.RESPONSE_OK :
        pathname = pathentry.get_text()
        while gtk.events_pending() :
        pdb.gimp_file_save(newimg, newimg.active_layer, pathname, pathname,

That loop gives the Python process a chance to clean up the dialog before passing control to GIMP and its main loop. GTK in the subprocess is happy, the user is happy, and I'm happy because now I have a much more efficient way of making lots of desktop backgrounds for lots of different machines.

The updated script, along with a lot more information on how to use it and how to set up tool presets for it.

Tags: , ,
[ 23:21 Sep 15, 2009    More gimp | permalink to this entry | ]

Thu, 23 Apr 2009

Linux Planet: GIMP Python Plugins, part II

Latest Linux Planet article: How to write a "blobify" GIMP plug-in in Python to make text look three-dimensional.

Creating a Fancy 3D-Effect GIMP Plugin in Python.

Tags: , ,
[ 11:46 Apr 23, 2009    More writing | permalink to this entry | ]

Thu, 09 Apr 2009

Linux Planet: Writing Plugins for GIMP in Python

Latest Linux Planet article: Part 1 of a two-parter on Writing GIMP scripts in Python. As usual, there's a Digg link too.

Tags: , ,
[ 22:21 Apr 09, 2009    More writing | permalink to this entry | ]

Thu, 05 Feb 2009

Use GIMP Tool Presets for setting multiple crop aspect ratios

Making desktop backgrounds in GIMP is a bit tedious if you have several machines with screens of different sizes. The workflow goes something like this:

First, choose Crop tool and turn on Fixed: Aspect Ratio. Then loop over images:

  1. Load an image
  2. Go to Tool Options
  3. Type in the aspect ratio: 4:3, 8:5, 5:4, 1366:768 etc.
  4. Go to the image and crop.
  5. Image->Scale (I have this on Shift-S, can't remember whether that was a default binding or not).
  6. Ctrl-K to delete the current width (Ctrl-U also works, but beeps; I'm not sure why)
  7. Type in the desired width (1024 or 1680 or 1366 or whatever) (I always hit Tab here, though it's probably not necessary)
  8. Click Scale or type Alt-S (unfortunately, Return doesn't work in this dialog).
  9. Save As to the appropriate name and path for the current resolution
  10. Undo (the Scale), Undo (the Crop)
  11. Load a new image (continue loop)

But you can use Save Options (Tool Presets) to avoid step 3, typing in the aspect ratio. Here's how:

Repeat, for each aspect ratio you might want to use.

Now clicking on Restore Options gives you a menu of all your commonly used aspect ratios -- much faster than typing them in every time. Too bad there's no way to use this shortcut for the Scale step, or to do Crop and Scale in one operation.

Nice shortcut! But having done that, I realized I could shorten it even more: I could make a selection (not a crop) with one of my preset aspect ratios, then run a script that would figure out from the aspect ratio which absolute size I wanted, crop and scale, and either save it to the right place, or make a new image so I could save without needing to Redo or Save a Copy. That was an easy script to write, so here it is:

Tags: , , ,
[ 23:45 Feb 05, 2009    More gimp | permalink to this entry | ]

Sun, 16 Nov 2008

Cleaning up the edges of Moonroot's transparent images

[moonroot] I wrote moonroot more to figure out how to do it than to run it myself. But on the new monitor I have so much screen real estate that I've started using it -- but the quality of the images was such an embarrassment that I couldn't stand it. So I took a few minutes and cleaned up the images and made a moonroot 0.6 release.

Turned out there was a trick I'd missed when I originally made the images, years ago. XPM apparently only allows 1-bit transparency. When I was editing the RGB image and removing the outside edge of the circle, some of the pixels ended up semi-transparent, and when I saved the file as .xpm, they ended up looking very different (much darker) from what I had edited.

Here are two ways to solve that in GIMP:

  1. Use the "Hard edge" option on the eraser tool (and a hard-edged brush, of course, not a fuzzy one).
  2. Convert the image to indexed, in which case GIMP will only allow one bit's worth of transparency. (That doesn't help for full-color images, but for a greyscale image like the moon, there's no loss of color since even RGB images can only have 8 bits per channel.)

Either way, the way to edit a transparent image where you're trying to make the edges look clean is to add a solid-color background layer (I usually use white, but of course it depends on how you're going to use the image) underneath the layer you're trying to edit. (In the layers dialog, click the New button, chose White for the new layer, click the down-arrow button to move it below the original layer, then click on the original layer so your editing will all happen there.)

Once you're editing a circle with sharp edges, you'll probably need to adjust the colors for some of the edge pixels too. Unfortunately the Smudge tool doesn't seem to work on indexed images, so you'll probably spend a lot of time alternating between the Color Picker and the Pencil tool, picking pixel colors then dabbing them onto other pixels. Key bindings are the best way to do that: o activates the Color Picker, N the Pencil, P the Paintbrush. Even if you don't normally use those shortcuts it's worth learning them for the duration of this sort of operation.

Or use the Clone tool, where the only keyboard shortcut you have to remember is Ctrl to pick a new source pixel. (I didn't think of that until I was already finished, but it works fine.)

Tags: , ,
[ 15:48 Nov 16, 2008    More gimp | permalink to this entry | ]

Fri, 14 Nov 2008

Great Advertising

Usually I just delete spam after seeing the subject line. But I couldn't resist one that arrived this morning:
Subject: You'll be saying WOW every time with ShamWow

Wondering whether the seller was familiar with the meaning of the word "sham", I just had to take a look.

[ Funny shamWOW ad ] I couldn't tell anything from the text -- it was all just random verbiage to try to fool Baysian filters. But the mail also attached two images, img001.png and img002.png. The first was a big grey starburst thing; the second, at 348Kb, was the actual ad (click on it to get the full-sized version; the thumbnail here doesn't do it justice).

There are just so many things to love about this ad, starting with the name "ShamWow" itself. I love the mixture of fonts and bright colors, with the slightly lopsided hourglass shape of the ShamWow! logo. I love the "AS SEEN ON TV" bug -- a charming image that hasn't changed a whit since the 60's, maybe even the 50's. I love the unidentifiable grey and yellow flat things with unreadable text on them -- they look like file folders and folded papers, but they're probably two different colors and sizes of ShamWow -- covered with a square announcing "10 Year [unreadable]", which made me wonder if they were selling auto loans or securities. But if you magnify it you find that the third word is probably "Warranty". I love the presumption that you'll think that 20x the weight of a small cloth object is a lot of water (is it? I have no idea, let me grab a paper towel and a gram scale). I love the blurry red and white "CLICK FOR DETAILS" button.

But what I like best about this image is that it's a PNG but it's full of JPG artifacts. Now, I'm not very picky about jpeg artifacts. (You'd think I would be, as a de-facto GIMP expert, but I'm really not.) I shoot DSLR photos in jpeg rather than raw mode because most of the time the difference just isn't enough for me to care about. I use jpeg for most of the icons on my web site if they don't need transparency, and I lower the jpeg quality level to make them load faster. I'm not a PNG snob (actually, I'm more likely to use GIF than PNG for web icons). But really -- this ad image is a wonderful example of jpeg artifacts and why you can't just turn the quality down arbitrarily far.

I could even understand using extreme jpeg compression because they were sending out a hundred quotillion spam messages and wanted to reduce bandwidth. But they're not sending a jpeg -- they've converted the low-quality JPG back to a 348Kb PNG before sending the spam.

All I can figure is that someone designed the ad and saved it as JPG, making it really small. And then someone in the business saw lbrandy's great cartoon on JPG vs. PNG -- and said "Oh, no! We'd better use PNG instead! And loaded up the JPG and saved it as a PNG with default settings.

(For further reading on PNG vs. JPEG and image file size optimization, you can get an overview of formats at my Image Formats for the Web and some detailed tutorials at the Bandwidth Conservation Society; or chapters 2 and 8 in my GIMP book, soon to be out in its second edition.)

Tags: , ,
[ 11:54 Nov 14, 2008    More humor | permalink to this entry | ]

Fri, 31 Oct 2008

GIMP Drag-n-Drop and Open Location without gvfs

Quite a while ago I noticed that drag-n-drop of images from Firefox had stopped working for me in GIMP's trunk builds (2.6 and 2.7); it failed with a "file not found" error. Opening URIs with Open Location also failed in the same way.

Since I don't run a gnome desktop, I assumed it probably had something to do with requiring gnome-vfs services that I don't have. But yesterday I finally got some time to chase it down with help from various folk on #gimp.

I had libgnomevfs (and its associated dev package) installed on my Ubuntu Hardy machine, but I didn't have gvfs. It was suggested that I install the gfvs-backends package. I tried that, but it didn't help; apparently gvfs requires not just libgvfs and gvfs-backends, but also running a new daemon, gvfsd. Finding an alternative was starting to sound appealing.

Turns out gimp now has three compile-time configure options related to opening URIs:

  --without-gvfs          build without GIO/GVfs support
  --without-gnomevfs      build without gnomevfs support
  --without-libcurl       build without curl support

These correspond to four URI-getting methods in the source, in plug-ins/file-uri:

GIMP can degrade from gvfs to gnomevfs to libcurl to wget, but only at compile time, not at runtime: only one of the four is built.

On my desktop machine, --without-gvfs was all I needed. Even without running the gnome desktop, the gnomevfs front-end seems to work fine. But it's good to know about the other options too, in case I need to make a non-gnomevfs version to run on the laptop or other lightweight machines.

Tags: , , ,
[ 12:09 Oct 31, 2008    More gimp | permalink to this entry | ]

Sat, 16 Aug 2008

Fast Pixel Ops in GIMP-Python

Last night Joao and I were on IRC helping someone who was learning to write gimp plug-ins. We got to talking about pixel operations and how to do them in Python. I offered my as an example of using pixel regions in gimp, but added that C is a lot faster for pixel operations. I wondered if reading directly from the tiles (then writing to a pixel region) might be faster.

But Joao knew a still faster way. As I understand it, one major reason Python is slow at pixel region operations compared to a C plug-in is that Python only writes to the region one pixel at a time, while C can write batches of pixels by row, column, etc. But it turns out you can grab a whole pixel region into a Python array, manipulate it as an array then write the whole array back to the region. He thought this would probably be quite a bit faster than writing to the pixel region for every pixel.

He showed me how to change the code to use arrays, and I tried it on a few test layers. Was it faster? I made a test I knew would take a long time in arclayer, a line of text about 1500 pixels wide. Tested it in the old arclayer; it took just over a minute to calculate the arc. Then I tried Joao's array version: timing with my wristwatch stopwatch, I call it about 1.7 seconds. Wow! That might be faster than the C version.

The updated, fast version (0.3) of is on my arclayer page.

If you just want the trick to using arrays, here it is:

from array import array

[ ... setting up ... ]
        # initialize the regions and get their contents into arrays:
        srcRgn = layer.get_pixel_rgn(0, 0, srcWidth, srcHeight,
                                     False, False)
        src_pixels = array("B", srcRgn[0:srcWidth, 0:srcHeight])

        dstRgn = destDrawable.get_pixel_rgn(0, 0, newWidth, newHeight,
                                            True, True)
        p_size = len(srcRgn[0,0])               
        dest_pixels = array("B", "\x00" * (newWidth * newHeight * p_size))

[ ... then inside the loop over x and y ... ]
                        src_pos = (x + srcWidth * y) * p_size
                        dest_pos = (newx + newWidth * newy) * p_size
                        newval = src_pixels[src_pos: src_pos + p_size]
                        dest_pixels[dest_pos : dest_pos + p_size] = newval

[ ... when the loop is all finished ... ]
        # Copy the whole array back to the pixel region:
        dstRgn[0:newWidth, 0:newHeight] = dest_pixels.tostring() 

Good stuff!

Tags: , , ,
[ 22:02 Aug 16, 2008    More gimp | permalink to this entry | ]

Sat, 12 Apr 2008

GIMP for middle school kids

I've been helping out with an extracurricular GIMP class that a local Linux and free software advocate, Christian Einfeldt, has organized at a middle school in San Francisco.

The class meets on a Saturday once or twice a month, so there's plenty of time to forget things between sessions, and most of the kids don't have a lot of prior computer experience (I'm told many of them are behavior problems or otherwise "at risk", but I sure wouldn't have guessed that from their exemplary behavior in class.) Despite the obstacles, the kids have learned some impressive image editing skills in a very short time! Lots of them have figured out how to set their Edubuntu desktop background; I've seen abstract patterns, photographs decorated in various ways (today one girl was painting a mouth, hair and jewelry on a photograph of a chimpanzee's face, and it came out looking very funny), photos of the students themselves pasted into exotic locales, and so on.

It's also an interesting exercise for me in seeing what beginning users find difficult to understand and what aspects of GIMP's user interface are difficult to explain. An additional challenge is that this classroom has no projector or centrally visible screen. So you can't just demonstrate how something works; everything must be explained slowly in words while the students follow along with each step, and then we have to go through the room helping students as they try to remember the steps.

One of the first tasks they take on is combining images: start with a photo of themselves, or of an animal or car, select it and paste it into another image. What's the easiest way of explaining selection of arbitrary shapes? Which method can be explained in less than a minute, and yet they'll remember how to do it after you leave and move on to the next student?

There are three obvious candidates for a general-purpose selection tool: the intelligent scissors, the paths tool, and the quickmask. We had a miscommunication in one of the early classes and didn't discuss which technique to teach, so I taught some students the paths tool while Christian was teaching others the iscissors. I found that both methods had some serious problems.

With Bezier paths, it's easy to click points around your object. Students get a little flustered the first few times they accidentally drag rather than click and drag handles appear, but they can get over that. The part that's difficult comes at the end, where they have to click Path to Selection, then Feather as a separate step (they don't need to feather the first time, but eventually they'll need it). And then there's the problem that the path as well as the selection remains visible, a distraction that they don't understand.

When I saw that Christian had been teaching some students the iscissors while I was teaching others paths, I thought, gee, good idea. Iscissors should be more straightforward, no? Well, no, as it turns out. New students have great difficulty making an iscissors selection. They're fine as long as they're clicking their points; the problem comes when they get to the last point, when in order to make a selection you must click carefully on your first point, then click again inside the figure. A lot of students don't understand this no matter how many times you explain: they don't remember which was their first point (it doesn't look any different from the others), they can't see it anyway (it usually doesn't contrast much with the image), and they can't tell whether they clicked it successfully.

At that point they try to click inside the image and get a spurious extra point -- and then they panic and start clicking all over the place, ending up with a mess that is (as far as I've been able to tell) unrecoverable. The only fix is to toss out that figure and start over, but even that isn't easy to do (click on another tool then back on the iscissors tool button). Basically, the iscissors tool is far too confusing and most students need to be personally walked through it at least three times (some of them a lot more than that) before they get it.

Anyone who's read my writing on GIMP probably knows that I'm a quickmask zealot. I'm a born again quickmask prophet: I used GIMP for years without really understanding the quickmask, and when I finally grokked it, it made a huge difference in ease of selection. I sometimes joke that "the quickmask changed my life", and that's hyperbole, or course; but it sure did change my GIMP editing. People seem to fear the quickmask so I usually don't present it first, but maybe I should. These students are very eager and competent at painting, and I think they'd take to the quickmask very easily with far fewer stumbles than the other two methods have given them.

There's one other variant of shaped selection that I didn't list: the lasso tool in add and subtract mode. The lasso tool is terrifically hard to use to try to select a whole figure from an image. You'd have to have a preternaturally steady hand, plus you can't zoom in and scroll around since the whole figure has to be completed in one movement. But what you can do is make a rough selection with the lasso, understanding that you'll have some errors; then alternate between Add mode and Subtract mode as you use the lasso on smaller areas to get the selection just right. It's nearly as easy as the quickmask, and doesn't require a big conceptual shift. The only reason I'm leery is that I suspect the three modes would confuse a lot of students -- especially since the mode buttons have no labels, merely tooltips.

While I'm on the topic, there's another issue that gives the students trouble besides selection: the floating selection that results from a paste. There's really no way to explain to a schoolkid why it's there (heck, maybe some day someone will explain that to me). And it's useless to try to get them to keep their Layers dialogs visible. (They don't even keep the toolbox visible most of the time; it's always covered by image windows. Most of these Edubuntu machines are working at 800x600 resolution, and there just isn't room on the screen for the normal GIMP window collection.)

So I try to drill them that "Every time you paste, you have to find the Layers window and click that button on the bottom left." Understandably, they often forget that step, then get into trouble because they can't see all their pasted layer, or some functions are greyed out.

Aside from selection and paste, the students seem to cope with GIMP remarkably well. Some of them have been exploring the menus for fun plug-ins, others are trying different patterns to make interesting backgrounds, and one even discovered how to make interesting effects with some of the specialized gradients. At the beginning I wondered if teaching GIMP might not be too ambitious, and maybe something simple like Tux Paint might be better. But GIMP is working out just fine except for those few stumbling blocks. The kids have a refreshing willingness to explore and try things, and the result is a whole lot of really fun images.

Tags: , ,
[ 23:44 Apr 12, 2008    More gimp | permalink to this entry | ]

Tue, 26 Feb 2008

Quick GIMP Tip: Middleclick to open images

I've wished forever that GIMP could open files and URLs as easily as Mozilla (and Netscape before it) does by selecting the filename in another app then middleclicking to "paste" in the toolbox. (Note: in Mozilla this is controlled by the middlemouse.contentLoadURL preference, and Ubuntu users have to enable it explicitly.)

Well, it turns out GIMP has that feature too, and has had it for a long time. The reason it had never worked for me is that it only works if you click on one (any) of the tool buttons. I was clicking in empty areas of the toolbox window, because it feels weird to click over a button when I don't mean to use that tool.

Now that I know to middleclick on a tool button, middlemouse open works great for Unix paths, file: URLs and even remote URLs (assuming you have Open URL working, of course, which on some systems may require installing gimp-libcurl or gimp-gnomevfs).

Nice! That'll save me some gimp-remote calls.

[ 16:21 Feb 26, 2008    More gimp | permalink to this entry | ]

Sun, 17 Feb 2008

Easy layer mode changing in GIMP

There's been some discussion on the gimp-developer list about that unwieldy layer mode option menu you see in both the Layers dialog and in drawing tool options.

Bill introduced the topic by suggesting a redesign of the menu to use two side-by-side columns instead of one. That makes the menu more compact and vastly shortens the average mouse movement needed to change modes.

But Sven didn't like the side by side option, pointing out that it implies some equivalence to modes that end up listed next to each other.

More discussion ensued, with Bill posting a screenshot of the unwieldy menu to illustrate how bad it is (including the bizarre gtk "the top half of the menu is blank" misfeature that always looks like a bug but is apparently intentional).

That Mode menu has always bothered me. Typically when I'm using layer modes, I try lots of them one by one to see which mode works best. But that's difficult with the current very tall menu, especially (as Bill pointed out on IRC) if you need to jump back and forth between two modes that aren't close to each other in the menu. And gtk option menu's behavior doesn't help, where clicking on it pops up the menu but not necessarily with the current item selected -- sometimes the previous item is selected, so you can't just arrow down once and assume you'll get the next mode.

That night after going to bed I got to thinking about it. I realized that the Mode menu problem was similar to the problem selecting a font from the combo box in the Text tool options -- I usually find it much easier to bring up the Fonts dialog and choose a font from there. What I really wanted for layer modes was a "Modes dialog".

And suddenly it came to me that I could solve most of my problem with a simple "Next mode" script. Once I had that, I could bind it to a key, or "tear off" the menu it was in so that it would stay visible and I could click it repeatedly. It took about ten minutes the following morning to write the script in python.


I posted my solution back to the list, and some discussion ensued on IRC. Bill pointed out that enabling tear-offs for the existing Mode option menu (which can be done in two lines of C code) gives essentially the Fonts dialog I wanted. Several of us thought that was a great idea. But when Bill posted to the list, Sven nixed the idea, saying tear-offs were deprecated. (They're not officially deprecated in GTK, or at least the GTK documentation doesn't say so and I can't find anything with google; but in any case Sven apparently doesn't like tear-offs and won't allow adding any new ones in GIMP.)

Fortunately, gimp-python comes to the rescue here too. Writing a turned out to be a little trickier than "next mode", only because it took me a while to realize I needed to call pdb.gimp_displays_flush() to update the display after changing the mode of the current layer (thanks Alexia and Bill).

So now I have both "next mode" and a separate mode dialog, making layer mode operations so much easier!

[ 12:50 Feb 17, 2008    More gimp | permalink to this entry | ]

Sun, 21 Oct 2007

GimpLabels: Printer fudge factor

I ran out of business cards (where do they go? I never seem to find occasion to give any out. They make good bookmarks, though) and wanted to print some more. I use gLabels for low-res label printing, but it prints poorly (or used to, anyway) so when I want something with crisp and sharp images, I use GIMP with my GIMP Labels script.

That's all fine, except that the "make label page" part of the script scales the labels to fit on a typical Avery letter-sized template -- and the Gutenprint drivers for my printer can't actually fill a letter sized page. (I have the choice of normal printing, in which it fills about 97% of the page, or Borderless printing, where it slops way over the edges.)

The solution is to crop a little extra off the outside edge of the label page. So I added some code to script-fu-rect-label-page to keep a "Printer fudge factor" and crop the page at the end. An easy tweak which seems to work fine, and with any luck it'll cure a lot of the misalignment problems I've seen with labels.

While I was making changes anyway, I added some clearer installation instructions for the 95% case of someone who just wants the script with the labels I've included, since I recently heard from someone who wasn't clear on where to install the script.

[ 13:03 Oct 21, 2007    More gimp | permalink to this entry | ]

Sat, 09 Dec 2006

Getting a Wacom Tablet Working under Edgy

Another person popped into #gimp today trying to get a Wacom tablet working (this happens every few weeks). But this time it was someone using Ubuntu's new release, "Edgy Eft", and I just happened to have a shiny new Edgy install on my laptop (as well as a Wacom Graphire 2 gathering dust in the closet because I can never get it working under Linux), so I dug out the Graphire and did some experimenting.

And got it working! It sees pressure changes and everything. It actually wasn't that hard, but it did require some changes. Here's what I had to do:

  1. Install wacom-tools and xinput
  2. Edit /etc/X11/xorg.conf and comment out those ForceDevice lines that say "Tablet PC ONLY".
  3. Reconcile the difference between udev creating /dev/input/wacom and xorg.conf using /dev/wacom: you can either change xorg.conf, change /etc/udev/rules.d/65-wacom.rules, or symlink /dev/input/wacom to /dev/wacom (that's what I did for testing, but it won't survive a reboot, so I'll have to pick a device name and make udev and X consistent).

A useful tool for testing is /usr/X11R6/bin/xinput list (part of the xinput package). That's a lot faster than going through GIMP's input device preference panel every time.

I added some comments to Ubuntu's bug 73160, where people had already described some of the errors but nobody had posted the steps to work around the problems.

While I was fiddling with GIMP on the laptop, I decided to install the packages I needed to build the latest CVS GIMP there. It needed a few small tweaks from the list I used on Dapper. I've updated the package list on my GIMP Building page accordingly.

Tags: , , , ,
[ 16:12 Dec 09, 2006    More linux | permalink to this entry | ]

Thu, 23 Nov 2006

GIMP JPEG 2000 Plug-In

People keep showing up on GIMP's IRC channels and asking about JPEG 2000 support. There was a Summer of Code "Wavelet" project last summer which implemented JPEG 2000 support (among other things) but no one ever seems to know where to find it.

So I asked Simon, who was the mentor for that project. Turns out he had tarballs, but didn't think it was appropriate to link them from his own site, especially as they were somewhat tricky to compile.

The consensus among the developers was that it would be nice to have jp2 and the other wavelet plug-ins available on the GIMP Plug-in Registry. So I fiddled with them, fixed a couple of Makefile issues, added READMEs with author credit and building instructions, and uploaded them to the registry. The plug-ins are:

JPEG 2000 support
A noise removal plug-in
Inverse halftoning -- remove halftones from printed images.

I haven't actually used these plug-ins (couldn't find a JPEG2k file to test) -- I just wanted to help make them available for people who need them.

While I was at it I updated my vastly out-of-date registry entries for Pandora and added an entry for my label/business card script.

[ 13:54 Nov 23, 2006    More gimp | permalink to this entry | ]

Tue, 15 Aug 2006

GIMPing a "favicon"

"Favicons" are those little icons you see to the left of the URLbar in a browser, and for each site in the bookmarks menu or toolbar. They're just a file named favicon.ico in the top level of a web site, and they're a nice addition to a site. (More details in the Wikipedia entry.)

I'd made a few favicons in the distant past by creating a 32x32 image, saving it as ppm, then using ppmtowinicon. But when I tried it in GIMP recently, I ran into trouble.

GIMP can save ICO files: Save As, click Select File Type and choose "Microsoft Windows icon (ico)". That gets you a dialog where you have to choose a color depth and palette. I tried different settings, but the resulting images never showed up properly in Firefox.

But then I tried saving as ppm and using ppmtowinicon and that no longer worked either. Argh! What's up?

The silly answer, it turns out, is that it had nothing to do with how GIMP was saving the images. The problem was that Firefox caches favicons, and shift-reload or Clear Cache doesn't help. When you're testing a new favicon, you have to load the url for the favicon.ico itself (and reload it if necessary). Success at last! It even handles transparency, so you can make shaped favicons that show up nicely against a tab, menu or toolbar background.

Of course, editing a 32x32 pixel image is a fun exercise in itself. I recommend using a second view (View->New View). Expand one view a lot (800x works well) so you can edit individual pixels, while the other view remains at normal size so you can see your final icon as others will see it in the browser.

[ 11:57 Aug 15, 2006    More gimp | permalink to this entry | ]

Tue, 18 Jul 2006


I got slashdotted yesterday -- a positive Slashdot book review of Beginning GIMP. Hooray!

The comments were mostly the usual mix of flames from Photoshop users saying "GIMP sucks because it isn't like Photoshop", with hardly anything about the book; no surprise there. I don't know why Photoshop users seem so compelled to attack the GIMP, but obviously they do since this happens so often. They don't seem to be willing to accept "Some people like one style of user interface, other people like another style, and a highly complex application like GIMP or Photoshop is going to take some time to learn no matter how it's designed."

Slashdot linked to Barnes & Noble rather than Amazon, which is understandable since BN has a killer 40% off sale in progress on Apress books (they have

at $26.99 for BN members, $29.99 otherwise).

Apress also pointed me toward a couple other reviews that I hadn't seen yet, so I created a review page to link to them.

[ 18:37 Jul 18, 2006    More gimp | permalink to this entry | ]

Sat, 27 May 2006

New Pandora, Reversing Layers, and Script-Fu Booleans

Dave thought I wasted too much presentation time reversing the layers in my panorama example prior to running Pandora. I'm sure he's right.

The problem is that GIMP's "Open as Layers", if you select multiple layers, opens them in the opposite direction from the way you'd generally expect to use them in a panorama, with the lexigraphically first layer on the top of the stack rather than the bottom.

The very next day, someone showed up on IRC asking how to reverse layers, because "Open as Layers" opened them in the wrong order to use for an animation.

At Mitch's suggestion, I wrote a reverse-layers script-fu (which Mitch improved by pointing out that it didn't handle the possible error case of a floating layer. As it happens, re-ordering floating layers works fine in current CVS, but apparently it's not supposed to. I suspect being able to move layers without alpha off the bottom position in the stack may also be a bug, so I added a guard against that). (Update: No, it turns out it's intentional that non-alpha layers can be moved anywhere in the stack in 2.3.)

Layer->Stack->Reverse Layer Order is now included in CVS GIMP, but for users of earlier versions I've made it available: reverse-layers.scm.

Meanwhile, I made a new version of Pandora which can build a panorama in either direction. I still find it slightly jarring to assemble a panorama from right to left after building them from left to right for so long, but maybe I'll get used to it.

I caught another bug at the same time: I was testing one of the parameters set in the GIMP dialog (which sets a toggle to either TRUE or FALSE) like this: (if use-mask (do-stuff))

That doesn't work in script-fu. Turns out TRUE is just an integer, while if apparently only tests for Lisp nil or non-nil. So you have to say (if (= use-mask TRUE) (do-stuff)) if you want tests to work against booleans coming from GIMP dialogs.

[ 23:22 May 27, 2006    More gimp | permalink to this entry | ]

Fri, 26 May 2006

"Beginning GIMP" is shipping!

It's been a busy couple of weeks. My book (Beginning GIMP: From Novice to Professional) finally started arriving on people's doorsteps.

I first found out it was shipping from an email from a reader in Ohio: "I just received your book, and I have a question ..." He was the first of the Amazon shipments.

Over the next few days, more Amazon shipments started trickling in -- my mom got hers, a couple of friends got their copies. But it was nearly a week before either I or the home office of Apress received our copies, so in the meantime I was pumping everyone I knew for information -- "How does it look?"

Finally my copies arrived. It's beautiful! I'm so happy with the printing job Apress arranged. Bright colors on thick glossy paper. The colors are surprisingly different from what I saw on the PDF that went to the printer -- the active window borders on all the screenshots (royal blue on my screen) are almost purple! Now I can better appreciate why people who print professionally care so much about details like ICC color profiles. Fortunately, I knew there might be some color shift, so none of the figures in the book depend on exact colors (the RGB color circles aren't precisely Red, Green and Blue, but I'm sure readers will understand them).

So now I'm on the lecture/booksigning circuit. What fun! I've only given a couple of talks so far; last night was a PenLUG talk that went well, with lots of audience questions. The audience ranged from beginners to experienced graphics programmers to someone who's interested in using GIMP in a scientific context (comparing images; I told him about the geologist I talked to a few months ago who was doing just that, using Difference or Subtract layer modes to compare two aerial photos of the same area) to a professional photographer who uses GIMP in his work. One of the great side benefits of speaking about GIMP is getting a chance to hear all the ways people use it for different purposes.

I made some business cards to hand out, but no one takes them. That's okay: it was a good excuse to fiddle with my gimplabels script-fu and learn how to print really nice business cards from GIMP. Making business cards is easy with gLabels, but since it uses gnome-print it can only print using the system's default settings, which makes for really chintzy looking, pixellated cards. Gimp-print, on the other hand, can print in high resolution to nice glossy photo-quality card stock.

I'm gradually learning how to give a better GIMP talk, collecting interesting examples to show and minimizing the time spent fumbling over menus or waiting for progress bars. And dealing with the occasional glitch: last night, SIOX for some reason refused to select my flower image, after working perfectly the hundred or so previous times I've used it on that image. (What timing! Just last week I also received my ATM-B award from Toastmasters. Too bad outside GIMP talks don't count toward the next level.)

Fortunately GIMP is very visual, so it's easy and fun to find whizzy examples and techniques that most people haven't seen before. People have lots of interest in GIMP and image editing in general, and they want to hear more about it and have lots of questions. It's a topic everyone can appreciate. After all, who doesn't like looking at cool images?

[ 11:32 May 26, 2006    More gimp | permalink to this entry | ]

Sun, 19 Mar 2006

Pandora Now in Script-Fu

Periodically I get requests from people without C compilers (which usually means Windows users) who are interested in using my GIMP plug-in Pandora, which helps with making panoramic images by loading all the images, positioning them approximately, and adding layer masks. I always regret that I don't have a Windows binary to offer people.

I've been thinking for a while that it would be easy to do a Pandora plug-in in script-fu, so that any GIMP user could run it. The only reason Pandora was written in C is that it provides a modified file selection dialog allowing you to choose the files you want in sequence. But it's not like the UI for that dialog is any great shakes (it's always been confusing, even to me, and I wrote it), and of course it uses the old gtk file selector, which has been orphaned for quite some time.

The way to work around this in script-fu is to let the user open all the images as layers in a single image using the normal Open and Open as Layers functions, then transform that image into a panorama by resizing it bigger and moving the layers to the right place. Easy! It's been on my list to do for a long time, but I didn't get motivated to write it until this morning when I wasn't doing anything else and another Windows user showed up on #gimp asking about panoramas.

I should have done it earlier. It only took an hour or two, and works as well as the old C version. It's available on the Pandora page. Feedback or bug reports appreciated!

[ 19:02 Mar 19, 2006    More gimp | permalink to this entry | ]

Tue, 14 Mar 2006

Quick GIMP Tips: Centering a Layer, or Preventing Centering

People are forever turning up on #gimp to ask (quite reasonably) how to center a layer, since GIMP offers no built-in way to do that.

There are Python and Perl scripts around somewhere (and it's easy to write, a great project if you're thinking about learning how to write GIMP scripts in any language). And the new Align tool can probably center, for those using GIMP 2.3, but the tool is a bit difficult for most people to figure out (fear not, the UI is still being developed).

But for those who want a quick solution:

Center a Layer:

Cut, then paste. The pasted layer comes out centered. (Unfortunately this loses text information, so if it's a text layer this isn't an ideal solution.)

Paste a layer on top of a copy of itself:

Do a Layer to Imagesize before copying. Then copies of the layer will overlap the original.

[ 19:51 Mar 14, 2006    More gimp | permalink to this entry | ]

Mon, 30 Jan 2006

The GIMP Book is Done!

Although I haven't been writing about it here, for most of the past year I've been working on a new GIMP book for Apress, called Beginning GIMP: From Novice to Professional.

Today the work was over: the last bits shipped to the printer! The rest is just waiting (... and waiting ... and waiting ...)

Amazon has a page on it already (complete with typo in the description; sigh) for folks who like to pre-order their books months early. Scheduled release date is currently late April. (I think they have to grow the trees first.)

In case you haven't already heard other authors say it, writing a book is a lot more work than you think it will be. Even if other authors have already told you that it's more work than you think it will be, it's more work than that. If you thought you already knew the subject you were writing about, think again. You'll find out how little you really knew. You'll discover all sorts of options you never noticed in your favorite tools, and new (and often better) ways to do things than the methods you'd been using for years. You'll discover bugs in plug-ins no one's used in a while, and why things you always thought were bugs really aren't.

That's the good sort of "too much work": the kind that keeps you learning, so that you come away from it with more than you started with. It's been fun. But I confess that I'll be glad to take a rest for a while and work on some long neglected coding projects.

I celebrated ship-to-printer with a little GIMP hacking (adding that feature list to configure that I wished for last week, so now GIMP will warn you of any missing features before you start your 45-minute build); and with lamb kebab with zereshk polo at Chatanoga.

[ 22:38 Jan 30, 2006    More gimp | permalink to this entry | ]

Tue, 24 Jan 2006

What Features will be Disabled in this GIMP?

I've been frustrated for some time at GIMP 2.3's inability to save EXIF data whenever I save a JPEG image. There were several bugs report on the problem, and I just assumed that this was something which had broken somewhere along the line and hadn't been fixed yet.

It turns out it was a stupid build problem on my machine: I didn't have libexif-dev installed on either of my Ubuntu systems, and GIMP's configure script wasn't warning me about it in any obvious way. (Of course, had I taken the time to read through the 3679 lines of config.log, the information was buried in there around line 2199.)

So now I have EXIF again, at least on the laptop (hooray!) but I also learned something more important: after running configure for the first time on any new system, before running make, do this:

grep -i "will not" config.log

That may not flag everything, but at least it's a start at getting a list of features that have been disabled because of dependencies you forgot to install (anything which configure is smart enough to tell you "will not be built").

Schumaml had the great idea of putting a list of enabled features in the About box. Maybe I'll look into doing that in a week or two (when the current crunch is over and I have more time to upgrade my development machine so that it can use gtk 2.8 and I can actually build GIMP again).

Update: I added a printout similar to the one I thought I remembered, so there should be no further need to grep for "will not".

[ 15:11 Jan 24, 2006    More gimp | permalink to this entry | ]

Mon, 29 Aug 2005

Using GIMP for Paper Prototyping

Sven, one of the GIMP developers, has been interested in setting up a "paper prototyping" system for reorganizing the GIMP's menus (see his blog post.

Since I've been involved with some of the ongoing menu reorganization, we've talked about it a bit, and discussed some tools that are being written to assist with online paper prototyping (since the "get everybody together in a room with slips of paper" model doesn't work for worldwide distributed projects).

But for some reason it never occurred to me until a couple days ago that GIMP itself would make a fine paper prototyping tool. The move tool lets you move the text layers into any configuration you like, you can control colors and fonts, and you can save to your choice of standard formats.

It didn't take long at all to whip up a script-fu to enable paper prototyping, which I posted to the gimp-developer list.

Nobody has actually used my script to comment on the menu reorganization yet ... but what the heck, it was fun to write the script. Maybe it'll be useful in other projects that need paper prototyping.

[ 17:43 Aug 29, 2005    More gimp | permalink to this entry | ]

Fri, 29 Jul 2005

Switching from Debian to Ubuntu; Dependencies To Build GIMP

I've switched my desktop machine from straight Debian (unstable, or "sid") to Ubuntu "Hoary Hedgehog". Sid was just getting too unstable for me (I'd been spoiled because it really has been pretty stable, except for printing problems, for the past few years). Freetype now has rendering problems, so any fixed width terminal font is nearly unreadable and many PDFs aren't readable at all. There are issues related to the switch to gcc 4. But the last straw was when printing to my Epson C86 stopped working.

(I try to make a point of mentioning bug numbers when I whine about open source issues. The freetype problem with terminal fonts was already reported as bug 315150, and I opened bug 319068 on the pdf issue though I suspect it's part of the same problem. The gcc4 issues are well known and are just transitional issues. I didn't bother reporting the printer regression; after over a year of having similar bugs for my old printer ignored, finally giving up and buying a new printer specifically so that I could continue to run Debian, it's hard to have much confidence that reporting printing bugs is worthwhile.)

The switchover to Ubuntu was surprisingly painless. The install went fairly smoothly, and in half a day I was up and running with my environment (currently fvwm) customized the way I wanted it. The only problems I've had with hoary are poor rendering of fixed-width fonts (not as poor as sid with the freetype bug, but a lot worse than debian used to be) and inability to play mp3 (I suspect I'll hit problems with other formats such as wmv as well, but I haven't tried yet). The font problem is quite annoying and no change I make to /etc/fonts/local.conf seems to make any difference. The mp3 problem probably requires downloading and hand-installing something -- I hear rumours that there's nothing apt-gettable which will make non-free formats work, though that seems odd for a distro aimed at desktop users.

Update 7/31: Turns out there are hoary packages for mp3 handling after all. Search for "mad" rather than "mp3", e.g. xmms-mad adds mp3 support to xmms.

But first I had to set up a development environment. Ubuntu's install is very minimal, since it uses only a single CD. It doesn't even install gcc by default. So I enabled all the ubuntu sources (restricted, universe, multiverse) and I've been gradually adding packages to get back everything I had on sid.

GIMP (2.3, from CVS) seemed like a good build test. Assembling the dependencies was straightforward but time consuming. Since people new to building GIMP are often confused about what they'll need, I kept track of the additional packages I needed, and posted the full list on my GIMP building page.

[ 12:24 Jul 29, 2005    More gimp | permalink to this entry | ]

Mon, 20 Jun 2005

GIMP Menu Reorganization

I'm working with the GIMP developers to do some minor reorganization of some of the menus.

In particular, we wanted to get things like script-fu and python-fu out of the menus so users don't have to know what language a function is written in to use it.

That part of the patch (for the image window; the Toolbox Xtns menu reorganization is still pending) got checked in a few days ago. Sven is now soliciting comments on the next step on his Planet Gnome blog. The proposal for the next step is in bug 116145. There haven't been many comments; I encourage anyone interested in GIMP's menus to read that bug and comment in it.

The Toolbox Xtns menu reorganization is a bit more complicated, since there are two conflicting proposals, in bug 145507 and bug 158980. I tried to suggest just moving stuff out of the Script-Fu menu for now, since there's no agreement on further changes yet, but that went over like a lead balloon.

So it's back to the image window's Filters menu. If there aren't any comments in a few more days I'll just go ahead with the proposal in the bug.

Maybe I'll even get to use my shiny new CVS access to check the changes in myself. Woo!

[ 11:49 Jun 20, 2005    More gimp | permalink to this entry | ]

Sun, 08 May 2005

Wacom Rides Again

Updating the blog again after taking time off for various reasons, including lack of time, homework, paying work, broken computer motherboard and other hardware problems, illness, a hand injury, and so on.

This afternoon, thanks to a very helpful Keir Mierle showing up on #gimp, I finally got all the pieces sorted and I now have a working tablet again. Hurrah!

I've put details of the setup that finally worked on my Linux and Wacom page.

Tags: , ,
[ 19:08 May 08, 2005    More linux | permalink to this entry | ]

Wed, 02 Feb 2005

GimpLabels script-fu

Someone showed up on #gimp the other day asking about how to make business cards. He was on Windows, so gLabels wasn't really an option, and of course my old gimp-print patch to read gLabels label templates would have been no help to a Windows user.

I got to thinking about how easy it would be to write a little gimp script analogous to my CD label script, which created a rectangular template in which to design a label, then created a bigger image scaled to the size of a page on which the label could be repeatedly positioned, with specified start and end points.

I couldn't resist trying it. It wasn't quite as easy as I had initially thought, mainly because I don't know script-fu very well and debugging script-fu is painful. But it still only took a few hours on a couple successive days to hack up something that more or less works: GimpLabels.

I didn't try to parse the gLabels XML from script-fu; I wrote a separate python script to translate the label templates into script-fu.

It's not perfect. On a page of 30 Avery 5160 labels (10 rows), it gets a little off by the bottom of the page. I don't know yet if this is a problem in the gLabels template, in my understanding of the parameters, or in the script-fu. It's fine for shorter pages.

I integrated my existing CD label routines into the script, but haven't yet written code to parse the CD label templates and make a print page from them. I've lost motivation for working on CD labels anyway, since discovering a few months ago how drastically they hurt CD longevity.

Anyway, GimpLabels was a fun hack, and an example of how easy it is to do this sort of thing in gimp.

[ 12:20 Feb 02, 2005    More gimp | permalink to this entry | ]

Tue, 25 Jan 2005

GIMP course started

I've started my "GIMP for Beginners" course on the Linuxchix Courses mailing list, topic "gimp".

Anyone reading this is welcome to join in!

Here's the first posting, Lesson 0.

[ 11:10 Jan 25, 2005    More gimp | permalink to this entry | ]

Tue, 28 Sep 2004

Pandora 0.7 released

I shot way too many panoramas on the Southpark trip (places like Canyonlands just don't fit in any normal camera lens) and ran up against some irritations in Pandora when stitching them together. Notably, it no longer remembered the overlap value from the previous run, and if you select filenames in the filepicker but don't click "Add" it just exited silently. Version 0.7 fixes those problems (Yosh figured out that it needed a call to gimp_main_exit in order to remember the values), and cleans up some crufty code that was left over from blindly copying the gimp sample plugin.

[ 12:28 Sep 28, 2004    More gimp | permalink to this entry | ]