Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatic access to the Photos Library on Mac OS X: PhotoKit / Photos Framework for Mac

In Objective-C, there's a Photos Framework a.k.a. PhotoKit which enables iOS developers to access the photos library on iPhone and iPad and to retrieve the pictures/videos along with their metadata.

How would Mac developers perform a similar task? It seems PhotoKit is only available in iOS 8.0. Is there an equivalent of the Photos Framework for Mac OS X?

like image 521
Pierre F Avatar asked May 09 '15 20:05

Pierre F


People also ask

Can other Mac users see my Photos?

The system library is effectively open at all times by macOS in the background as long as that user is logged in, so even quitting Photos will not free up the library so that another user can open it.

How do I manage photo library on Mac?

To rearrange your albums, drag an album in the sidebar anywhere you want in the list. To sort the photos in an album, Control-click on the album, then choose a sorting option, like Keep Sorted By Oldest First or Keep Sorted By Newest First.

What is the system photo library on Mac?

When you first use Photos, you create a new library or select the library that you want to use. This library automatically becomes your System Photo Library. Although you can use multiple photo libraries in Photos, the System Photo Library is the only library that can use iCloud Photos and Shared Albums.

How do I open a photo database on a Mac?

If you want to open a different Photos libraryPress and hold the Option key while you open Photos. Select the library that you want to open, then click Choose Library. Photos uses this library until you open a different one.


2 Answers

The Media Library Framework is the place to go.

Usage:

@import MediaLibrary;

- (void) awakeFromNib
{
  NSDictionary *options = @{
     MLMediaLoadSourceTypesKey: @(MLMediaSourceTypeImage),
     MLMediaLoadIncludeSourcesKey: @[MLMediaSourcePhotosIdentifier]
  };

  MLMediaLibrary *mediaLibrary = [[MLMediaLibrary alloc] initWithOptions:options];
  self.mediaLibrary = mediaLibrary;

  [mediaLibrary addObserver:self
                 forKeyPath:@"mediaSources"
                    options:0
                    context:(__bridge void *)@"mediaLibraryLoaded"];

  [mediaLibrary mediaSources]; // returns nil and starts asynchronous loading
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                        change:(NSDictionary *)change context:(void *)context
{
   if (context == (__bridge void *)@"mediaLibraryLoaded") {
      // Media Library is loaded now, we can access mediaSources
      MLMediaSource *mediaSource = [self.mediaLibrary.mediaSources objectForKey:@"com.apple.Photos"];
   }
}

The concept behind the library is that you have to request it to read an attribute of an object, which returns an empty reference. Then you subscribe to this attribute with a key-value-observer and you wait till it is loaded. Then you can retrieve the next child with the same principle and so on...

like image 116
Pierre F Avatar answered Oct 14 '22 16:10

Pierre F


Based on Pierre F answer I extend code for displaying url's for all photos:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    NSDictionary *options = @{
                              MLMediaLoadSourceTypesKey: @(MLMediaSourceTypeImage),
                              MLMediaLoadIncludeSourcesKey: @[MLMediaSourcePhotosIdentifier]
                              };

    self.mediaLibrary = [[MLMediaLibrary alloc] initWithOptions:options];

    [self.mediaLibrary addObserver:self
                        forKeyPath:@"mediaSources"
                           options:0
                           context:(__bridge void *)@"mediaLibraryLoaded"];

    [self.mediaLibrary.mediaSources objectForKey:MLMediaSourcePhotosIdentifier];
}


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
                        change:(NSDictionary *)change context:(void *)context
{
     MLMediaSource *mediaSource = [self.mediaLibrary.mediaSources objectForKey:MLMediaSourcePhotosIdentifier];

    if (context == (__bridge void *)@"mediaLibraryLoaded")
    {
        [mediaSource addObserver:self
                            forKeyPath:@"rootMediaGroup"
                               options:0
                               context:(__bridge void *)@"rootMediaGroupLoaded"];

        [mediaSource rootMediaGroup];
    }
    else if (context == (__bridge void *)@"rootMediaGroupLoaded")
    {
        MLMediaGroup *albums = [mediaSource mediaGroupForIdentifier:@"TopLevelAlbums"];

        for (MLMediaGroup *album in albums.childGroups)
        {
            NSString *albumIdentifier = [album.attributes objectForKey:@"identifier"];

            if ([albumIdentifier isEqualTo:@"allPhotosAlbum"])
            {
                self.allPhotosAlbum = album;

                [album addObserver:self
                        forKeyPath:@"mediaObjects"
                           options:0
                           context:@"mediaObjects"];

                [album mediaObjects];

                break;
            }
        }
    }
    else if (context == (__bridge void *)@"mediaObjects")
    {
        NSArray * mediaObjects = self.allPhotosAlbum.mediaObjects;

        for(MLMediaObject * mediaObject in mediaObjects)
        {
            NSURL * url  = mediaObject.URL;

            NSLog(url.path);
        }
    }
}
like image 37
toohtik Avatar answered Oct 14 '22 16:10

toohtik