UIImagePickerController是iOS系统提供的选取相册图片和进行拍照的视图控制器,可以通过delegate的方法获取UIImage对象,进行后续操作。UIImage对象只是一个图像对象,无法从中获取图像的原始信息,比如原图数据,格式等。
我们来看下UIImagePickerControllerDelegate中的回调方法
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
其中info的信息给访问原始数据提供了可能。info包含的键如下
NSString *const UIImagePickerControllerMediaType ;指定用户选择的媒体类型(文章最后进行扩展)
NSString *const UIImagePickerControllerOriginalImage ;原始图片
NSString *const UIImagePickerControllerEditedImage ;修改后的图片
NSString *const UIImagePickerControllerCropRect ;裁剪尺寸
NSString *const UIImagePickerControllerMediaURL ;媒体的URL
NSString *const UIImagePickerControllerReferenceURL ;原件的URL
NSString *const UIImagePickerControllerMediaMetadata;当来数据来源是照相机的时候这个值才有效
info中的key值
其中UIImagePickerControllerReferenceURL是原始文件的URL,我们可以通过它来访问原始图片信息。这里需要注意的是,这个URL不是沙盒文件路径的URL,而是一个AssetURL,需要系统提供的AssetsLibrary框架进行访问。
ALAssetsLibrary可以实现查看相册列表,增加相册,保存图片到相册等功能。它的组成比较符合照片库本身的组成,照片库中的完整照片库对象、相册、相片都能在 AssetsLibrary 中找到一一对应的组成,这使到 AssetsLibrary 的使用变得直观而方便。
下面来看一下如何通过info信息读取原始图片的数据
NSURL *imageAssetUrl = [info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
[assetLibrary assetForURL:imageAssetUrl resultBlock:^(ALAsset *asset) {
ALAssetRepresentation* representation = [asset defaultRepresentation];
// 创建一个buffer保存图片数据
uint8_t *buffer = (Byte*)malloc(representation.size);
NSUInteger length = [representation getBytes:buffer fromOffset: 0.0 length:representation.size error:nil];
// 将buffer转换为NSData object,然后释放buffer内存
NSData *imageData = [[NSData alloc] initWithBytesNoCopy:buffer length:representation.size freeWhenDone:YES];
} failureBlock:^(NSError *error) {
//失败的处理
}];
这里需要注意的是,读取图片的信息是一个异步操作。
在iOS8以后,苹果提供一套全新的框架PhotoKit来代替ALAssetsLibrary。PhotoKit 是一套比 AssetsLibrary 更完整也更高效的库,对资源的处理跟 AssetsLibrary 也有很大的不同。
下面再来看一下如何使用PhotoKit框架读取原始图片的数据
NSURL *imageAssetUrl = [info objectForKey:UIImagePickerControllerReferenceURL];
PHFetchResult*result = [PHAsset fetchAssetsWithALAssetURLs:@[imageAssetUrl] options:nil];
PHAsset *asset = [result firstObject];
PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
NSData *imageData = imageData;
}];
PHImageRequestOptions中可以指定请求是同步或者异步。
对于AssetsLibrary框架和PhotoKit框架的使用想要深入了解的同学可以参考iOS 开发之照片框架详解。
以上获取原图数据的代码,可以实现类似微信发送原图的功能。
网友评论
fileURL = (info[UIImagePickerControllerReferenceURL] as? URL)!
let source = CGImageSourceCreateWithURL (fileURL! as CFURL, nil)
let sourceProperties = CGImageSourceCopyProperties(source!, nil)
但因为这个fileURL不是URL不是沙盒文件路径的URL,而是一个AssetURL,
请问一下, 是否可以将AssertURL 转换成沙盒文件路径的URL, 或者是否能直接从AssetsLibrary得到source 信息?
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
NSData *imageData = imageData;
}]
为什么啊。好疑惑
PHFetchResult*result = [PHAsset fetchAssetsWithALAssetURLs:@[imageAssetUrl] options:nil];
PHAsset *asset = [result firstObject];
PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
NSData *imageData = imageData;
}]
用这个获取原图数据。。报错
ios Failed to load image data for asset
options.networkAccessAllowed = YES;