TZImagePickerController|TZImagePickerController 拍照返回的照片错误问题
项目中需要用到相册,自己封装比较耗时,所以选择了现成的第三方SDK,选来选去(其实也没怎么选)最终选择了TZImagePickerController(以下简称TZImage)。很舒服的一个开源相册,功能还是很强大,在此膜拜一下作者。
【TZImagePickerController|TZImagePickerController 拍照返回的照片错误问题】那么说一说我在使用时遇到的一个小问题,如题:
bug:当系统相册中出现“来自未来的照片”(相册中有照片的存储时间是未来的某个时间,原因暂时未知,可能是用户在拍照时自行修改了iPhone的时间),使用TZImage的拍照功能会出现最终得到的照片不是拍照获得的照片问题。(有点拗口,应该能理解吧)
问题原因(想看解决方法的同学们可以跳过):TZImage拍照完成之后,会将照片按照当前拍摄时间存入本地相册,然后更新相册,再从相册中取出当前排序的第一张照片返回给我们。而一般来说,相册的排序都是按照时间来排的,不论你是选择正序还是倒序,所以在正常情况下这样做是毫无问题的。但就是有时候是不正常的。就像我上面描述所说的:系统相册中出现来自未来的照片,这种情况下,TZImage拍照后获得的照片永远都是相册中的第一张照片。然而我们拍摄得到的照片是当前时间,肯定不会被放在相册的第一张了,也就出现了所拍不所得的问题。(很尴尬)
既然发现的问题的原因,那么解决起来就方便多了。先来说说我的思路,其实这个问题不算很难解决,我能想到3种解决方法。(原谅我这个菜鸡就这点水平)
1、在TZImage拍摄完照片的代理中取到当前拍摄的照片,使用block或者代理传递到我们需要的地方,跳过存储和更新相册的过程。
这种方案简单暴力,解决起来应该是最快的方式。可是对于后续的需求就会造成不便,我们知道在相机的回调中通过此方法获得的照片是原图
文章图片
所以对于一些诸如头像设置之类的不需要图片质量那么大的情况下,原图会造成一些不必要的流量操作,网络不好的话用户体验也会受到一定影响。当然我们可以在这里就对图片进行压缩处理,但是这种处理方式显然不是最好的。
2、在TZImage存储照片的时候,对存储的时间进行调整。
这种处理方式也很简单,而且无需更多的操作,只是简单的修改一下照片的时间属性。
文章图片
只需要在这里将[NSDate date]改成一个相对靠后的时间,你不是来自未来的照片吗,我让你知道什么是未来,设置一个2100年,什么?还不够。那就2200年,总之我就是要我拍摄的照片放在相册的第一个,怎么说?
文章图片
皮一下很舒服。好了,言归正传,这种处理方式显然也是有问题的,到时候因为一个APP导致手机里一堆搞不清楚时间的照片,就皮不起来了。
3、也是我目前能想到的最好的解决方式。当照片存储完成之后,通过照片的localIdentifier获取到照片的PHAsset(iOS 8之前获取ALAsset),再通过PHAsset/ALAsset,获取到TZAssetModel(TZImage自己的图片对象),接着在更新相册的方法中,把我们刚才获取到的Model传进来(推荐block),不再使用TZImage原先的方式取值,把我们自己获取到的Model存入回调数组中,万事大吉。
说起来很抽象?上代码:
文章图片
我将TZImage的savePhotoWithImage:location:completion方法的block进行了调整,新增了一个返回值TZAssetModel *assetModel。在savePhotoWithImage:location:completion方法中将其获取并传递回来:
- (void)savePhotoWithImage:(UIImage*)image location:(CLLocation*)location completion:(getCurrentPhotos)completion {最后,修改排序的方法:
__blockTZAssetModel*model =nil;
__blockNSString*idStr =nil;
if (iOS8Later) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
if(iOS9Later) {
NSData*data =https://www.it610.com/article/UIImageJPEGRepresentation(image,0.9);
PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
options.shouldMoveFile=YES;
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
[requestaddResourceWithType:PHAssetResourceTypePhoto data:data options:options];
if(location) {
request.location= location;
}
request.creationDate= [NSDatedate];
idStr = request.placeholderForCreatedAsset.localIdentifier;
}else{
PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
if(location) {
request.location= location;
}
request.creationDate= [NSDatedate];
idStr = request.placeholderForCreatedAsset.localIdentifier;
}
}completionHandler:^(BOOLsuccess,NSError*error) {
dispatch_async(dispatch_get_main_queue(), ^{
if(success && completion) {
PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[idStr] options:nil];
if(result) {
PHAsset*asset = [resultlastObject];
model = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypePhoto];
}
completion(model,nil);
}elseif(error) {
NSLog(@"保存照片出错:%@",error.localizedDescription);
if(completion) {
completion(model, error);
}
}
});
}];
}else{
[self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) {
if(error) {
NSLog(@"保存图片失败:%@",error.localizedDescription);
if(completion) {
completion(model, error);
}
}else{
// 多给系统0.5秒的时间,让系统去更新相册数据
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if(completion) {
[self.assetLibraryassetForURL:assetURLresultBlock:^(ALAsset*asset) {
model = [TZAssetModel modelWithAsset:assetURL type:TZAssetModelMediaTypePhoto];
completion(model,nil);
}failureBlock:^(NSError*error) {
completion(model,nil);
}];
}
});
}
}];
}
}
- (void)reloadPhotoArray:(TZAssetModel*)currentAssetModel {原谅我把注释掉的代码也贴上来了,主要是方便以后我查看自己修改的部分。
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
[[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) {
_model= model;
[[TZImageManager manager] getAssetsFromFetchResult:_model.result completion:^(NSArray *models) {
[tzImagePickerVchideProgressHUD];
TZAssetModel*assetModel = currentAssetModel;
if(tzImagePickerVc.sortAscendingByModificationDate) {
//assetModel = [models lastObject];
[_modelsaddObject:assetModel];
}else{
//assetModel = [models firstObject];
[_modelsinsertObject:assetModelatIndex:0];
}
if(tzImagePickerVc.maxImagesCount<=1) {
if(tzImagePickerVc.allowCrop) {
TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
//if (tzImagePickerVc.sortAscendingByModificationDate) {
//photoPreviewVc.currentIndex = _models.count - 1;
//} else {
//photoPreviewVc.currentIndex = 0;
//}
photoPreviewVc.currentIndex= [_modelsindexOfObject:assetModel];
photoPreviewVc.models=_models;
[selfpushPhotoPrevireViewController:photoPreviewVc];
}else{
[tzImagePickerVc.selectedModelsaddObject:assetModel];
[selfdoneButtonClick];
}
return;
}
if(tzImagePickerVc.selectedModels.count< tzImagePickerVc.maxImagesCount) {
assetModel.isSelected=YES;
[tzImagePickerVc.selectedModelsaddObject:assetModel];
[self refreshBottomToolBarStatus];
}
_collectionView.hidden=YES;
[_collectionViewreloadData];
_shouldScrollToBottom = YES;
[self scrollCollectionViewToBottom];
}];
}];
}
PS:第一次写。而且技术有限,只能分享一下自己解决问题的思路和最后的成果。大佬们若发现什么问题,请多多指正,我需要你们的鞭策。鞭。。。。策(哪里怪怪的)
推荐阅读
- 拍照一年啦,如果你想了解我,那就请先看看这篇文章
- 前端代码|前端代码 返回顶部 backToTop
- 后端返回image的Buffer,显示图片
- 使用sqlalchemy|使用sqlalchemy orm 的model序列化,解决返回model的异常
- 【数组题】给定一个二进制矩阵|【数组题】给定一个二进制矩阵 A,我们想先水平翻转图像,然后反转图像并返回结果。
- RF接口返回数据验证举例
- 三行代码禁用侧滑返回
- SpringMVC返回的ResponseEntity出现乱码及解决
- 和春天有个约会(六)
- GoWeb开发_Iris框架讲解(二)(Get、Post、Put等请求及数据返回格式)