Xamarin 中的 PhotoKitPhotoKit in Xamarin.iOS

PhotoKit 是一个新的框架,它允许应用程序查询系统映像库并创建自定义用户界面来查看和修改其内容。PhotoKit is a new framework that allows applications to query the system image library and create custom user interfaces to view and modify its contents. 它包括多种类,这些类表示图像和视频资产,以及资产(如影集和文件夹)的集合。It includes a number of classes that represent image and video assets, as well as collections of assets such as albums and folders.

模型对象Model Objects

PhotoKit 在它调用模型对象的内容中表示这些资产。PhotoKit represents these assets in what it calls model objects. 代表照片和视频的模型对象的类型为 PHAssetThe model objects that represent the photos and videos themselves are of type PHAsset. PHAsset 包含元数据(例如资产的媒体类型和其创建日期)。A PHAsset contains metadata such as the asset’s media type and its creation date. 同样,PHAssetCollectionPHCollectionList 类分别包含有关资产集合和集合列表的元数据。Similarly, the PHAssetCollection and PHCollectionList classes contain metadata about asset collections and collection lists respectively. 资产集合是一组资产,例如给定年份的所有照片和视频。Asset collections are groups of assets, such as all the photos and videos for a given year. 同样,收集列表也是一组资产集合,如按年份分组的照片和视频。Likewise, collection lists are groups of asset collections, such as photos and videos grouped by year.

查询模型数据Querying Model Data

使用 PhotoKit 可以轻松地通过各种 fetch 方法来查询模型数据。PhotoKit makes it easy to query model data through a variety of fetch methods. 例如,若要检索所有映像,请调用 PHAsset.Fetch,同时传递 PHAssetMediaType.Image 媒体类型。For example, to retrieve all images, you would call PHAsset.Fetch, passing the PHAssetMediaType.Image media type.

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

然后,PHFetchResult 实例将包含表示图像的所有 PHAsset 实例。The PHFetchResult instance would then contain all the PHAsset instances representing images. 若要获取图像本身,请使用 PHImageManager (或缓存版本 PHCachingImageManager)通过调用 RequestImageForAsset发出对映像的请求。To get the images themselves, you use the PHImageManager (or the caching version, PHCachingImageManager) to make a request for the image by calling RequestImageForAsset. 例如,以下代码将为 PHFetchResult 中的每个资产检索一个图像,以便在 "集合" 视图单元格中显示:For example, the following code retrieves an image for each asset in a PHFetchResult to display in a collection view cell:

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

这会生成图像网格,如下所示:This results in a grid of images as shown below:

保存对照片库所做的更改Saving Changes to the Photo Library

这就是处理查询和读取数据的方法。That’s how to handle querying and reading data. 你还可以将更改写入库。You can also write changes back to the library. 由于多个感兴趣的应用程序能够与系统照片库进行交互,因此你可以注册一个观察者,以便使用 PhotoLibraryObserver 通知更改。Since multiple interested applications are able to interact with the system photo library, you can register an observer to be notified of changes using a PhotoLibraryObserver. 然后,当发生更改时,应用程序可以相应地进行更新。Then, when changes come in, your application can update accordingly. 例如,下面是一个简单的实现,用于重载上面的集合视图:For example, here’s a simple implementation to reload the collection view above:

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

若要实际从你的应用程序中写回更改,你需要创建一个更改请求。To actually write changes back from your application, you create a change request. 每个模型类都具有关联的更改请求类。Each of the model classes has an associated change request class. 例如,若要更改 PHAsset,请创建一个 PHAssetChangeRequest。For example, to change a PHAsset, you create a PHAssetChangeRequest. 执行写回照片库并发送到观察者的更改的步骤如下:The steps to perform changes that are written back to the photo library and sent to observers like the one above are:

  • 执行编辑操作。Perform the editing operation.
  • 将筛选的图像数据保存到 PHContentEditingOutput 实例。Save the filtered image data to a PHContentEditingOutput instance.
  • 发出更改请求,以发布编辑输出中的更改。Make a change request to publish the changes form the editing output.

下面是一个示例,该示例将更改写入到应用核心映像 noir 筛选器的映像:Here’s an example that writes back a change to an image that applies a Core Image noir filter:

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

当用户选择该按钮时,将应用筛选器:When the user selects the button, the filter is applied:

而且,由于 PHPhotoLibraryChangeObserver,当用户向后导航时,该更改将反映在 "集合" 视图中:And thanks to the PHPhotoLibraryChangeObserver, the change is reflected in the collection view when the user navigates back: