jwz - Cocoa EXIF rotation [entries|archive|friends|userinfo]
jwz

  www.jwz.org
  userinfo
  archive
  rss

Links
[»| [DNA Lounge] [Blog] [iCal] ]
[»| [DNA Lounge Legal Defense Fund] ]
[»| [WebCollage] [LJ WebCollage] ]

Cocoa EXIF rotation [Sat, 27-Dec-2008 3:38 PM]
Previous Entry Add to Memories Tell a Friend Next Entry
[Tags|, , , ]
[music |Cabaret Voltaire -- Motion 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]);
      }
    }
  }
linkReply

Comments:
[User Picture]From: [info]scullin
Sun, 28-Dec-2008 12:17 AM (UTC)

(Link)

I have to say it's creepy that when i google "NSImageEXIFData Orientation", this is the first result.
[User Picture]From: [info]poon
Sun, 28-Dec-2008 12:21 AM (UTC)

Using libexif

(Link)

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);
}

[User Picture]From: [info]jwz
Sun, 28-Dec-2008 12:25 AM (UTC)

Re: Using libexif

(Link)

Well that's just silly. Finder and Preview are accomplishing it somehow, and they aren't using libexif to do it.
[User Picture]From: [info]poon
Sun, 28-Dec-2008 1:26 AM (UTC)

Re: Using libexif

(Link)

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;
}
[User Picture]From: [info]tooluser
Sun, 28-Dec-2008 5:16 PM (UTC)

Re: Using libexif

(Link)

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.
[User Picture]From: [info]bovinity
Sun, 28-Dec-2008 12:41 AM (UTC)

(Link)

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.
[User Picture]From: [info]sol3
Sun, 28-Dec-2008 12:44 AM (UTC)

(Link)

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.

[User Picture]From: [info]endquote
Mon, 29-Dec-2008 4:16 AM (UTC)

(Link)

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.