January 2, 2007

How to configure a scanner's buttons on Linux

Author: Manolis Tzanidakis

While not perfect, support for scanners on Linux is constantly improving; just check the list of devices supported by SANE (Scanner Access Now Easy -- the scanning suite for Linux and other Unix-like systems). One thing that's still missing though is a way to make a scanner's buttons work on Linux. That's what this tutorial is about.

I run Ubuntu 6.10 (Egdy Eft) on my desktop system, but all required programs are available on most Linux distributions and, possibly, BSD variants. The actual programs you will need for this setup are:

scanimage, the scanning command of the SANE package. In Ubuntu/Debian this command is included in the sane-utils package.

convert, part of the ImageMagick image manipulation suite. We will use this program to convert the scanned pictures to different formats. On Ubuntu/Debian install the imagemagick package. This article is a nice introduction to the powerful ImageMagick suite.

scanbuttond is the daemon program that does all the dirty work of running commands when a scanner button is pressed. For more information check its home page. On Ubuntu and Debian (testing and unstable only) install the scanbuttond package.

Optionally, you can also install the zenity package (installed by default on Ubuntu) to print nice, graphical error messages when something goes wrong.

Before continuing you need to make sure that your scanner operates correctly under Linux. A previous tutorial, How to share a scanner on your network, contains information on how to set up your scanner on Linux. Read the first part of that article and make sure that running scanimage -L as your regular, non-root user lists your scanner. This command on my system returns:

