Fixing the Orientation of JPEG Photographs

 

I used to fix the orientation of my photographs through an application that would transpose the compressed JPEG blocks. This had the advantage of avoiding the image degradation of a decompression and a subsequent compression.

However, this works only when the photograph's size is in both dimensions an exact multiple of a block's size. When disk space at my disposal increased I configured my camera to take pictures at full resolution, and this method couldn't work anymore. A couple of months ago I found out that the media player I'm increasingly using to watch the photographs respects the so-called EXIF orientation field (as does Mac's Preview). This one-byte field specifies the orientation of the photograph (for instance, portrait or landscape). Some higher-end cameras set it automatically, but one can also modify it by hand. I started using the jpegexiforient command-line tool for this task, but even I, a command-line aficionado, found it difficult to use.

I therefore wrote jeo, a GUI-based program that allows the interactive setting of a JPEG photograph's Exif orientation field. From the following links you can download the program's source code, Windows executable, Mac OS X application, and Unix (Linux, Solaris, FreeBSD, etc) executable. In order to work jeo requires a Java virtual machine to be installed.

I wrote the program in Processing, which proved to be a good match for my requirements. I've never written a program that relied as heavily on exceptions as this one, and I often wondered on their utility. In this case they proved an invaluable debugging aid, because they allowed me to easily pinpoint the location and reason of each failure; locating the orientation field in a JPEG file is anything but trivial. I also had doubts regarding the time performance of the image rotation loop (Processing stores the images in a one-dimensional array). To reduce the code duplication I assigned the new location of each pixel inside a doubly-nested loop.

int x2, y2;
for (int x = 0; x < img.width; x++)
    for (int y = 0; y < img.height; y++) {
	switch (currentOrientation) {
	case 8:
	    x2 = y;
	    y2 = img2.height - x - 1;
	    break;
	case 3:
	    x2 = img2.width - x - 1;
	    y2 = img2.height - y - 1;
	    break;
	case 6:
	    x2 = img2.width - y - 1;
	    y2 = x;
	    break;
	default:
	    throw new IllegalStateException();
	}
	img2.pixels[y2 * img2.width + x2] = img.pixels[y * img.width + x];
    }
It seems that either the compiler or the JVM did a very good job in compiling the code, because the program's performance is quite snappy.

Comments   Toot! Share


Last modified: Sunday, June 14, 2009 8:20 pm

Creative Commons Licence BY NC

Unless otherwise expressly stated, all original material on this page created by Diomidis Spinellis is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.