澳门京葡网站iOS 版将充分利用 iPad 的强大性能,我们可以用PHAsset保存图片和视频资源对象

澳门京葡网站 8

又一个跟PS叫板的修图应用来到iOS上。

1. Model

PHAsset 、PHAssetCollection、PHCollectionList
是Photos框架中的模型类,PHAsset类模型是图片或者视频文件数据;PHAssetCollection即图片或者视频文件的集合,包括相册、moments、智能相册以及共享照片流;PHCollectionList是一组资源集合,可能是一组Assets,也可能是一组collection。
它们关系如下图:

澳门京葡网站 1

photos_model.png

澳门京葡网站 2

1.1 PHAsset

PHAsset是iOS8平台的新接口,用来获取图片和视频文件的元数据,相当于以前的
ALAsset接口,但比起ALAsset,PhotoKit
提供了额外的关于用户资源的元数据,而这些数据在以前使用 ALAssetsLibrary
框架中是没有办法访问,或者很难访问到。我们可以用PHAsset保存图片和视频资源对象,
然后展示或者修改它.它有几个重要属性:

  • mediaType :资源类型,图片或者音频或视频

    澳门京葡网站 3

    Paste_Image.png

  • mediaSubtypes
    :图片又包含全景图(Panorama)、HDR图片、屏幕截图、livePhoto.live
    photo 加3Dtouch效果太赞! [视频链接].我们可以使用照片资源的
    mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了
    HDR,拍摄时是否使用了相机应用的全景模式.(澳门京葡网站 ,http://www.macworld.com/article/2988585/apple-phone/how-to-get-started-with-3d-touch-live-photos-and-4k-video-on-the-iphone-6s.html)

    澳门京葡网站 4

    Paste_Image.png

  • Creation date

  • Location

  • Favorite
    布尔值,用户是否标记资源为”收藏”,我们平时浏览照片或视频,在下方点💗就表示收藏这张图。

  • hidden 要验证一个资源是否被用户标记为收被隐藏,只要检查 PHAsset
    实例的 hidden 属性即可。

  • sourceType : 资源可以来源自用户相册、iCloud、iTunes同步

    澳门京葡网站 5

    Paste_Image.png

  • representsBurstburstSelectionTypes: 对于一个资源,如果其
    PHAsset 的 representsBurst 属性为
    true,则表示这个资源是一系列连拍照片中的代表照片
    (多张照片是在用户按住快门时拍摄的)。它还有一个属性是
    burstIdentifier,如果想要获取连拍照片中的剩余的其他照片,可以通过将这个值传入
    fetchAssetsWithBurstIdentifier(…)
    方法来获取。用户可以在连拍的照片中做标记;此外,系统也会自动用各种试探来标记用户可能会选择的潜在代表照片。这个元数据是可以通过
    PHAsset 的 burstSelectionTypes
    属性来访问。这个属性是用三个常量组成的位掩码:.UserPick
    表示用户手动标记的资源,.AutoPick 表示用户可能标记的潜在资源,.None
    表示没有标记的资源。

澳门京葡网站 6

Paste_Image.png

我模拟器相册中某张图片:

<PHAsset: 0x7f8293659e20> B84E8479-475C-4727-A4A4-B77AA9980897/L0/001 mediaType=1/0, sourceType=1, (4288x2848), creationDate=2009-10-09 21:09:20 +0000, location=0, hidden=0, favorite=0

著名图像编辑应用 Pixelmator 开发团队计划在下周正式面向 iOS
平台推出其桌面级图像编辑应用 Pixelmator Photo。

localIdentifier

Photos
框架中的根类PHObject只有一个公开接口localIdentifier,是对象唯一唯一标志符.PHObject实现了-isEqual
和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象。
在我的模拟器中“最近删除”这个相册的localIdentifier为72053882-BF20-4D4A-B1A5-03D1DDAE1707/L0/040

Pixelmator Photo 与 Pixelmator
系列不同,从名称就可以看出来,前者主要针对的是照片。这款应用最初出现在苹果新
iPad Pro
的发布会上,当时它利用了苹果高端平板的强大功能,旨在提供可以直接在苹果平板上对照片进行桌面级修改所需的所有工具。

1.2 PHAssetCollection

PHAssetCollection是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.它的重要属性

  • assetCollectionType 资源集合类型,比如相册或者“时刻”相册

typedef NS_ENUM(NSInteger, PHAssetCollectionType) {
PHAssetCollectionTypeAlbum = 1,
PHAssetCollectionTypeSmartAlbum = 2,
PHAssetCollectionTypeMoment = 3,} 
NS_ENUM_AVAILABLE_IOS(8_0);
  • assetCollectionSubtype 子类型

enum PHAssetCollectionType : Int { 
case Album //从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册 
case SmartAlbum //经由相机得来的相册 
case Moment //Photos 为我们自动生成的时间分组的相册
}

enum PHAssetCollectionSubtype : Int { 
case AlbumRegular //用户在 Photos 中创建的相册 
case AlbumSyncedEvent //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。
case AlbumSyncedFaces //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
case AlbumSyncedAlbum //做了 AlbumSyncedEvent 应该做的事 
case AlbumImported //从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。 
case AlbumMyPhotoStream //用户的 iCloud 照片流 
case AlbumCloudShared //用户使用 iCloud 共享的相册 
case SmartAlbumGeneric //文档解释为非特殊类型的相册,主要包括从 iPhoto 同步过来的相册。 
case SmartAlbumPanoramas //相机拍摄的全景照片 
case SmartAlbumVideos //相机拍摄的视频 
case SmartAlbumFavorites //收藏文件夹 
case SmartAlbumTimelapses //延时视频文件夹,同时也会出现在视频文件夹中 
case SmartAlbumAllHidden //包含隐藏照片或视频的文件夹 
case SmartAlbumRecentlyAdded //相机近期拍摄的照片或视频 
case SmartAlbumBursts //连拍模式拍摄的照片  
case SmartAlbumUserLibrary //这个命名最神奇了,就是相机相册,所有相机拍摄的照片或视频都会出现在该相册中,而且使用其他应用保存的照片也会出现在这里。 
case Any //包含所有类型
}
  • startDate

  • endDate

  • estimatedAssetCount :估算的asset数量,不精确我模拟器
    智能相册里,“最近删除”这个相册的对象信息

<PHAssetCollection: 0x7f82951bd640> 72053882-BF20-4D4A-B1A5-03D1DDAE1707/L0/040 Recently Deleted assetCollectionType=2/1000000201

据悉,iOS 版将充分利用 iPad 的强大性能,通过 Core ML
机器学习技术来对图像调整和裁剪进行辅助。和 Mac 版有所不同的是,面向 iPad
的版本将专注于照片修饰,该有的照片调整功能一应俱全,另外还新增了「Repair
and
Crop」工具可以帮助用户实现更完美的照片,比如从照片中抹除瑕疵甚至更大的对象。还可支持超过
500 种相机的 RAW 格式。

1.3 PHCollectionList

一组有序的资源集合的集合,暂时还没用过。几个重要属性:

  • collectionListType
  • collectionListSubtype
  • startDate
  • endDate

澳门京葡网站 7

2. 获取模型数据

PHAsset
、PHCollection、PHCollectionList有一系列类方法可供我们访问资源的元数据

目前 Pixelmator Photo 正在进行预订,售价 25 元,提前购买的用户可以在 4
月 9 日正式上架时第一时间自动下载安装。

2.1 比如PHAsset提供了一系列获取资源对象的方法

+ fetchAssetsInAssetCollection:options:+
fetchAssetsWithMediaType:options:+
fetchAssetsWithLocalIdentifiers:options:+
fetchKeyAssetsInAssetCollection:options:+ 
fetchAssetsWithOptions:+ 
fetchAssetsWithBurstIdentifier:options:+
fetchAssetsWithALAssetURLs:options:

其中fetchAssetsInAssetCollection:options:方法可以获取资源集合中的所有asset对象。每个方法中的
PHFetchOptions参数,是获取asset对象的一些配置,我们可以设置获取asset的条件,比如获取哪种资源,如何分类。获取的时候,如果该参数为空,则使用系统的默认值,当我们调用如上所示方法获取时,可以直接传nil。
例子:

PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init]; 
// 按图片生成时间排序
allPhotosOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 
// 获取图片 
PHFetchResult *allPhotos = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
// 获取智能相册
PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 获取用户创建的相册 
PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];

