Photos Framework を使って写真.appと画像をやりとりする

  • 51
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

iOS8で Photos Framework が追加されました。
Photos Framework は「写真.app」や「iCloud」の写真/ビデオに対し、読み書きやプロパティの編集、変更の監視などができます。
App Extensionが追加されたのもあり、写真やビデオを複数のアプリで扱うための機能が用意されています。

写真.appと画像をやりとりするサンプルを作成してみました

Photos Framework では、 主に3つの階層があってその上でデータをやりとりします。
基本的な読み書きでは、PHAssetCollecitonPHAssetを扱うことになります。

クラス なにを扱うのか
PHCollectionList PHAssetCollectionの集まり
PHAssetCollection カメラロール自体やユーザ作成のフォルダ、モーメントの年など
PHAsset 写真やビデオ自体

アルバムから画像を取得して UIImageView に表示する

- (void)readImage {
    // PHAssetCollection を取得します
    PHAssestCollection * myAlbum = [self getMyAlbum];

    // PHAsset をフェッチします
    PHFetchResult *assets = [PHAsset fetchAssetsInAssetCollection:myAlbum options:nil];

    // フェッチ結果から assets を取り出します
    NSArray * assetArray = [self getAssets:assets];

    // asset を使って、UIImageView をランダムに更新します
    [self updateImageViewWithAsset:assetArray[arc4random() % assets.count]];
}

- (PHAssetCollection *)getMyAlbum {
        // ユーザ作成のアルバム一覧を指定して、PHAssetCollection をフェッチします
    PHFetchResult *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum
                                                                               subtype:PHAssetCollectionSubtypeAlbumRegular
                                                                               options:nil];

    // [My Album]の AssetCollection を取得します
    __block PHAssetCollection * myAlbum;
    [assetCollections enumerateObjectsUsingBlock:^(PHAssetCollection *album, NSUInteger idx, BOOL *stop) {
        if ([album.localizedTitle isEqualToString:@"My Album"]) {
            myAlbum = album;
            *stop = YES;
        }
    }];

    return myAlbum;
}

- (NSArray *)getAssets:(PHFetchResult *)fetch {
    // フェッチ結果を配列に格納します
    __block NSMutableArray * assetArray = NSMutableArray.new;
    [fetch enumerateObjectsUsingBlock:^(PHAsset *asset, NSUInteger idx, BOOL *stop) {
        [assetArray addObject:asset];
    }];
    return assetArray;
}

- (void)updateImageViewWithAsset:(PHAsset *)asset {
    typeof(self) __weak wself = self;
    [[PHImageManager defaultManager] requestImageForAsset:asset
                                               targetSize:CGSizeMake(300,300)
                                              contentMode:PHImageContentModeAspectFill
                                                  options:nil
                                            resultHandler:^(UIImage *result, NSDictionary *info) {
                                                if (result) {
                                                    // imageVivew を更新します
                                                    wself.imageView.image = result;
                                                }
                                            }];
}

アルバムに画像を保存する

「写真.app」へ変更を要求する場合は、xxxChangeRequestというクラスを使用します。
保存するときに、identifierが取得できます。これを使って画像を取り出すこともできます。

- (void)addNewAssetWithImage:(UIImage *)image toAlbum:(PHAssetCollection *)album
{
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // PHAssetChangeRequest を作ります
        PHAssetChangeRequest *createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

        // PHAssetCollectionChangeRequest を作ります
        PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:album];

        // placeholder を取得して、PHAssetCollection に asset を追加します
        PHObjectPlaceholder * placeHolder = [createAssetRequest placeholderForCreatedAsset];
        [albumChangeRequest addAssets:@[ placeHolder ]];

        // placeholder から取得できる identifier を
        // 保存しておくと後から画像を一意に取得することができます
        NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
        [defaults setObject:placeHolder.localIdentifier forKey:kAssetIdentifier];
        [defaults synchronize];

    } completionHandler:^(BOOL success, NSError *error) {
        NSLog(@"Finished adding asset. %@", (success ? @"Success" : error));
    }];
}

保存した画像をアルバムから Identifier で読み込む

getAssets:updateImageViewWithAsset:は上で記述したメソッドです。

- (void)readImageWidthIdentifier {
    // Identifier を指定して PHAsset をフェッチします
    NSString * identifier = [[NSUserDefaults standardUserDefaults]objectForKey:kAssetIdentifier];
    PHFetchResult *assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[identifier] options:nil];

    // assets を取り出します
    NSArray * assetArray = [self getAssets:assets];

    // UIImageView を更新します
    [self updateImageViewWithAsset:assetArray.lastObject];
}

ALAssestLibrary との違いとして、フェッチ結果の取り出しが同期になっているのが使いやすく感じました。
もっと使いこなせるようになっていきたいですね。

サンプルコード

https://github.com/taketomato/photosFWsample

参考URL

Photos Framework 公式ドキュメント
Developers.IO PhotoKit 特集