Xamarin.iOS の PhotoKit

Download Sample コードサ ンプルをダウンロードする

PhotoKit は、アプリケーションでシステム イメージ ライブラリのクエリを実行し、その内容を表示および変更するカスタム ユーザー インターフェイスを作成できるようにする新しいフレームワークです。 これには、画像や動画の資産だけでなく、アルバムやフォルダーなどの資産のコレクションを表す多くのクラスが含まれています。

アクセス許可

アプリが写真ライブラリにアクセスできるようになる前に、ユーザーにアクセス許可ダイアログが表示されます。 Info.plist ファイルには、アプリで写真ライブラリを使用する方法などを説明するテキストを用意する必要があります。これには、次のようなものがあります。

<key>NSPhotoLibraryUsageDescription</key>
<string>Applies filters to photos and updates the original image</string>

モデル オブジェクト

PhotoKit は、モデル オブジェクトと呼ばれるものの中でこれらの資産を表します。 写真や動画自体を表すモデル オブジェクトは PHAsset 型です。 PHAsset には、資産のメディアの種類や作成日などのメタデータが含まれます。 同様に、PHAssetCollection クラスと PHCollectionList クラスには、それぞれ資産コレクションとコレクション リストに関するメタデータが含まれています。 資産コレクションは、特定の年のすべての写真や動画などの資産のグループです。 同様に、コレクション リストは、年ごとにグループ化された写真や動画などの資産コレクションのグループです。

モデル データのクエリ実行

PhotoKit を使用すると、さまざまなフェッチ メソッドを通じてモデル データのクエリを簡単に実行できます。 たとえば、すべてのイメージを取得するには、PHAssetMediaType.Image メディアの種類を渡す PHAsset.Fetch を呼び出します。

PHFetchResult fetchResults = PHAsset.FetchAssets (PHAssetMediaType.Image, null);

その後、PHFetchResult インスタンスにはイメージを表すすべての PHAsset インスタンスが含まれます。 イメージ自体を取得するには、PHImageManager (またはキャッシュ バージョンの PHCachingImageManager) を使用して、RequestImageForAsset を呼び出してイメージの要求を行います。 たとえば、次のコードは、コレクション ビュー セルに表示する PHFetchResult 内の各資産のイメージを取得します。

public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
    var imageCell = (ImageCell)collectionView.DequeueReusableCell (cellId, indexPath);
    imageMgr.RequestImageForAsset (
        (PHAsset)fetchResults [(uint)indexPath.Item],
        thumbnailSize,
        PHImageContentMode.AspectFill, new PHImageRequestOptions (),
        (img, info) => {
            imageCell.ImageView.Image = img;
        }
    );
    return imageCell;
}

これにより、次に示すようにイメージのグリッドが作成されます。

The running app displaying a grid of images

写真ライブラリへの変更の保存

これは、データのクエリ実行と読み取りを処理する方法です。 変更をライブラリに書き戻すこともできます。 関心のある複数のアプリケーションがシステム写真ライブラリとやりとりできるため、PhotoLibraryObserver を使用して変更を通知するオブザーバーを登録できます。 その後変更が行われると、それに応じてアプリケーションを更新できます。 たとえば、上記のコレクション ビューを再読み込みする簡単な実装を次に示します。

class PhotoLibraryObserver : PHPhotoLibraryChangeObserver
{
    readonly PhotosViewController controller;
    public PhotoLibraryObserver (PhotosViewController controller)

    {
        this.controller = controller;
    }

    public override void PhotoLibraryDidChange (PHChange changeInstance)
    {
        DispatchQueue.MainQueue.DispatchAsync (() => {
            var changes = changeInstance.GetFetchResultChangeDetails (controller.fetchResults);
            controller.fetchResults = changes.FetchResultAfterChanges;
            controller.CollectionView.ReloadData ();
        });
    }
}

実際にアプリケーションから変更を書き戻すには、変更要求を作成します。 各モデル クラスには、変更要求クラスが関連付けられています。 たとえば、PHAsset を変更するには、PHAssetChangeRequest を作成します。 写真ライブラリに書き戻され、上記のようなオブザーバーに送信される変更を実行する手順は次のとおりです。

  1. 編集操作を実行します。
  2. フィルター処理されたイメージ データを PHContentEditingOutput インスタンスに保存します。
  3. 編集出力から変更を公開するために変更要求を行います。

Core Image noir フィルターを適用するイメージに変更を書き戻す例を次に示します。

void ApplyNoirFilter (object sender, EventArgs e)
{
    Asset.RequestContentEditingInput (new PHContentEditingInputRequestOptions (), (input, options) => {

        // perform the editing operation, which applies a noir filter in this case
        var image = CIImage.FromUrl (input.FullSizeImageUrl);
        image = image.CreateWithOrientation((CIImageOrientation)input.FullSizeImageOrientation);
        var noir = new CIPhotoEffectNoir {
            Image = image
        };
        var ciContext = CIContext.FromOptions (null);
        var output = noir.OutputImage;
        var uiImage = UIImage.FromImage (ciContext.CreateCGImage (output, output.Extent));
        imageView.Image = uiImage;
        //
        // save the filtered image data to a PHContentEditingOutput instance
        var editingOutput = new PHContentEditingOutput(input);
        var adjustmentData = new PHAdjustmentData();
        var data = uiImage.AsJPEG();
        NSError error;
        data.Save(editingOutput.RenderedContentUrl, false, out error);
        editingOutput.AdjustmentData = adjustmentData;
        //
        // make a change request to publish the changes form the editing output
        PHPhotoLibrary.GetSharedPhotoLibrary.PerformChanges (() => {
            PHAssetChangeRequest request = PHAssetChangeRequest.ChangeRequest(Asset);
            request.ContentEditingOutput = editingOutput;
        },
        (ok, err) => Console.WriteLine ("photo updated successfully: {0}", ok));
    });
}

ユーザーがボタンを選択すると、フィルターが適用されます。

Two examples, showing the photo before and after the filter is applied

また、PHPhotoLibraryChangeObserver により、ユーザーが戻ると、コレクション ビューに変更が反映されます。

Photo collection view showing the modified photo