device `plustek:libusb:004:002' is a Epson Perfection 1260/Photo USB flatbed scanner

To start, you need to adjust scanimage's options manually to achieve the best scanning results. Grab a ruler and measure your scanner's actual scanning surface -- X and Y axis -- or find these values in your scanner's manual. Put a nice color picture on your scanner and run the command scanimage --device "plustek:libusb:004:002" --mode Color --resolution 300 --depth 8 -x 215 -y 297 > ~/test.pnm to scan the image and save it as test.pnm in your home directory. Make sure to replace plustek:libusb:004:002 with the device printed by running scanimage -L, and the values of -x and -y with the dimensions of your scanner. 215 and 297 are my scanner's scanning surface dimensions in mm (millimeters). Don't worry if you get these dimensions wrong; scanimage will round them to the correct values automatically. For example, when I entered 220 as the length of the X axis, scanimage returned:

scanimage: rounded value of br-x from 220 to 215

The other options supplied to the scanimage command instruct it to scan a picture in Color mode (--mode) with 8 bits per sample (--depth) and 300dpi resolution (--resolution). These options should be enough for most users. For all available options run scanimage -h | less and check the scanimage man page.

View the scanned picture test.pnm on your favorite image viewing program and adjust scanimage's options to your liking. Write the adjusted command down somewhere since you'll need it later.

Scanbuttond configuration

Scanbuttond has three configuration files -- meta.conf, buttonpressed.sh, and initscanner.sh -- all installed under the /etc/scanbuttond directory on Ubuntu. The first file, meta.conf, defines which scanner backend libraries will be used. You shouldn't need to edit it unless you test a beta version and you're told so by the program's developers.

Some scanners might need some extra initialization steps -- such as firmware uploading or running some commands -- before they can be used by scanbuttond. You can enter these commands into the initscanner.sh file, which is actually a shell script run by scanbuttond during initialization. For my scanner, which is supported by the plustek backend, I had to add scanimage -n to that file. For more information on using initscanner.sh, check the paragraph titled "Scanner initialization" on scanbuttond's README file (in Ubuntu/Debian it's installed as /usr/share/doc/scanbuttond/README.gz) and SANE's documentation for your scanner.

The last file, buttonpressed.sh, is the most interesting. It defines which commands should run when the buttons are pressed. It's a shell script that's run by scanbuttond with the button number as the first argument ($1) and the scanner device as the second ($2). By default the only thing it does is print the button's number when it's pressed. Run scanbuttond as your regular, non-root user and check its logs by running sudo tail -f /var/log/daemon.log on a virtual terminal. If scanbuttond starts without problems you should see something similar to this:

Dec 14 19:37:18 my_hostname scanbuttond: found scanner: vendor="Epson", 
product="Perfection 1260", connection="libusb", sane_name="plustek:libusb:004:002" Dec 14 19:37:18 my_hostname scanbuttond: scanbuttond started

Now press the scanner's buttons while keeping an eye on the log tail command's output to verify that all of your scanner's buttons work. You should see something like:

Dec 14 19:37:37 my_hostname scanbuttond: button 1 has been pressed.
Dec 14 19:37:37 my_hostname scanbuttond: button 1 has been released.

Now it's time for the fun part. Back up the original buttonpressed.sh file by renaming it to buttonpressed.sh.orig and paste the following as a new buttonpressed.sh file:

#!/bin/sh

# daemon's name
DAEMON=scanbuttond

# securely create temporary file to avoid race condition attacks
TMPFILE=`mktemp /tmp/$DAEMON.XXXXXX`

# lock file
LOCKFILE="/tmp/$DAEMON.lock"

# device name
DEVICE="$2"

# destination of the final image file (modify to match your setup)
DESTINATION="/home/manolis/Desktop/scanned_image.jpg"

# remove temporary file on abort
trap 'rm -f $TMPFILE' 0 1 15

# function: create lock file with scanbuttond's PID
mk_lock() {
	pidof $DAEMON > $LOCKFILE
}

# function: remove temporary and lock files
clean_up () {
	test -e $LOCKFILE && rm -f $LOCKFILE
	rm -f $TMPFILE
}

# function: check if lock file exists and print an error message with zenity (if it's installed)
chk_lock() {
	if [ -e $LOCKFILE ]; then
		if [ -x /usr/bin/zenity ]; then
			zenity --display :0.0 --title="Scanbuttond" --error \
			--text="Another scanning operation is currently in progress."
		fi
		exit 1
	fi
}

# function: the actual scan command (modify to match your setup)
scan() {
	scanimage --device-name "$DEVICE" --mode Color --resolution 300 \
			--depth 8 -x 215 -y 297 > $TMPFILE
}

case $1 in
	1)
	   # button 1 (scan): scan the picture & save it as $DESTINATION
	   chk_lock; mk_lock; scan; convert $TMPFILE -quality 85 -quiet $DESTINATION; clean_up
	   ;;
	2)
	   # button 2 (copy): scan the picture, convert it to postscript and print it
	   chk_lock; mk_lock; scan; convert $TMPFILE ps:- | lpr; clean_up
	   ;;
	3)
	   # button 3 (mail): scan the picture, save it as $DESTINATION and send it as an e-mail
	   # attachment with Evolution
	   chk_lock; mk_lock; scan; convert $TMPFILE -quality 85 -quiet $DESTINATION
	   evolution --display=:0.0 "mailto:?attach=$DESTINATION"; clean_up
	   ;;
	4)
	   # button 4 (web): unconfigured
	   echo "button 4 has been pressed on $2"
	   ;;
esac

This script looks more complicated than it actually is; each command is explained in detail in the included comments (lines starting with #). The lines you need to edit are marked with notes that say (modify to match your setup). To make a long story short it scans, copies, and emails (with Evolution) a picture when you press buttons 1, 2, and 3, respectively. The convert program is used to convert the scanned image to the JPEG format when you press buttons 1 and 3, and converts the image to PostScript (PS) when you press button 2. You can find more information about convert's features and options on its man page (man convert).

I left button 4 unconfigured as an exercise for the reader. You could try combining one of the utilities mentioned in this article with a scanner button to automate uploading scanned pictures to your Flickr account.

Make this new buttonpressed.sh file, as well as initscanner.sh, executable with chmod 755 /etc/scanbuttond/{buttonpressed,initscanner}.sh. Stop scanbuttond, if it's already running, with killall -TERM scanbuttond. To start scanbuttond automatically when you log in, add it to your desktop environment's session startup list. For example, on GNOME go to the menu System -> Preferences -> Sessions > Startup Programs.

Conclusion

When fine-tuned, scanbuttond can increase your productivity by automating your basic scanning tasks, or you can use it just to impress your friends at your local LUG. It can also be used for fun -- you could for instance combine it with a USB Missile Launcher and play a prank on your colleagues.

Click Here!