2.2 PHFetchOptions

  • predicate : 做选择的约束条件。比如,只获取图片,不获取视频。指定
    PHAssetMediaType为image.

// swift:
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue)
  • sortDescriptors 可指定字段用来对获取结果进行排序

  • includeHiddenAssets 获取结果是否包括被隐藏的资源

  • includeAllBurstAssets 获取结果是否包括连拍资源

PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.wantsIncrementalChangeDetails = YES;
options.includeAllBurstAssets = YES;
options.includeHiddenAssets = YES;
// 只取图片
options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeImage];
// 按时间排序
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumAllHidden options:nil];

2.3 PHFetchResult

类似数组,存储获取到asset对象集合。

  • 同步快速获取结果,
  • 即使结果集很大,框架也能保证获取速度.
    因为它不会一次性将所有结果放进内存,而是按需批量加载
  • 可以用类似 NSArray 的接口来访问PHFetchResult结果内的集合。
    比如 :

3. 资源对象的增删改

上面PHAsset PHAssetCollection
PHCollectionList对象都是不可改变的。那么我们如何实现资源增删改呢?要借助
request API :

澳门京葡网站 8

request.png

比如:这段代码用来修改一张图片的资源属性:是否被收藏。

// 创建
    request = [PHAssetChangeRequest creationRequestForAssetFromImage:image]

    - (void)toggleFavoriteForAsset:(PHAsset *)asset {
        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            // 改变
            PHAssetChangeRequest *request = [PHAssetChangeRequest changeRequestForAsset:asset];
            request.favorite = !asset.favorite;
        } completionHandler:^(BOOL success, NSError *error) {
            NSLog(@"Finished updating asset. %@", (success ? @"Success." : error));
        }];
    }

