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];
    }
  });
}

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

(0)

相关推荐

  • 深入分析iOS应用中对于图片缓存的管理和使用

    我们的 iOS 应用都包含了大量的图像.创建富有吸引力的视图,主要依赖于大量的装饰图片,所有这些首先必须从远程服务器获取.如果每次打开应用都要从服务器一次又一次的获取每个图像,那么用户体验肯定达不到好的效果,所以本地缓存远程图像是非常有必要的. 两种方式加载本地图片 1.通过imageNamed:方法加载图片 用过这种方式加载图片,一旦图片加载到内存中,那么就不会销毁,一直到程序退出.(也就是说imageNamed:会有图片缓存的功能,当下次访问图片的时候速度会更快.) 用这种方式加载图片,图片

  • iOS开发中用imageIO渐进加载图片及获取exif的方法

    imageIO完成渐进加载图片 一.常见渐进加载图片模式   目前我们看到的渐进加载主要有以下三种实现方式:   1)  依次从web上加载不同尺寸的图片,从小到大.最开始先拉取一个小缩略图做拉伸显示,然后拉取中等规格的图,拉取完毕直接覆盖显示,最后拉取原图,拉取完成后显示原图.   2)直接从web上拉取最大的图片,每接受一点儿数据就显示一点儿图片,这样就会实现从上到下一点点刷新出来的效果.   3)结合第1种和第2种,先拉取一个缩略图做拉伸显示,然后采用第二种方法直接拉取原图,这样即可以实现

  • iOS实现图片存在本地、再从本地获取图片的功能

    iOS实现图片存在本地.再从本地获取图片的功能,代码如下: //将图片保存到本地 + (void)SaveImageToLocal:(UIImage*)image Keys:(NSString*)key { NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults]; //[preferences persistentDomainForName:LocalPath]; [preferences setObject:UII

  • IOS开发代码分享之获取启动画面图片的string

    本代码支持 iPhone 6 以下. 支持 iPhone 及 iPad +(NSString*)getLaunchImageName {           NSArray* images= @[@"LaunchImage.png", @"LaunchImage@2x.png",@"LaunchImage-700@2x.png",@"LaunchImage-568h@2x.png",@"LaunchImage-700

  • iOS实现图片保存与搜索功能

    本文实现Photos.framework的常见功能,包括:创建自定义相册.保存图片到自定义相册.搜索所有相册的图片,具体内容如下 1.保存图片到相册 /** * 保存图片到相册 */ - (IBAction)saveImage { PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; if (status == PHAuthorizationStatusDenied) { NSLog(@"请到[设置-隐私-照片]

  • iOS中获取系统相册中的图片实例

    本文介绍了iOS中获取系统相册中的图片,在很多应用中都能用到,可以获取单张图片,也可以同时获取多张图片,废话不多说了,看下面吧. 一.获取单张图片 思路: 1.利用UIImagePickerController可以从系统自带的App(照片\相机)中获得图片 2.设置代理,遵守代理协议 注意这个UIImagePickerController类比较特殊,需要遵守两个代理协议 @interface ViewController () <UIImagePickerControllerDelegate,

  • iOS App中调用相册中图片及获取最近的一张图片的方法

    UIImagePickerController从拍照.图库.相册获取图片 iOS 获取图片有三种方法: 1. 直接调用摄像头拍照 2. 从相册中选择 3. 从图库中选择 UIImagePickerController 是系统提供的用来获取图片和视频的接口: 用UIImagePickerController 类来获取图片视频,大体分为以下几个步骤: 1. 初始化UIImagePickerController 类: 2. 设置UIImagePickerController 实例的数据来源类型(下面解

  • iOS中读取照片库及保存图片或视频到照片库的要点解析

    读取照片库PhotoLibrary iOS中如果我们只有一次读取一张图片或者一个视频(或拍一张照片/视频)的需求,那么我们用 UIImagePickerController 就可以搞定.但是很多时候我们需要一次性从PhotoLibrary读取多个照片或者视频,这时候我们就需要另辟蹊径了,好在apple为我们提供了相应的接口. 在开始coding之前我们想要认识几个类: ALAssetsLibrary:代表整个PhotoLibrary,我们可以生成一个它的实例对象,这个实例对象就相当于是照片库的句

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

    好些天没写点东西了,最近公司要做新项目,有点小忙.不想我的坚持就此中断,我把我前些天研究的东西拿出来给大家看看. 这次整理的是AssetsLibrary和PhotoKit的使用.本人处女座,有点强迫症,之前写的项目里用的是AssetsLibrary写的调取相册内的媒体文件,但是Xcode总是报警告错误,虽然能够编译并展示效果,但是十几个警告错误挂在那,心里总不是滋味,所以我就研究了一下AssetLibrary和PhotoKit. 在 iOS 8 出现之前,开发者只能使用 AssetsLibrar

  • IOS获取系统相册中照片的示例代码

    先来看看效果图 下面话不多少,我们直接上代码: #import "ViewController.h" @interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate> @property (weak, nonatomic) IBOutlet UIImageView *IconView; @end @implementation ViewController

  • iOS开发之获取LaunchImage启动图的实例

    实例如下: #define KYRect [UIScreen mainScreen].bounds //获取启动图片 CGSize viewSize = KYRect.size; //横屏请设置成 @"Landscape" NSString *viewOrientation = @"Portrait"; NSString *launchImageName = nil; NSArray* imagesDict = [[[NSBundle mainBundle] inf

  • ios利用 AFN 上传相册或者拍照图片

    由于项目中多处需要上传图片,我们可以自定义上传图片请求,自定义调取相册及拍照,方便多处使用时调用. 主要步骤: 1.第一步:请求上传你选取的相册图片或者拍照图片(经过压缩处理) 2.第二步:获取到第一步图片url上传给服务器 3.第三步:回显图片(当然进入该界面时先判断是否有图片,无图则展示占位图片,否则就回显图片) 废话不多说,直接上代码: 1)封装的上传图片的网络请求(图片压缩) QTXUploadImage 文件 // 利用 afn 上传一张图片 #import <Foundation/F

  • Android获取SD卡中选中图片的路径(URL)示例

    最近在做一个图片上传的功能,需要提供上传图片在SD卡中的路径,在网上看了些例子,改改调试成功,代码很简单.其布局文件如下: 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill

  • android换肤功能 如何动态获取控件中背景图片的资源id?

    这个是在在做一个换肤功能时遇到的问题. 对于换肤,网上都有示例,可以从别的皮肤安装包中读取所要的资源,前提是你必须先持有这个资源的引用名称,像R.drawable.background(喂,这不是废话嘛).这个换肤的方案原理就是,自身应用的资源名称是R.drawable.background,那皮肤包中应该也是这个名称,然后通过这个名称获取该资源在皮肤包中的具体id,代码: //先获取本地资源引用名称,type name是R.drawable.background中的"drawable"

  • 使用wxPython获取系统剪贴板中的数据的教程

    涉及到开发桌面程序,尤其是文本处理,剪贴板就很常用,不像 java 中那么烦锁,wxpython 中访问剪贴板非常简单,寥寥几句足以. # 取得剪贴板并确保其为打开状态 text_obj = wx.TextDataObject() wx.TheClipboard.Open() if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open(): # do something... wx.TheClipboard.Close() 取值: if wx.Th

  • Android依据名字通过反射获取在drawable中的图片

    MainActivity如下: 复制代码 代码如下: package cn.testreflect; import java.lang.reflect.Field; import android.os.Bundle; import android.widget.ImageView; import android.app.Activity; /** * Demo描述: * 依据图片的名字,通过反射获取其在drawable中的ID * 在根据此ID显示图片 */ public class MainA

  • asp.net 获取文件夹中的图片的代码

    前台: 复制代码 代码如下: <asp:DataList ID="DataList1" runat="server" RepeatDirection="Horizontal" RepeatColumns="5" CellSpacing="25"> <ItemTemplate> <img src="<%# Eval("FullName") %&

随机推荐