您的位置:首页 > 移动开发 > IOS开发

iOS开发之获取系统相册中的图片与视频教程(内带url转换)

2016-11-07 15:30 991 查看

好些天没写点东西了,最近公司要做新项目,有点小忙。不想我的坚持就此中断,我把我前些天研究的东西拿出来给大家看看。

这次整理的是AssetsLibrary和PhotoKit的使用。本人处女座,有点强迫症,之前写的项目里用的是AssetsLibrary写的调取相册内的媒体文件,但是Xcode总是报警告错误,虽然能够编译并展示效果,但是十几个警告错误挂在那,心里总不是滋味,所以我就研究了一下AssetLibrary和PhotoKit。

在 iOS 8 出现之前,开发者只能使用 AssetsLibrary 框架来访问设备的照片库,这是一个有点跟不上 iOS 应用发展步伐以及代码设计原则但确实强大的框架,考虑到 iOS7 仍占有不少的渗透率,因此 AssetsLibrary 也是本文重点介绍的部分。而在 iOS8 出现之后,苹果提供了一个名为 PhotoKit 的框架,一个可以让应用更好地与设备照片库对接的框架。

一、AssetsLibrary 组成

AssetsLibrary 的组成比较符合照片库本身的组成,照片库中的完整照片库对象、相册、相片都能在 AssetsLibrary 中找到一一对应的组成,这使到 AssetsLibrary 的使用变得直观而方便。想要了解AssetsLibrary得从它的类开始。

AssetsLibrary: 代表整个设备中的资源库(照片库),通过 AssetsLibrary 可以获取和包括设备中的照片和视频

  • ALAssetsGroup: 映射照片库中的一个相册,通过 ALAssetsGroup 可以获取某个相册的信息,相 册下的资源,同时也可以对某个相册添加资源。
  • ALAsset: 映射照片库中的一个照片或视频,通过 ALAsset 可以获取某个照片或视频的详细信息, 或者保存照片和视频。
  • ALAssetRepresentation: ALAssetRepresentation 是对 ALAsset 的封装(但不是其子类),可以更方便地获取 ALAsset 中的资源信息,每个 ALAsset 都有至少有一个 ALAssetRepresentation 对象,可以通过 defaultRepresentation 获取。而例如使用系统相机应用拍摄的 RAW + JPEG 照片,则会有两个 ALAssetRepresentation,一个封装了照片的 RAW 信息,另一个则封装了照片的 JPEG 信息。

@话不多说,直接上代码

