iOS开发之获取系统相册中的图片与视频教程(内带url转换)
好些天没写点东西了,最近公司要做新项目,有点小忙。不想我的坚持就此中断,我把我前些天研究的东西拿出来给大家看看。
这次整理的是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]; } }); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 简单实现java音乐播放器