Read from iPhoto Library programmatically

4.5k views Asked by At

I want to create an Application that connects to the iPhoto Library. So now I would like to read the Events and the pictures themselves from the library.

Is there an elegant / easy way to do this or do I have to manually read the Bundle Structure of the iPhoto User Data?

So far I have only found a picture taker: Is there a UIImagePicker for the Mac Desktop

Update: I found another relevant SO post: Selecting iPhoto images within a cocoa application

2

There are 2 answers

0
lagnat On BEST ANSWER

You can do it with NSAppleScript. This is some copy/paste from my app, hacked up a bit just to show the idea.

    NSAppleEventDescriptor d = .. compile this script ..
        @"tell application \"iPhoto\" to properties of albums"

    for (int i = 0; i < [d numberOfItems]; i++)
    {
        NSAppleEventDescriptor *albumDesc = [d descriptorAtIndex:i];

        // <NSAppleEventDescriptor: 'ipal'{ 
        //  'ID  ':4.265e+09, 
        //  'purl':'utxt'("http://www.flickr.com/photos/..."), 
        //  'pnam':'utxt'("Vacation"), 
        //  'alTy':'pubs', 
        //  'alCh':[  ], 
        //  'alPx':'msng' }>

        NSString *albumName = [[albumDesc descriptorForKeyword:'pnam'] stringValue];
        NSString *albumId = [[albumDesc descriptorForKeyword:'ID  '] stringValue];

You can do the same thing to find the images

NSString *scp = 
    [NSString stringWithFormat:@"tell application \"iPhoto\" to properties of photos of album id %@",
     [album objectForKey:@"id"]];

NSAppleEventDescriptor *d = ... compile scp ...

// 1 based!?
for (int i = 1; i <= [d numberOfItems]; i++)
{
    NSAppleEventDescriptor *photoDesc = [d descriptorAtIndex:i];

    // Yes.. this happens.  Not sure why?!
    if (!photoDesc)
        continue;

    // <NSAppleEventDescriptor: 'ipmr'{ 
    // 'pnam':'utxt'("IMG_0058.JPG"), 
    // 'pwid':768, 
    // 'pdim':[ 768, 1024 ], 
    // 'alti':1.79769e+308, 
    // 'filn':'utxt'("3133889525_10975ba071_b.jpg"), 
    // 'ipth':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Masters/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg"), 
    // 'idat':'ldt '($F57C69C500000000$), 
    // 'rate':0, 
    // 'titl':'utxt'("IMG_0058.JPG"), 
    // 'phit':1024, 
    // 'itpt':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Thumbnails/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg.jpg"), 
    // 'ID  ':4.295e+09, 
    // 'lati':'msng', 
    // 'pcom':'utxt'(""), 
    // 'opth':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Masters/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg"), 
    // 'lngt':'msng', 
    // 'tiln':'utxt'("3133889525_10975ba071_b.jpg.jpg") }>

    NSString *path = [[photoDesc descriptorForKeyword:'ipth'] stringValue];
    NSString *imgname = [[photoDesc descriptorForKeyword:'pnam'] stringValue];
0
A.Badger On

If releasing apps on the App Store you are now required now required to use the Sandbox, this stops the previous AppleScript method from working (the iPhoto app launches but an empty set is returned).

iPhoto libraries consist of a directory structure containing photos, databases and XML files. The contents changes with each version of iPhoto so be careful if manually accessing these files.

If you just want the album details you can parse the file AlbumData.xml

If you would like photos you can browse the Masters folder. The files structure follows date rather than by the sets configured in iPhoto.

More information can be found on the internals of the iPhoto library here: http://www.fatcatsoftware.com/iplm/Help/iphoto%20library%20internals.html

The majority of the databases are in SQLite format and so can be programmatically accessed through Objective C, though again you can expect schema changes between different versions of iPhoto. The main databases of interest are Library.apdb and Properties.apdb in Database/apdb.


If you still want to use the Apple Script method, here's a version of the previous answer with the Apple script execution part included:

NSAppleScript *script = [[NSAppleScript alloc] initWithSource:@"tell application \"iPhoto\" to properties of albums"];
NSAppleEventDescriptor *d = [script executeAndReturnError:nil];

NSLog(@"photo library count: %ld", (long)[d numberOfItems]);

for (int i = 0; i < [d numberOfItems]; i++)
{
    NSAppleEventDescriptor *albumDesc = [d descriptorAtIndex:i];

    NSString *albumName = [[albumDesc descriptorForKeyword:'pnam'] stringValue];
    NSLog(@"%@", albumName);
}