| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940 |
- //
- // TZImageManager.m
- // TZImagePickerController
- //
- // Created by 谭真 on 16/1/4.
- // Copyright © 2016年 谭真. All rights reserved.
- //
- #import "TZImageManager.h"
- #import <AssetsLibrary/AssetsLibrary.h>
- #import "TZAssetModel.h"
- #import "TZImagePickerController.h"
- @interface TZImageManager ()
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wdeprecated-declarations"
- @property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
- @end
- @implementation TZImageManager
- static CGSize AssetGridThumbnailSize;
- static CGFloat TZScreenWidth;
- static CGFloat TZScreenScale;
- + (instancetype)manager {
- static TZImageManager *manager;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- manager = [[self alloc] init];
- if (iOS8Later) {
- manager.cachingImageManager = [[PHCachingImageManager alloc] init];
- // manager.cachingImageManager.allowsCachingHighQualityImages = YES;
- }
-
- TZScreenWidth = [UIScreen mainScreen].bounds.size.width;
- // 测试发现,如果scale在plus真机上取到3.0,内存会增大特别多。故这里写死成2.0
- TZScreenScale = 2.0;
- if (TZScreenWidth > 700) {
- TZScreenScale = 1.5;
- }
- });
- return manager;
- }
- - (void)setColumnNumber:(NSInteger)columnNumber {
- _columnNumber = columnNumber;
- CGFloat margin = 4;
- CGFloat itemWH = (TZScreenWidth - 2 * margin - 4) / columnNumber - margin;
- AssetGridThumbnailSize = CGSizeMake(itemWH * TZScreenScale, itemWH * TZScreenScale);
- }
- - (ALAssetsLibrary *)assetLibrary {
- if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init];
- return _assetLibrary;
- }
- /// Return YES if Authorized 返回YES如果得到了授权
- - (BOOL)authorizationStatusAuthorized {
- NSInteger status = [self authorizationStatus];
- if (status == 0) {
- /**
- * 当某些情况下AuthorizationStatus == AuthorizationStatusNotDetermined时,无法弹出系统首次使用的授权alertView,系统应用设置里亦没有相册的设置,此时将无法使用,故作以下操作,弹出系统首次使用的授权alertView
- */
- [self requestAuthorizationWhenNotDetermined];
- }
-
- return status == 3;
- }
- - (NSInteger)authorizationStatus {
- if (iOS8Later) {
- return [PHPhotoLibrary authorizationStatus];
- } else {
- return [ALAssetsLibrary authorizationStatus];
- }
- return NO;
- }
- //AuthorizationStatus == AuthorizationStatusNotDetermined 时询问授权弹出系统授权alertView
- - (void)requestAuthorizationWhenNotDetermined {
- if (iOS8Later) {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
- dispatch_async(dispatch_get_main_queue(), ^{
- });
- }];
- });
- } else {
- [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
- } failureBlock:nil];
- }
- }
- #pragma mark - Get Album
- /// Get Album 获得相册/相册数组
- - (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAlbumModel *))completion{
- __block TZAlbumModel *model;
- if (iOS8Later) {
- PHFetchOptions *option = [[PHFetchOptions alloc] init];
- if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
- if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
- PHAssetMediaTypeVideo];
- // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
- if (!self.sortAscendingByModificationDate) {
- option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
- }
- PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
- for (PHAssetCollection *collection in smartAlbums) {
- // 有可能是PHCollectionList类的的对象,过滤掉
- if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
- if ([self isCameraRollAlbum:collection.localizedTitle]) {
- PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
- model = [self modelWithResult:fetchResult name:collection.localizedTitle];
- if (completion) completion(model);
- break;
- }
- }
- } else {
- [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
- if ([group numberOfAssets] < 1) return;
- NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
- if ([self isCameraRollAlbum:name]) {
- model = [self modelWithResult:group name:name];
- if (completion) completion(model);
- *stop = YES;
- }
- } failureBlock:nil];
- }
- }
- - (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAlbumModel *> *))completion{
- NSMutableArray *albumArr = [NSMutableArray array];
- if (iOS8Later) {
- PHFetchOptions *option = [[PHFetchOptions alloc] init];
- if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
- if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
- PHAssetMediaTypeVideo];
- // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
- if (!self.sortAscendingByModificationDate) {
- option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
- }
- // 我的照片流 1.6.10重新加入..
- PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil];
- PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
- PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
- PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
- PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil];
- NSArray *allAlbums = @[myPhotoStreamAlbum,smartAlbums,topLevelUserCollections,syncedAlbums,sharedAlbums];
- for (PHFetchResult *fetchResult in allAlbums) {
- for (PHAssetCollection *collection in fetchResult) {
- // 有可能是PHCollectionList类的的对象,过滤掉
- if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
- PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
- if (fetchResult.count < 1) continue;
- if ([collection.localizedTitle containsString:@"Deleted"] || [collection.localizedTitle isEqualToString:ASLocalizedString(@"最近删除")]) continue;
- if ([self isCameraRollAlbum:collection.localizedTitle]) {
- [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle] atIndex:0];
- } else {
- [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]];
- }
- }
- }
- if (completion && albumArr.count > 0) completion(albumArr);
- } else {
- [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
- if (group == nil) {
- if (completion && albumArr.count > 0) completion(albumArr);
- }
- if ([group numberOfAssets] < 1) return;
- NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
- if ([self isCameraRollAlbum:name]) {
- [albumArr insertObject:[self modelWithResult:group name:name] atIndex:0];
- } else if ([name isEqualToString:@"My Photo Stream"] || [name isEqualToString:ASLocalizedString(@"我的照片流")]) {
- if (albumArr.count) {
- [albumArr insertObject:[self modelWithResult:group name:name] atIndex:1];
- } else {
- [albumArr addObject:[self modelWithResult:group name:name]];
- }
- } else {
- [albumArr addObject:[self modelWithResult:group name:name]];
- }
- } failureBlock:nil];
- }
- }
- #pragma mark - Get Assets
- /// Get Assets 获得照片数组
- - (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *))completion {
- NSMutableArray *photoArr = [NSMutableArray array];
- if ([result isKindOfClass:[PHFetchResult class]]) {
- PHFetchResult *fetchResult = (PHFetchResult *)result;
- [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- TZAssetModel *model = [self assetModelWithAsset:obj allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
- if (model) {
- [photoArr addObject:model];
- }
- }];
- if (completion) completion(photoArr);
- } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
- ALAssetsGroup *group = (ALAssetsGroup *)result;
- if (allowPickingImage && allowPickingVideo) {
- [group setAssetsFilter:[ALAssetsFilter allAssets]];
- } else if (allowPickingVideo) {
- [group setAssetsFilter:[ALAssetsFilter allVideos]];
- } else if (allowPickingImage) {
- [group setAssetsFilter:[ALAssetsFilter allPhotos]];
- }
- ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (result == nil) {
- if (completion) completion(photoArr);
- }
- TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
- if (model) {
- [photoArr addObject:model];
- }
- };
- if (self.sortAscendingByModificationDate) {
- [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (resultBlock) { resultBlock(result,index,stop); }
- }];
- } else {
- [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (resultBlock) { resultBlock(result,index,stop); }
- }];
- }
- }
- }
- /// Get asset at index 获得下标为index的单个照片
- /// if index beyond bounds, return nil in callback 如果索引越界, 在回调中返回 nil
- - (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *))completion {
- if ([result isKindOfClass:[PHFetchResult class]]) {
- PHFetchResult *fetchResult = (PHFetchResult *)result;
- PHAsset *asset;
- @try {
- asset = fetchResult[index];
- }
- @catch (NSException* e) {
- if (completion) completion(nil);
- return;
- }
- TZAssetModel *model = [self assetModelWithAsset:asset allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
- if (completion) completion(model);
- } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
- ALAssetsGroup *group = (ALAssetsGroup *)result;
- if (allowPickingImage && allowPickingVideo) {
- [group setAssetsFilter:[ALAssetsFilter allAssets]];
- } else if (allowPickingVideo) {
- [group setAssetsFilter:[ALAssetsFilter allVideos]];
- } else if (allowPickingImage) {
- [group setAssetsFilter:[ALAssetsFilter allPhotos]];
- }
- NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index];
- @try {
- [group enumerateAssetsAtIndexes:indexSet options:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (!result) return;
- TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
- if (completion) completion(model);
- }];
- }
- @catch (NSException* e) {
- if (completion) completion(nil);
- }
- }
- }
- - (TZAssetModel *)assetModelWithAsset:(id)asset allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage {
- TZAssetModel *model;
- TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
- if ([asset isKindOfClass:[PHAsset class]]) {
- PHAsset *phAsset = (PHAsset *)asset;
- if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
- else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
- else if (phAsset.mediaType == PHAssetMediaTypeImage) {
- if (iOS9_1Later) {
- // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto;
- }
- // Gif
- if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
- type = TZAssetModelMediaTypePhotoGif;
- }
- }
- if (!allowPickingVideo && type == TZAssetModelMediaTypeVideo) return nil;
- if (!allowPickingImage && type == TZAssetModelMediaTypePhoto) return nil;
- if (!allowPickingImage && type == TZAssetModelMediaTypePhotoGif) return nil;
-
- if (self.hideWhenCanNotSelect) {
- // 过滤掉尺寸不满足要求的图片
- if (![self isPhotoSelectableWithAsset:phAsset]) {
- return nil;
- }
- }
- NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",phAsset.duration] : @"";
- timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
- model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
- } else {
- if (!allowPickingVideo){
- model = [TZAssetModel modelWithAsset:asset type:type];
- return model;
- }
- /// Allow picking video
- if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
- type = TZAssetModelMediaTypeVideo;
- NSTimeInterval duration = [[asset valueForProperty:ALAssetPropertyDuration] integerValue];
- NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration];
- timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
- model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
- } else {
- if (self.hideWhenCanNotSelect) {
- // 过滤掉尺寸不满足要求的图片
- if (![self isPhotoSelectableWithAsset:asset]) {
- return nil;
- }
- }
- model = [TZAssetModel modelWithAsset:asset type:type];
- }
- }
- return model;
- }
- - (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration {
- NSString *newTime;
- if (duration < 10) {
- newTime = [NSString stringWithFormat:@"0:0%zd",duration];
- } else if (duration < 60) {
- newTime = [NSString stringWithFormat:@"0:%zd",duration];
- } else {
- NSInteger min = duration / 60;
- NSInteger sec = duration - (min * 60);
- if (sec < 10) {
- newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec];
- } else {
- newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec];
- }
- }
- return newTime;
- }
- /// Get photo bytes 获得一组照片的大小
- - (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion {
- __block NSInteger dataLength = 0;
- __block NSInteger assetCount = 0;
- for (NSInteger i = 0; i < photos.count; i++) {
- TZAssetModel *model = photos[i];
- if ([model.asset isKindOfClass:[PHAsset class]]) {
- [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
- if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length;
- assetCount ++;
- if (assetCount >= photos.count) {
- NSString *bytes = [self getBytesFromDataLength:dataLength];
- if (completion) completion(bytes);
- }
- }];
- } else if ([model.asset isKindOfClass:[ALAsset class]]) {
- ALAssetRepresentation *representation = [model.asset defaultRepresentation];
- if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size;
- if (i >= photos.count - 1) {
- NSString *bytes = [self getBytesFromDataLength:dataLength];
- if (completion) completion(bytes);
- }
- }
- }
- }
- - (NSString *)getBytesFromDataLength:(NSInteger)dataLength {
- NSString *bytes;
- if (dataLength >= 0.1 * (1024 * 1024)) {
- bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0];
- } else if (dataLength >= 1024) {
- bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0];
- } else {
- bytes = [NSString stringWithFormat:@"%zdB",dataLength];
- }
- return bytes;
- }
- #pragma mark - Get Photo
- /// Get photo 获得照片本身
- - (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion {
- CGFloat fullScreenWidth = TZScreenWidth;
- if (fullScreenWidth > _photoPreviewMaxWidth) {
- fullScreenWidth = _photoPreviewMaxWidth;
- }
- return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
- }
- - (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
- return [self getPhotoWithAsset:asset photoWidth:photoWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
- }
- - (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed {
- CGFloat fullScreenWidth = TZScreenWidth;
- if (fullScreenWidth > _photoPreviewMaxWidth) {
- fullScreenWidth = _photoPreviewMaxWidth;
- }
- return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:progressHandler networkAccessAllowed:networkAccessAllowed];
- }
- - (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed {
- if ([asset isKindOfClass:[PHAsset class]]) {
- CGSize imageSize;
- if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) {
- imageSize = AssetGridThumbnailSize;
- } else {
- PHAsset *phAsset = (PHAsset *)asset;
- CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
- CGFloat pixelWidth = photoWidth * TZScreenScale;
- CGFloat pixelHeight = pixelWidth / aspectRatio;
- imageSize = CGSizeMake(pixelWidth, pixelHeight);
- }
- // 修复获取图片时出现的瞬间内存过高问题
- // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢
- PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
- option.resizeMode = PHImageRequestOptionsResizeModeFast;
- PHImageRequestID imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
- BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
- if (downloadFinined && result) {
- result = [self fixOrientation:result];
- if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
- }
- // Download image from iCloud / 从iCloud下载图片
- if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) {
- PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
- options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (progressHandler) {
- progressHandler(progress, error, stop, info);
- }
- });
- };
- options.networkAccessAllowed = YES;
- options.resizeMode = PHImageRequestOptionsResizeModeFast;
- [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
- UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
- resultImage = [self scaleImage:resultImage toSize:imageSize];
- if (resultImage) {
- resultImage = [self fixOrientation:resultImage];
- if (completion) completion(resultImage,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
- }
- }];
- }
- }];
- return imageRequestID;
- } else if ([asset isKindOfClass:[ALAsset class]]) {
- ALAsset *alAsset = (ALAsset *)asset;
- dispatch_async(dispatch_get_global_queue(0,0), ^{
- CGImageRef thumbnailImageRef = alAsset.thumbnail;
- UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp];
- dispatch_async(dispatch_get_main_queue(), ^{
- if (completion) completion(thumbnailImage,nil,YES);
-
- if (photoWidth == TZScreenWidth || photoWidth == _photoPreviewMaxWidth) {
- dispatch_async(dispatch_get_global_queue(0,0), ^{
- ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
- CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
- UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- if (completion) completion(fullScrennImage,nil,NO);
- });
- });
- }
- });
- });
- }
- return 0;
- }
- /// Get postImage / 获取封面图
- - (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion {
- if (iOS8Later) {
- id asset = [model.result lastObject];
- if (!self.sortAscendingByModificationDate) {
- asset = [model.result firstObject];
- }
- [[TZImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
- if (completion) completion(photo);
- }];
- } else {
- ALAssetsGroup *group = model.result;
- UIImage *postImage = [UIImage imageWithCGImage:group.posterImage];
- if (completion) completion(postImage);
- }
- }
- /// Get Original Photo / 获取原图
- - (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion {
- [self getOriginalPhotoWithAsset:asset newCompletion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
- if (completion) {
- completion(photo,info);
- }
- }];
- }
- - (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
- if ([asset isKindOfClass:[PHAsset class]]) {
- PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init];
- option.networkAccessAllowed = YES;
- [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
- BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
- if (downloadFinined && result) {
- result = [self fixOrientation:result];
- BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue];
- if (completion) completion(result,info,isDegraded);
- }
- }];
- } else if ([asset isKindOfClass:[ALAsset class]]) {
- ALAsset *alAsset = (ALAsset *)asset;
- ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
-
- dispatch_async(dispatch_get_global_queue(0,0), ^{
- CGImageRef originalImageRef = [assetRep fullResolutionImage];
- UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- if (completion) completion(originalImage,nil,NO);
- });
- });
- }
- }
- - (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion {
- if ([asset isKindOfClass:[PHAsset class]]) {
- PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init];
- option.networkAccessAllowed = YES;
- [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
- BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
- if (downloadFinined && imageData) {
- BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue];
- if (completion) completion(imageData,info,isDegraded);
- }
- }];
- } else if ([asset isKindOfClass:[ALAsset class]]) {
- ALAsset *alAsset = (ALAsset *)asset;
- ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
- Byte *imageBuffer = (Byte *)malloc(assetRep.size);
- NSUInteger bufferSize = [assetRep getBytes:imageBuffer fromOffset:0.0 length:assetRep.size error:nil];
- NSData *imageData = [NSData dataWithBytesNoCopy:imageBuffer length:bufferSize freeWhenDone:YES];
- if (completion) completion(imageData,nil,NO);
- }
- }
- #pragma mark - Save photo
- - (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion {
- NSData *data = UIImageJPEGRepresentation(image, 0.9);
- if (iOS9Later) { // 这里有坑... iOS8系统下这个方法保存图片会失败 原来是因为PHAssetResourceType是iOS9之后的...
- [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
- PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
- options.shouldMoveFile = YES;
- [[PHAssetCreationRequest creationRequestForAsset] addResourceWithType:PHAssetResourceTypePhoto data:data options:options];
- } completionHandler:^(BOOL success, NSError * _Nullable error) {
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (success && completion) {
- completion(nil);
- } else if (error) {
-
- NSLog(ASLocalizedString(@"保存照片出错:%@"),error.localizedDescription);
- if (completion) {
- completion(error);
- }
- }
- });
- }];
- } else {
- [self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) {
- if (error) {
- NSLog(ASLocalizedString(@"保存图片失败:%@"),error.localizedDescription);
- if (completion) {
- completion(error);
- }
- } else {
- // 多给系统0.5秒的时间,让系统去更新相册数据
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if (completion) {
- completion(nil);
- }
- });
- }
- }];
- }
- }
- #pragma mark - Get Video
- /// Get Video / 获取视频
- - (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * _Nullable, NSDictionary * _Nullable))completion {
- if ([asset isKindOfClass:[PHAsset class]]) {
- [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
- if (completion) completion(playerItem,info);
- }];
- } else if ([asset isKindOfClass:[ALAsset class]]) {
- ALAsset *alAsset = (ALAsset *)asset;
- ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
- NSString *uti = [defaultRepresentation UTI];
- NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
- AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
- if (completion && playerItem) completion(playerItem,nil);
- }
- }
- #pragma mark - Export video
- /// Export Video / 导出视频
- - (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion {
- if ([asset isKindOfClass:[PHAsset class]]) {
- PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
- options.version = PHVideoRequestOptionsVersionOriginal;
- options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
- options.networkAccessAllowed = YES;
- [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
- // NSLog(@"Info:\n%@",info);
- AVURLAsset *videoAsset = (AVURLAsset*)avasset;
- // NSLog(@"AVAsset URL: %@",myAsset.URL);
- [self startExportVideoWithVideoAsset:videoAsset completion:completion];
- }];
- } else if ([asset isKindOfClass:[ALAsset class]]) {
- NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
- AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
- [self startExportVideoWithVideoAsset:videoAsset completion:completion];
- }
- }
- - (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset completion:(void (^)(NSString *outputPath))completion {
- // Find compatible presets by video asset.
- NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset];
-
- // Begin to compress video
- // Now we just compress to low resolution if it supports
- // If you need to upload to the server, but server does't support to upload by streaming,
- // You can compress the resolution to lower. Or you can support more higher resolution.
- if ([presets containsObject:AVAssetExportPreset640x480]) {
- AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:videoAsset presetName:AVAssetExportPreset640x480];
-
- NSDateFormatter *formater = [[NSDateFormatter alloc] init];
- [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss"];
- NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
- NSLog(@"video outputPath = %@",outputPath);
- session.outputURL = [NSURL fileURLWithPath:outputPath];
-
- // Optimize for network use.
- session.shouldOptimizeForNetworkUse = true;
-
- NSArray *supportedTypeArray = session.supportedFileTypes;
- if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
- session.outputFileType = AVFileTypeMPEG4;
- } else if (supportedTypeArray.count == 0) {
- NSLog(ASLocalizedString(@"No supported file types 视频类型暂不支持导出"));
- return;
- } else {
- session.outputFileType = [supportedTypeArray objectAtIndex:0];
- }
-
- if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) {
- [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil];
- }
-
- AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset];
- if (videoComposition.renderSize.width) {
- // 修正视频转向
- session.videoComposition = videoComposition;
- }
-
- // Begin to export video to the output path asynchronously.
- [session exportAsynchronouslyWithCompletionHandler:^(void) {
- switch (session.status) {
- case AVAssetExportSessionStatusUnknown:
- NSLog(@"AVAssetExportSessionStatusUnknown"); break;
- case AVAssetExportSessionStatusWaiting:
- NSLog(@"AVAssetExportSessionStatusWaiting"); break;
- case AVAssetExportSessionStatusExporting:
- NSLog(@"AVAssetExportSessionStatusExporting"); break;
- case AVAssetExportSessionStatusCompleted: {
- NSLog(@"AVAssetExportSessionStatusCompleted");
- dispatch_async(dispatch_get_main_queue(), ^{
- if (completion) {
- completion(outputPath);
- }
- });
- } break;
- case AVAssetExportSessionStatusFailed:
- NSLog(@"AVAssetExportSessionStatusFailed"); break;
- default: break;
- }
- }];
- }
- }
- /// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
- - (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset {
- if (iOS8Later) {
- return [assets containsObject:asset];
- } else {
- NSMutableArray *selectedAssetUrls = [NSMutableArray array];
- for (ALAsset *asset_item in assets) {
- [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]];
- }
- return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]];
- }
- }
- - (BOOL)isCameraRollAlbum:(NSString *)albumName {
- NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
- if (versionStr.length <= 1) {
- versionStr = [versionStr stringByAppendingString:@"00"];
- } else if (versionStr.length <= 2) {
- versionStr = [versionStr stringByAppendingString:@"0"];
- }
- CGFloat version = versionStr.floatValue;
- // 目前已知8.0.0 - 8.0.2系统,拍照后的图片会保存在最近添加中
- if (version >= 800 && version <= 802) {
- return [albumName isEqualToString:ASLocalizedString(@"最近添加")] || [albumName isEqualToString:@"Recently Added"];
- } else {
- return [albumName isEqualToString:@"Camera Roll"] || [albumName isEqualToString:ASLocalizedString(@"相机胶卷")] || [albumName isEqualToString:ASLocalizedString(@"所有照片")] || [albumName isEqualToString:@"All Photos"];
- }
- }
- - (NSString *)getAssetIdentifier:(id)asset {
- if (iOS8Later) {
- PHAsset *phAsset = (PHAsset *)asset;
- return phAsset.localIdentifier;
- } else {
- ALAsset *alAsset = (ALAsset *)asset;
- NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL];
- return assetUrl.absoluteString;
- }
- }
- /// 检查照片大小是否满足最小要求
- - (BOOL)isPhotoSelectableWithAsset:(id)asset {
- CGSize photoSize = [self photoSizeWithAsset:asset];
- if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) {
- return NO;
- }
- return YES;
- }
- - (CGSize)photoSizeWithAsset:(id)asset {
- if (iOS8Later) {
- PHAsset *phAsset = (PHAsset *)asset;
- return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight);
- } else {
- ALAsset *alAsset = (ALAsset *)asset;
- return alAsset.defaultRepresentation.dimensions;
- }
- }
- #pragma mark - Private Method
- - (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name{
- TZAlbumModel *model = [[TZAlbumModel alloc] init];
- model.result = result;
- model.name = name;
- if ([result isKindOfClass:[PHFetchResult class]]) {
- PHFetchResult *fetchResult = (PHFetchResult *)result;
- model.count = fetchResult.count;
- } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
- ALAssetsGroup *group = (ALAssetsGroup *)result;
- model.count = [group numberOfAssets];
- }
- return model;
- }
- - (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size {
- if (image.size.width > size.width) {
- UIGraphicsBeginImageContext(size);
- [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
- UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return newImage;
- } else {
- return image;
- }
- }
- - (ALAssetOrientation)orientationFromImage:(UIImage *)image {
- NSInteger orientation = image.imageOrientation;
- return orientation;
- }
- /// 获取优化后的视频转向信息
- - (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset {
- AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
- // 视频转向
- int degrees = [self degressFromVideoFileWithAsset:videoAsset];
- if (degrees != 0) {
- CGAffineTransform translateToCenter;
- CGAffineTransform mixedTransform;
- videoComposition.frameDuration = CMTimeMake(1, 30);
-
- NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo];
- AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
-
- if (degrees == 90) {
- // 顺时针旋转90°
- translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0);
- mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);
- videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
- } else if(degrees == 180){
- // 顺时针旋转180°
- translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height);
- mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);
- videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
- } else if(degrees == 270){
- // 顺时针旋转270°
- translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width);
- mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);
- videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
- }
-
- AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
- roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
- AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
-
- [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
-
- roateInstruction.layerInstructions = @[roateLayerInstruction];
- // 加入视频方向信息
- videoComposition.instructions = @[roateInstruction];
- }
- return videoComposition;
- }
- /// 获取视频角度
- - (int)degressFromVideoFileWithAsset:(AVAsset *)asset {
- int degress = 0;
- NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
- if([tracks count] > 0) {
- AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
- CGAffineTransform t = videoTrack.preferredTransform;
- if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
- // Portrait
- degress = 90;
- } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
- // PortraitUpsideDown
- degress = 270;
- } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
- // LandscapeRight
- degress = 0;
- } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
- // LandscapeLeft
- degress = 180;
- }
- }
- return degress;
- }
- /// 修正图片转向
- - (UIImage *)fixOrientation:(UIImage *)aImage {
- if (!self.shouldFixOrientation) return aImage;
-
- // No-op if the orientation is already correct
- if (aImage.imageOrientation == UIImageOrientationUp)
- return aImage;
-
- // We need to calculate the proper transformation to make the image upright.
- // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
- CGAffineTransform transform = CGAffineTransformIdentity;
-
- switch (aImage.imageOrientation) {
- case UIImageOrientationDown:
- case UIImageOrientationDownMirrored:
- transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
- transform = CGAffineTransformRotate(transform, M_PI);
- break;
-
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
- transform = CGAffineTransformRotate(transform, M_PI_2);
- break;
-
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
- transform = CGAffineTransformRotate(transform, -M_PI_2);
- break;
- default:
- break;
- }
-
- switch (aImage.imageOrientation) {
- case UIImageOrientationUpMirrored:
- case UIImageOrientationDownMirrored:
- transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
-
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRightMirrored:
- transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
- default:
- break;
- }
-
- // Now we draw the underlying CGImage into a new context, applying the transform
- // calculated above.
- CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
- CGImageGetBitsPerComponent(aImage.CGImage), 0,
- CGImageGetColorSpace(aImage.CGImage),
- CGImageGetBitmapInfo(aImage.CGImage));
- CGContextConcatCTM(ctx, transform);
- switch (aImage.imageOrientation) {
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- // Grr...
- CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
- break;
-
- default:
- CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
- break;
- }
-
- // And now we just create a new UIImage from the drawing context
- CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
- UIImage *img = [UIImage imageWithCGImage:cgimg];
- CGContextRelease(ctx);
- CGImageRelease(cgimg);
- return img;
- }
- #pragma clang diagnostic pop
- @end
- //@implementation TZSortDescriptor
- //
- //- (id)reversedSortDescriptor {
- // return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate];
- //}
- //
- //@end
|