This is a read-only archive!

Taking screenshots of a single window

I am running a game and I need to take many screenshots of the game window. There are lots of Linux tools that take screenshots: scrot, import (part of ImageMagick), gnome-screenshot, ksnapshot, and the GIMP does it too.

It turns out none of them does EXACTLY what I want, on its own. My requirements are:

  1. Take a snapshot via a single configurable keystroke.
  2. Save it in a directory of my choosing.
  3. Take a snapshot of a SINGLE window. And crop off the window borders. I need to take way too many snapshots to have time to go around editing them afterwards.
  4. Look at what files already exist in the directory I pick, and give the new file a filename that is next in ascending order after the files that already exist. It should pad the filename out to 5 digits.
  5. Do all of this non-interactively. It shouldn't ask me to confirm.

The way I finally ended up doing this is using import; I wrote a script to use it, and I assigned that script to a keystroke in my window manager. And once again, it's Ruby to the rescue:

#!/usr/bin/ruby

Dir.chdir('/SOME/DIRECTORY') do
    begin
        num = sprintf '%05d', Dir.glob('*').select{
            |x| x.match(/^\d+\.png/)
        }.sort[-1].match(/^(\d+)/)[1].to_i + 1
    rescue Exception => e
        puts e
        num = '00001'
    end
    raise "How'd that happen?" if File.exist? "#{num}.png"
    `import -window 'NameOfWindow' #{num}.png`
end

That this kind of thing is possible is why I love Linux. I can do so much more. I can have it save in multiple file formats. I can have it generate thumbnails as it saves new snapshots. (It's so easy to generate all the thumbnails later using convert that I'm not going to bother.) I could timestamp the filenames rather than using incrementing integers. (There is a race condition in this script that would be fixed if I did this, but I don't care enough to do it that way.)

March 03, 2007 @ 3:23 PM PST
Cateogory: Programming

3 Comments

noos
Quoth noos on March 09, 2007 @ 8:06 AM PST

This is a nice little script. Unfortunately, it requires you to know the name of the window you want a screenshot of, or it'll spit out error messages about there being no such window, so instead of the import line you have, you can simply use:

import #{num}.png

Also, if there's no existing file your script spits out an error about "undefined method `match' for nil:NilClass"

Finally, instead of searching through existing files and figuring out what the next consecutive filename should be, it's much easier to just use the current month, day, hour, minute, and second to create a unique filename (which will be in consecutive order as long as the clock on your machine works properly :). This can be done with a simple bash script:

!/bin/bash

#

Grab a screenshot of a window and output it,

using a unique name, to the appropriate directory

#

#

#

CONFIGURABLE VARIABLES

# IMPORT='import'

IMPORT_OPTS='-window root' # Grab the full screen

DATE=date +%m%d%H%M%S OUTPUT_PATH="$HOME/images/screenshots/full-screen" OUTPUT_FILENAME="$OUTPUT_PATH/$DATE.png" #

#

#

Grab screenshot

# $IMPORT $IMPORT_OPTS "$OUTPUT_FILENAME"

Brian
Quoth Brian on March 10, 2007 @ 5:56 AM PST

Thanks for another way to do it. Yours is simpler and more general-purpose.

I only want screenshots of one window, the same program each time, so that's why I use the window name. If that program isn't running, my script should die. I could timestamp the files, but I'm putting these files on a web page and typing in filenames made of 20 semi-random numbers is error prone and painful. I could always timestamp them and rename/renumber them later, but my way works for me.

noos
Quoth noos on March 10, 2007 @ 4:46 PM PST

Yep. That makes sense. Though, as far as typos go, you could use cut and paste, or write a script to transfer the files to your web page.