(1)
创建PHAssetChangeRequest对象。想要修改资源,需要创建一个PHAssetChangeRequest
。然后你就可以修改创建创建日期,资源位置,以及是否将隐藏资源,是否将资源看做用户收藏等。此外,你还可以从用户的库里删除资源。类似地,若要修改资源集合或集合列表,需要创建一个
PHAssetCollectionChangeRequest或
PHCollectionListChangeRequest对象。然后你就可以修改集合标题,添加或删除集合成员,或者完全删除集合。
(2)
操作的请求都要求在PHPhotoLibrary的performChanges的changeBlock中执行
(3)如果有更新UI操作,需要遵守PHPhotoLibraryChangeObserver
协议,实现photoLibraryDidChange(changeInfo:
PHChange!)方法.在photoLibraryDidChange中进行UI更新操作。
比如,下面2段代码用来向册中新增一张图片:

// 为image对象生成PHAsset对象,并加入collection
   [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
       PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];

       if (self.assetCollection) {
           PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
           [assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
       }
   } completionHandler:^(BOOL success, NSError *error) {
       if (!success) {
           NSLog(@"Error creating asset: %@", error);
       }
   }];

创建一个新资源只要用
creationRequestForAssetFromXXX(…)工厂方法,来创建变化请求,并传入资源图像数据
(或一个
URL)。如果你需要对新建的资源做额外的修改,你可以用创建变化请求的placeholderForCreatedAsset属性。它会返回一个可用的
placeholder 来代替“真实的” PHAsset 引用.

// PHPhotoLibraryChangeObserver协议的方法,更新相册UI
    - (void)photoLibraryDidChange:(PHChange *)changeInstance {
        // Check if there are changes to the assets we are showing.
        PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.assetsFetchResults];
        if (collectionChanges == nil) {
            return;
        }

        /*
         Change notifications may be made on a background queue. Re-dispatch to the
         main queue before acting on the change as we'll be updating the UI.
         */
        dispatch_async(dispatch_get_main_queue(), ^{
            // Get the new fetch result.
            self.assetsFetchResults = [collectionChanges fetchResultAfterChanges];

            UICollectionView *collectionView = self.collectionView;

            if (![collectionChanges hasIncrementalChanges] || [collectionChanges hasMoves]) {
                // Reload the collection view if the incremental diffs are not available
                [collectionView reloadData];

            } else {
                /*
                 Tell the collection view to animate insertions and deletions if we
                 have incremental diffs.
                 */
                [collectionView performBatchUpdates:^{
                    NSIndexSet *removedIndexes = [collectionChanges removedIndexes];
                    if ([removedIndexes count] > 0) {
                        [collectionView deleteItemsAtIndexPaths:[removedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                    }

                    NSIndexSet *insertedIndexes = [collectionChanges insertedIndexes];
                    if ([insertedIndexes count] > 0) {
                        [collectionView insertItemsAtIndexPaths:[insertedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                    }

                    NSIndexSet *changedIndexes = [collectionChanges changedIndexes];
                    if ([changedIndexes count] > 0) {
                        [collectionView reloadItemsAtIndexPaths:[changedIndexes aapl_indexPathsFromIndexesWithSection:0]];
                    }
                } completion:NULL];
            }

            [self resetCachedAssets];
        });
    }

3.1 PHPhotoLibrary

系统中PHPhotoLibrary单例对象
是用来维护用户照片库。当我们需要编辑资源对象元数据、资源内容、或者插入新的资源对象等,都可以借助通过PHPhotoLibrary单例对象执行block,block中创建我们指定的请求对象(比如PHAssetChangeRequest,PHAssetCollectionChangeRequest,
PHCollectionListChangeRequest的对象)。photoLibraryDidChange(changeInfo:
PHChange!)中进行.