Cocoa EXIF rotation

Dear Lazyweb,

How do you load an NSImage with proper EXIF rotation applied? I can't figure out how to determine the correct rotation. The following doesn't work. I get a dictionary containing a bunch of EXIF keys like exposure and shutter speed, but the "Orientation" tag is notably missing, and the image is displayed sideways. Preview and Finder display it properly, and exiftool says the field is there.


NSImage *img = [[NSImage alloc] initWithContentsOfFile:filename];
NSArray *reps = [img representations];
NSBitmapImageRep *rep = reps ? [reps objectAtIndex:0] : 0;
if (rep) {
NSDictionary *exif = [rep valueForProperty: @"NSImageEXIFData"];
if (exif) {
NSString *rot = [exif objectForKey:@"Orientation"];
NSLog (@"rot = %@", rot);
NSEnumerator *e = [exif keyEnumerator];
id key;
while ((key = [e nextObject])) {
NSLog (@"%@ = %@", key, [exif objectForKey:key]);
}
}
}
Tags: , , , ,

8 Responses:

  1. scullin says:

    I have to say it's creepy that when i google "NSImageEXIFData Orientation", this is the first result.

  2. poon says:

    Cocoa provides no love.

    Using libexif from http://sf.net/projects/libexif :


    #include <stdio.h>
    #include <stdlib.h>
    #include <libexif/exif-data.h>

    int
    main(int argc, char *argv[]) {
    if(argc != 2) {
    printf("Usage: foo <image>\n");
    exit(1);
    }

    int orientation = 0;
    ExifData *exifData = exif_data_new_from_file(argv[1]);
    if (exifData) {
    ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
    ExifEntry *exifEntry = exif_data_get_entry(exifData,
    EXIF_TAG_ORIENTATION);
    if (exifEntry)
    orientation = exif_get_short(exifEntry->data, byteOrder);

    exif_data_free(exifData);
    }

    /*
    0th Row 0th Column
    1 top left side
    2 top right side
    3 bottom right side
    4 bottom left side
    5 left side top
    6 right side top
    7 right side bottom
    8 left side bottom
    */

    if(orientation != 0) {
    printf("orientation == %d\n", orientation);
    }

    exit(0);
    }

    • jwz says:

      Well that's just silly. Finder and Preview are accomplishing it somehow, and they aren't using libexif to do it.

      • poon says:

        Alright, alright.


        #import <Cocoa/Cocoa.h>

        int main (int argc, char *argv[])
        {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSString *filename = [NSString stringWithCString:argv[1]];
        NSData *imageData = [[NSData alloc] initWithContentsOfFile:filename];
        NSImage *image = [[NSImage alloc] initWithData:imageData];

        if(!image)
        return 0;

        CGImageSourceRef imageSource =
        CGImageSourceCreateWithData ((CFDataRef)imageData, NULL);

        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);

        CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource,
        0, NULL);

        NSLog(@"orientation == %@",
        CFDictionaryGetValue(properties, kCGImagePropertyOrientation));

        [pool drain];
        return 0;
        }
        • tooluser says:

          What, were you just waiting for him to complain hard enough? We can probably take that for granted.

          Thanks, I was curious about this, too.

  3. bovinity says:

    The ImageIO framework is the way to go - http://phughes.us/node/2 has some sample code.

    GraphicsImaging/Reference/CGImageProperties_Reference/Reference/reference.html has all the keys, of which kCGImagePropertyOrientation is the one you're looking for.

  4. sol3 says:

    It looks like you want to be using ImageIO framework. Specifically a CGImageSource object, and one of the properties that you can pull out is kCGImagePropertyOrientation.

  5. endquote says:

    I've seen a bunch of apps get exif rotation wrong, including ones published by Flickr, so I guess it's sort of good to hear that it's not a total no-brainer to implement.