#import <AssetsLibrary/AssetsLibrary.h> // 必须导入
// 照片原图路径
#define KOriginalPhotoImagePath  \
[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"OriginalPhotoImages"]
// 视频URL路径
#define KVideoUrlPath  \
[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"VideoURL"]
// caches路径
#define KCachesPath  \
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]
// MainViewController
@interface MTHMainViewController ()
@property (nonatomic,strong) MTHNextViewController *nextVC;
@property (nonatomic,strong) NSMutableArray    *groupArrays;
@property (nonatomic,strong) UIImageView      *litimgView;
@end
@implementation MTHMainViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.title = @"Demo";
self.view.backgroundColor = [UIColor clearColor];
// 初始化
self.groupArrays = [NSMutableArray array];
// 测试BarItem
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"测试" style:UIBarButtonItemStylePlain target:self action:@selector(testRun)];
// 测试手势
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(didClickPanGestureRecognizer:)];
[self.navigationController.view addGestureRecognizer:panRecognizer];
// 图片或者视频的缩略图显示
self.litimgView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 200, 120, 120)];
[self.view addSubview:_litimgView];
}
- (void)testRun
{
__weak MTHMainViewController *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
ALAssetsLibraryGroupsEnumerationResultsBlock listGroupBlock = ^(ALAssetsGroup *group, BOOLBOOL *stop) {
if (group != nil) {
[weakSelf.groupArrays addObject:group];
} else {
[weakSelf.groupArrays enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOLBOOL *stop) {
[obj enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOLBOOL *stop) {
if ([result thumbnail] != nil) {
// 照片
if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypePhoto]){
NSDate *date= [result valueForProperty:ALAssetPropertyDate];
UIImage *image = [UIImage imageWithCGImage:[result thumbnail]];
NSString *fileName = [[result defaultRepresentation] filename];
NSURL *url = [[result defaultRepresentation] url];
int64_t fileSize = [[result defaultRepresentation] size];
NSLog(@"date = %@",date);
NSLog(@"fileName = %@",fileName);
NSLog(@"url = %@",url);
NSLog(@"fileSize = %lld",fileSize);
// UI的更新记得放在主线程,要不然等子线程排队过来都不知道什么年代了,会很慢的
dispatch_async(dispatch_get_main_queue(), ^{
self.litimgView.image = image;
});
}
// 视频
else if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo] ){
// 和图片方法类似
}
}
}];
}];
}
};
ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error)
{
NSString *errorMessage = nil;
switch ([error code]) {
case ALAssetsLibraryAccessUserDeniedError:
case ALAssetsLibraryAccessGloballyDeniedError:
errorMessage = @"用户拒绝访问相册,请在<隐私>中开启";
break;
default:
errorMessage = @"Reason unknown.";
break;
}
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"错误,无法访问!"
message:errorMessage
delegate:self
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil nil];
[alertView show];
});
};
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
[assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
usingBlock:listGroupBlock failureBlock:failureBlock];
});
}


@但是:
按照上面方法直接取出来的路径是无法传输的,必须自己转化成NSData对象重新写入沙盒路径

// 将原始图片的URL转化为NSData数据,写入沙盒
- (void)imageWithUrl:(NSURL *)url withFileName:(NSString *)fileName
{
// 进这个方法的时候也应该加判断,如果已经转化了的就不要调用这个方法了
// 如何判断已经转化了,通过是否存在文件路径
ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
// 创建存放原始图的文件夹--->OriginalPhotoImages
NSFileManager * fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:KOriginalPhotoImagePath]) {
[fileManager createDirectoryAtPath:KOriginalPhotoImagePath withIntermediateDirectories:YES attributes:nil error:nil];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (url) {
// 主要方法
[assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *rep = [asset defaultRepresentation];
Byte *buffer = (Byte*)malloc((unsigned long)rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:((unsigned long)rep.size) error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
NSString * imagePath = [KOriginalPhotoImagePath stringByAppendingPathComponent:fileName];
[data writeToFile:imagePath atomically:YES];
} failureBlock:nil];
}
});
}
// 将原始视频的URL转化为NSData数据,写入沙盒
- (void)videoWithUrl:(NSURL *)url withFileName:(NSString *)fileName
{
// 解析一下,为什么视频不像图片一样一次性开辟本身大小的内存写入?
// 想想,如果1个视频有1G多,难道直接开辟1G多的空间大小来写?
ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (url) {
[assetLibrary assetForURL:url resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *rep = [asset defaultRepresentation];
NSString * videoPath = [KCachesPath stringByAppendingPathComponent:fileName];
char constconst *cvideoPath = [videoPath UTF8String];
FILEFILE *file = fopen(cvideoPath, "a+");
if (file) {
const int bufferSize = 11024 * 1024;
// 初始化一个1M的buffer
Byte *buffer = (Byte*)malloc(bufferSize);
NSUInteger read = 0, offset = 0, written = 0;
NSError* err = nil;
if (rep.size != 0)
{
do {
read = [rep getBytes:buffer fromOffset:offset length:bufferSize error:&err];
written = fwrite(buffer, sizeof(char), read, file);
offset += read;
} while (read != 0 && !err);//没到结尾,没出错,ok继续
}
// 释放缓冲区,关闭文件
free(buffer);
buffer = NULL;
fclose(file);
file = NULL;
}
} failureBlock:nil];
}
});
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

您可能感兴趣的文章:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 相册 视频