Xamarin.iOS 中的 PhotoKit

PhotoKit 是一个新的框架,它支持应用程序查询系统图像库并创建自定义用户界面来查看和修改其内容。 它包括多个表示图像和视频资产的类,以及专辑和文件夹等资产集合。

权限

在应用可以访问照片图库之前,系统会向用户显示权限对话框。 必须在 Info.plist 文件中提供说明性文本,以说明应用如何使用照片图库,例如:

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

模型对象

PhotoKit 以其调用模型对象的方式表示这些资产。 表示照片和视频本身的模型对象属于类型 PHAssetPHAsset 包含元数据,例如资产的媒体类型及其创建日期。 同样,PHAssetCollectionPHCollectionList 类分别包含有关资产集合和集合列表的元数据。 资产集合是资产组,例如给定年份的所有照片和视频。 同样,集合列表则是资产集合的组,例如按年份分组的照片和视频。

查询模型数据

PhotoKit 可以轻松地通过各种提取方法查询模型数据。 例如,要检索所有图像,需要调用 PHAsset.Fetch,从而传递 PHAssetMediaType.Image 媒体类型。

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

这会生成如下所示的图像网格:

显示图像网格的正在运行的应用

保存对照片图库的更改

这就是如何处理查询和读取数据。 还可以将更改写回到库。 由于多个感兴趣的应用程序能够与系统照片图库交互,因此可以使用 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. 发出更改请求以从编辑输出发布更改。

以下示例将更改写回到应用核心映像 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));
    });
}

当用户选择按钮时,将应用该筛选器:

显示应用筛选器前后的照片的两个示例

由于 PHPhotoLibraryChangeObserver 的原因,当用户导航返回时,更改将反映在集合视图中:

显示已修改的照片的照片集合视图