點擊下載 Demo
注意??:內存有泄露,暫時沒時間修復,使用需慎重哈
一、獲取照片
1、開啟相冊權限
首先,需在工程對應的plist文件內添加“Privacy - Photo Library Usage Description”這個key,同時設置其值為“App needs your permission to access the Photo”類似這樣的說明。
// 獲取當前App的相冊授權狀態
PHAuthorizationStatus authorizationStatus = [PHPhotoLibrary authorizationStatus];
// 判斷授權狀態
if (authorizationStatus == PHAuthorizationStatusAuthorized) {
// 如果已經授權, 獲取圖片
[self getAllAsset];
}
// 如果沒決定, 彈出指示框, 讓用戶選擇
else if (authorizationStatus == PHAuthorizationStatusNotDetermined) {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
// 如果用戶選擇授權, 則獲取圖片
if (status == PHAuthorizationStatusAuthorized) {
[self getAllAsset];
}
}];
} else {
[self noticeAlert];
}
2、獲取相簿中的PHAsset對象
PHAsset: 代表照片庫中的一個資源,跟 ALAsset 類似,通過 PHAsset 可以獲取和保存資源
PHFetchOptions: 獲取資源時的參數,可以傳 nil,即使用系統默認值
PHFetchResult: 表示一系列的資源結果集合,也可以是相冊的集合,從 PHCollection 的類方法中獲得
// 獲取所有資源的集合,并按資源的創建時間排序
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate"
ascending:NO]];
PHFetchResult *result = [PHAsset fetchAssetsWithOptions:options];
3、獲取相片
PhotoKit 無法直接從 PHAsset 的實例中獲取圖像,而是引入了一個管理器?PHImageManager 獲取圖像。PHImageManager 是通過請求的方式拉取圖像,并可以控制請求得到的圖像的尺寸、剪裁方式、質量,緩存以及請求本身的管理(發出請求、取消請求)等。而請求圖像的方法是 ?PHImageManager 的一個實例方法。
// 篩選本地圖片,過濾視頻、iCloud圖片
PHAsset *asset = self.assetArr[index];
if (asset.mediaType != PHAssetMediaTypeImage || asset.sourceType != PHAssetSourceTypeUserLibrary) {
[self requestImageWithIndex:index+1];
return;
}
// 請求圖像的屬性
PHImageRequestOptions *imageOpt = [[PHImageRequestOptions alloc] init];
// resizeMode 屬性控制圖像的剪裁
imageOpt.resizeMode = PHImageRequestOptionsResizeModeNone;
// deliveryMode 則用于控制請求的圖片質量
imageOpt.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
// 獲取縮率圖
PHImageManager *mgr = [PHImageManager defaultManager];
__weak typeof(self) weakSelf = self;
[mgr requestImageForAsset:asset
targetSize:CGSizeMake(125, 125)
contentMode:PHImageContentModeDefault
options:imageOpt
resultHandler:^(UIImage *result, NSDictionary *info) {
[weakSelf getImageSizeWithIndex:index
image:result];
}];
- asset,圖像對應的 PHAsset。
- targetSize,需要獲取的圖像的尺寸,如果輸入的尺寸大于資源原圖的尺寸,則只返回原圖。需要注意在 PHImageManager 中,所有的尺寸都是用 Pixel 作為單位(Note that all sizes are in pixels),因此這里想要獲得正確大小的圖像,需要把輸入的尺寸轉換為 Pixel。如果需要返回原圖尺寸,可以傳入 PhotoKit 中預先定義好的常量?PHImageManagerMaximumSize,表示返回可選范圍內的最大的尺寸,即原圖尺寸。
- contentMode,圖像的剪裁方式,與?UIView 的 contentMode 參數相似,控制照片應該以按比例縮放還是按比例填充的方式放到最終展示的容器內。注意如果 targetSize 傳入?PHImageManagerMaximumSize,則 contentMode 無論傳入什么值都會被視為?PHImageContentModeDefault。
- options,一個?PHImageRequestOptions 的實例,可以控制的內容相當豐富,包括圖像的質量、版本,也會有參數控制圖像的剪裁,下面再展開說明。
- resultHandler,請求結束后被調用的 block,返回一個包含資源對于圖像的 UIImage 和包含圖像信息的一個 NSDictionary,在整個請求的周期中,這個 block 可能會被多次調用,關于這點連同 options 參數在下面展開說明。
參考鏈接:http://kayosite.com/ios-development-and-detail-of-photo-framework-part-two.html
3、獲取相片原圖大小
這里獲取的是相片原圖的數據大小,請求參數與獲取圖片類似,可參考上面
PHImageRequestOptions *sizeOpt = [[PHImageRequestOptions alloc] init];
sizeOpt.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
sizeOpt.resizeMode = PHImageRequestOptionsResizeModeExact;
__weak typeof(self) weakSelf = self;
PHImageManager *mgr = [PHImageManager defaultManager];
[mgr requestImageDataForAsset:self.assetArr[index]
options:sizeOpt
resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
[weakSelf dealImageWithIndex:index
image:image
imageData:imageData];
}];
二、存儲照片
1、保存圖片到系統相冊
此方法可以直接保存在系統相冊的"相機膠卷"中
- (void)save {
// 存儲圖片到"相機膠卷"
UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
// 成功保存圖片到相冊中, 必須調用此方法, 否則會報參數越界錯誤
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
if (error) {
NSLog(@"保存失敗");
} else {
NSLog(@"保存成功");
}
}
2、保存圖片到自定義相冊
首先根據相簿名獲取相簿,然后將圖片存入到相簿中。詳情可參考:http://www.lxweimin.com/p/1b3616945fc3
三、刪除照片
/// 刪除照片
+ (void)deleteAssets:(NSArray<PHAsset *> *)assets completionHandler:(void (^)(BOOL success, NSError *error))completion {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:assets];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (completion) {
dispatch_async(dispatch_get_main_queue(), ^{
completion(success, error);
});
}
}];
}
四、相似照片
判斷照片的相似度,可分為五步:
1、縮小尺寸
2、簡化色彩
3、計算平均值
4、比較像素的灰度
5、計算哈希值
原理介紹參考:http://www.lxweimin.com/p/8c3296ba6522
使用opencv判斷相似度:http://www.qingpingshan.com/rjbc/ios/202983.html
iOS,OC,圖片相似度比較,圖片指紋:http://www.cnblogs.com/kongkaikai/p/5251543.html
五、壓縮照片
壓縮圖片不能壓縮到指定大小,有誤差,只能計算近似值。這里通過遞歸的方法,壓縮到小于1.5M
// 壓縮圖片 小于1.5M -- 先壓縮大小再壓縮數據
+ (NSDictionary *)compressData:(NSData *)imageData {
NSUInteger imageSize = imageData.length;
UIImage *image = [UIImage imageWithData:imageData];
NSLog(@"圖片壓縮前 data: %.2fMB, size:%@", imageData.length / 1024.0 / 1024.0, NSStringFromCGSize(image.size));
// 壓縮率
CGFloat rate = 1024 * 1024.0 / imageSize;
// 大小壓縮
CGSize size = CGSizeMake(image.size.width * rate, image.size.height * rate);
UIImage *img2 = [self imageWithImage:image scaledToSize:size];
NSData *data2 = UIImageJPEGRepresentation(img2, 1);
NSLog(@"大小壓縮后 data: %.2fMB, size:%@", data2.length / 1024.0 / 1024.0, NSStringFromCGSize(size));
if (data2.length > 1024 * 1024 * 1.5) {
// 數據壓縮
NSData *data = UIImageJPEGRepresentation(img2, rate);
UIImage *img = [UIImage imageWithData:data];
NSLog(@"數據壓縮后 data: %.2fMB, size:%@", data.length / 1024.0 / 1024.0, NSStringFromCGSize(img.size));
if (data.length > 1024 * 1024 * 1.5) {
return [self compressData:data];
} else {
return @{@"image":img, @"length":@(data.length)};
}
} else {
return @{@"image":img2, @"length":@(data2.length)};
}
}