Hacking in Photography: Automatically rotating thumbnail preview image using DCRaw

DCRaw features an option to extract the thumbnail jpeg image, which is a much quicker way to preview the image in your image processing software, compared to exporting a PCM or TIFF image. However, if you have the auto-rotate feature disabled on your camera, the thumbnail image will always be horizontal-aspect. The primary reason to have auto-rotate turned off is to more quickly view the a larger preview image on the LCD screen. With auto-rotate turned on, vertical shots are rotated on the camera and displayed horizontally, in a 4:3 aspect, which makes the preview image much smaller. Disabling the auto-rotate feature causes the camera to display vertical images in 3:4 aspect on the LCD screen. A downside is that the camera must be rotated when viewing the image, and the thumbnail embedded in the CR2 Camera Raw file is always horizontal-aspect. When you use DCRaw to extract the thumbnail it must first be rotated to view on the screen. DCRaw parses the orientation reported by the camera in the "flip" global variable, so we can use this to determine the proper rotation angle to get a vertical aspect image. I almost always rotate the camera 90 degrees counter-clockwise to shoot a vertical image. You should normally rotate the camera so the orientation of the shutter trigger is on the top of the camera, for vertical aspect shots.

The program DCRaw is used in virtually every image editing software on the market.

DCRaw software for processing Camera Raw files.
by Dave Coffin

We can use the MagickWand library that comes with ImageMagick to add auto-rotate to the DCRaw jpeg thumbnail output function.

ImageMagick(R) is a software suite to create, edit, compose, or convert bitmap images. It can read and write images in a variety of formats (over 100) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG, and TIFF. Use ImageMagick to resize, flip, mirror, rotate, distort, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and B'ezier curves.


To use the MagickWand library, first add the include:

#include <wand/MagickWand.h>

We need to move the variable ofname scope outside of main() so that it becomes a global variable. First, in "int CLASS main" remove the definition of ofname, then add it to the beginning of dcraw.c with the other global variables. Also add the global "auto_flip" which will be set during command line switch parsing.

   All global variables are defined here, and all functions that
   access them are prefixed with "CLASS".  Note that a thread-safe
   C++ class cannot have non-const static local variables.

int auto_flip = 0; /* request auto flip */
char *ofname; /* output filename */

Add the auto_flip variable to the parser, after user_flip line in main():

      case 't':  user_flip   = atoi(argv[arg++]);  break;
      case 'R':  auto_flip   = 1; break; /* Auto Flip */

You should also add -R to the usage instructions, after -t Flip:

    puts(_("-t [0-7]  Flip image (0=none, 3=180, 5=90CCW, 6=90CW)"));
    puts(_("-R        Auto flip thumbnail image (use with -e)"));

Add the ImageMagick rotate code to the function definition around line 9108:

void CLASS jpeg_thumb()

...at the end of the function, add the following:

  /* open with ImageMagick library and rotate image */
  if (auto_flip) {
        /* amount of rotation */
        long degrees = 0;
        switch (flip) {
                case 0: break;                  /* no rotation */
                case 5: degrees = -90;          /* 90 CCW      */
                case 3: degrees = -180;         /* 180 CCW     */
                case 6: degrees = 90;           /* 90 CW       */
                default: break;
	/* do not rotate if degrees = 0 */
        if (degrees!=0) {
                if (verbose)
                        printf("Rotating %s %li\n",ofname,degrees);

                MagickWand *mwand;
                PixelWand *pwand;

		/* initialize MagickWand library */
		/* load image into memory */
                MagickReadImage(mwand, ofname);

		/* set format to jpeg */
                MagickSetImageFormat(mwand, "jpeg");

		/* create a new pixelwand object */
                pwand = NewPixelWand();

		/* the foreground/background should not matter when rotating 90/180 deg. */
                PixelSetColor(pwand, "none");
                MagickSetImageBackgroundColor(mwand, pwand);  

		/* rotate image */
                MagickRotateImage(mwand, pwand, degrees);

		/* write the image */
                MagickWriteImage(mwand, ofname);

		/* destroy object and free up memory */

		/* shut down the library */


We need to add ImageMagick library to compile command:

# clang -o dcraw -O3 -I/usr/include -I/usr/local/include -I/usr/local/include/ImageMagick \
	-L/usr/local/lib dcraw.c -lm -ljasper -ljpeg -llcms -lMagickWand

Output from dcraw about our test image:

# ./dcraw -i -v ../TAI/IMG_4668.CR2 
Notice: DCRAW_OFFSET not set, defaulting to GMT

Filename: ../TAI/IMG_4668.CR2
Timestamp: Fri Dec 14 17:34:55 2012
Camera: Canon EOS REBEL T2i
ISO speed: 1600
Shutter: 1/128.0 sec
Aperture: f/9.1
Focal length: 28.0 mm
Embedded ICC profile: no
Number of raw images: 1
Thumb size:  5184 x 3456
Full size:   5344 x 3516
Image size:  5202 x 3465
Output size: 3465 x 5202
Flip: 5
Raw colors: 3
Daylight multipliers: 2.222196 0.932800 1.295405
Camera multipliers: 2433.000000 1024.000000 1483.000000 1024.000000

We can tell by the "Output Size" that this image is a vertical aspect shot, also see "Flip: 5" which is a hint about the orientation of the camera when the shot was fired.

# ./dcraw -e -R ../TAI/IMG_4668.CR2

# identify ../TAI/IMG_4668.thumb.jpg 
../TAI/IMG_4668.thumb.jpg JPEG 3456x5184 3456x5184+0+0 8-bit DirectClass 3.611MB 0.000u 0:00.000

View the image to verify that the rotation is correct:

# display ../TAI/IMG_4668.thumb.jpg

{image pops up in ImageMagick window}

Auto Rotate

Note: function write_ppm_tiff() already flips the images for us, so we do not need to add the auto_flip functionality to the export function.