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

时间:2022-09-19 17:01:01

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

这次整理的是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 信息。

@话不多说,直接上代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#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];
  });
}

iOS开发之获取系统相册中的图片与视频教程(内带url转换)
@但是:
按照上面方法直接取出来的路径是无法传输的,必须自己转化成nsdata对象重新写入沙盒路径

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
   // 将原始图片的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];
    }
  });
}

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