代码地址如下:
http://www.demodashi.com/demo/13339.html

1.livePhoto简介

livePhoto是iOS 9.0 之后系统相机提供的拍摄动态照片的功能,但是仅在6S+,iOS 9.0+设备可用。拍摄完livePhoto之后,只需要在相册按压livePhoto相片即可动态的播放。livePhoto还可以设置为动态壁纸。如果只能用相机拍摄的livePhoto设置为动态壁纸,这不能满足我们的需求了。如果可以将视频转换为livePhoto那就完美了。如果要实现这个功能就要了解live Photo的本质了。

2.livePhoto的本质

其实livePhoto的本质是一张jpg图片+一段mov视频另外再加入一些信息一起写入到相册内即可生成livePhoto,核心的写入代码是我在github找到的,但是Swift版,我将它翻译为OC版。Swift版写入livePhotoDemo

3.涉及到的技术

1)相册数据的读取与写入;

2)share Extension的使用;

3)视频提取某一帧图片;

4)不同进程间的通讯;

5)PHLivePhotoView展示livePhoto图片;

4.实现livePhoto制作工具

主界面UI如下图,噗。。请原谅我毫无美感的页面设计,勿喷。



顶部一个AVplayer实现本地视频的播放,AVplayer下面一个UISlider可以选择视频的哪一帧作为livePhoto的封面图。UISlider下面一个PHLivePhotoView按压可以预览livePhoto的效果图。

1)如何提取视频中的某一帧?
/**
获取视频的 某一帧 @param currentTime 某一时刻单位 s
@param path 视频路径
@return return 返回image
*/
- (UIImage *)getVideoImageWithTime:(Float64)currentTime videoPath:(NSURL *)path {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:path options:nil];
// float fps = [[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] nominalFrameRate];
// NSLog(@"视频帧率%f",fps);
AVAssetImageGenerator *gen = [[AVAssetImageGenerator alloc] initWithAsset:asset];
gen.appliesPreferredTrackTransform = YES;
gen.requestedTimeToleranceAfter = kCMTimeZero;// 精确提取某一帧,需要这样处理
gen.requestedTimeToleranceBefore = kCMTimeZero;// 精确提取某一帧,需要这样处理 CMTime time = CMTimeMakeWithSeconds(currentTime, 600);
NSError *error = nil;
CMTime actualTime;
CGImageRef image = [gen copyCGImageAtTime:time actualTime:&actualTime error:&error];
UIImage *img = [[UIImage alloc] initWithCGImage:image];
CMTimeShow(actualTime);
CGImageRelease(image);
return img;
}
2)图片与视频分别经过特定的处理然后分别存储为JPG 与 MOV格式。

将视频转为livePhoto存入相册,iOS原生API并没有给出这样的方法。而能将视频转为livePhoto,是源于SwiftlivePhotoDemo作者对livePhoto细心观察。我这里只是借花献佛转化为OC版本。



使用上图中的两个文件可以将图片与视频分别经过特定的处理然后分别存储为JPG 与 MOV格式

3)将处理后的JPG 与 MOV一同存储生成livePhoto

首先引入#import <Photos/Photos.h>框架,调用performChanges方法存储,具体代码如下

+ (void)writeLivePhotoWithVideo:(NSURL *)videoPath image:(NSURL *)imagePath result:(void(^)(BOOL res))result {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetCreationRequest * request = [PHAssetCreationRequest creationRequestForAsset];
[request addResourceWithType:PHAssetResourceTypePhoto fileURL:imagePath options:nil];
[request addResourceWithType:PHAssetResourceTypePairedVideo fileURL:videoPath options:nil];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (success) {
//保存成功
NSLog(@"保存成功");
}
if (result) {
result(success);
}
}];
}

自此一个简单的livePhoto制作工具完成。但是为了用户体验,我们还要进行素材选取途径拓宽。

4)拓宽素材选取的途径
a.从相册选取素材

从相册选取素材,这里使用了UIImagePickerController来处理,具体代码如下:

- (void)chooseVideoFromPhotoLibraryResult:(ResultBlock)result {
UIImagePickerController *imagePick = [[UIImagePickerController alloc] init];
imagePick.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
imagePick.mediaTypes = @[@"public.movie"];//只获取视频数据
imagePick.delegate = self;
self.result = result;
[[[UIApplication sharedApplication] delegate].window.rootViewController presentViewController:imagePick animated:YES completion:nil];
}
// UIImagePickerController 的选择结果的代理方法。
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
if ([[info[@"UIImagePickerControllerMediaURL"] absoluteString] length]) {
if (self.result) {
self.result(info[@"UIImagePickerControllerMediaURL"], YES);
}
}
}
b.使用share Extension,让用户可以从其他App中获取素材

我们在项目工程下file-->New-->target-->share Extension-->Nest 创建一个share Extension如下图:





这篇文章详细解读了share Extension,如有需要可以先看一下

由于没有使用原生的share Extension UI所以这里,我们先把系统生成的.h+.m+MainInterface.storyboard这三个文件删除。然后创建一个viewController(继承UIviewController)+Xib。

在viewdidload里实现下面的代码,这些代码是为了获取用户选择的视频地址的操作。

 __weak typeof (self) ws = self;
[self.extensionContext.inputItems enumerateObjectsUsingBlock:^(NSExtensionItem * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[obj.attachments enumerateObjectsUsingBlock:^(NSItemProvider * _Nonnull itemProvider, NSUInteger idx, BOOL * _Nonnull stop) {
if ([itemProvider hasItemConformingToTypeIdentifier:itemProvider.registeredTypeIdentifiers[0]]) {
[itemProvider loadItemForTypeIdentifier:itemProvider.registeredTypeIdentifiers[0] options:nil completionHandler:^(id<NSSecureCoding> _Nullable item, NSError * _Null_unspecified error) {
NSLog(@"%@",item);
if ([(NSObject *)item isKindOfClass:[NSURL class]]) {
NSString * lastAppending = [[[(NSURL*)item absoluteString] componentsSeparatedByString:@"/"] lastObject];
NSFileManager *fileManger = [NSFileManager defaultManager];
NSURL *groupFile = [fileManger containerURLForSecurityApplicationGroupIdentifier:@"group.com.livephoto"];
NSURL *fileUrl = [groupFile URLByAppendingPathComponent:lastAppending];
//移除旧的数据
[fileManger removeItemAtURL:fileUrl error:nil];
NSError *error = nil;
[fileManger copyItemAtURL:(NSURL *)item toURL:fileUrl error:&error];
if (!error) {
ws.lastAppending = lastAppending;
dispatch_async(dispatch_get_main_queue(), ^{
[ws initVideoWithPath:fileUrl];
});
NSLog(@"存入成功!!!");
}
}
}];
*stop = YES;
}
}];
*stop = YES;
}];

这里要注意,由于Extension 与 宿主app分别属于不同的进程,由于iOS是沙盒存储机制。所以不同的进程是不能直接相互访问数据的。但是同一个公司的App 可以通过AppGroup来设置一个公共的存储空间,从而达到 不同的进行相互访问数据。这里我们也是使用AppGroup 把素材资源存储在公共的区域。方便宿主app访问素材数据。具体AppGroup如何来实现?可以参考这篇文文章:iOS App Group实现数据共享

如何唤醒宿主App处理素材数据?

其实iOS提供的Extension当中只有today widget 可以通过url schemes的方式唤醒。其他都是不能唤醒宿主App的。但是通过下面的方法还是可以强行通过url schemes的方式唤醒宿主app的,但是不知道是否可以通过审核?我看到京东的 拍照购 是可以唤醒京东app 的。

- (IBAction)handleVideo:(UIButton *)sender {
UIResponder *responder = self;
while (responder) {
if ([responder respondsToSelector:@selector(openURL:)]) {
[responder performSelector:@selector(openURL:) withObject:[NSURL URLWithString:[NSString stringWithFormat:@"livePhoto://data=%@",_lastAppending]]];
break;
}
responder = [responder nextResponder];
}
}

5.项目文件截图

6.注意点

运行demo前请先配置好自己的环境,以及把App Group换成自己的。最后看一下项目运行效果吧。

iOS开发一个制作Live Photo的工具

代码地址如下:
http://www.demodashi.com/demo/13339.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

iOS开发一个制作Live Photo的工具的更多相关文章

  1. iOS 开发人员不可缺少的75个工具

    原文出处: Ben Scheirman 译文出处: Njuxjy 假设你去到一位熟练的木匠的工作室,你总是能发现他/她有一堆工具来完毕不同的任务. 软件开发相同如此. 你能够从软件开发人员怎样使用工具 ...

  2. iOS开发一个用户登录注册模块需要解决的坑

    最近和另外一位同事负责公司登录和用户中心模块的开发工作,开发周期计划两周,减去和产品和接口的协调时间,再减去由于原型图和接口的问题,导致强迫症纠结症状高发,情绪不稳定耗费的时间,能在两周基本完成也算是 ...

  3. iOS开发~制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a

    一.概要 平时项目开发中,可能使用第三方提供的静态库.a,如果.a提供方技术不成熟,使用的时候就会出现问题,例如: 在真机上编译报错:No architectures to compile for ( ...

  4. iOS开发~制作同时支持armv7,armv7s,arm64,i386,x86_64的静态库.a以及 FrameWork 的创建

    armv7,armv7s,arm64,i386,x86_64 详解 一.概要 平时项目开发中,可能使用第三方提供的静态库.a,如果.a提供方技术不成熟,使用的时候就会出现问题,例如: 在真机上编译报错 ...

  5. iOS开发之--制作属于自己的frameWork

    开发的时候,有时候,我们会遇到协同开发,在协同开发的时候,每个开发者都会创建自己的工具类,还有就是当一个项目需要嵌套到另一个项目里面,这些时候,如果能把所需的部分打包成framework,会方便很多, ...

  6. IOS开发中制作属于自己的静态库.a、资源库.bundle、.framework

    一.什么是库        库实际上是一种代码共享的方式,主要用于代码重用和源码隐藏,通常分为动态库和静态库. 静态库:链接时完整的拷贝至可执行文件中,被多次使用就有多份冗余拷贝. 动态库:链接时不复 ...

  7. 分享iOS开发常用(三方类库,工具,高仿APP,实用网站,技术干货)

    一 . JSONModel  (三方类库会有更新,建议大家在线下载) http://pan.baidu.com/s/1i5ybP1z 二.AFNetworkiong http://pan.baidu. ...

  8. IOS封装一个微信聊天的输入工具

    1.实现微信的输入工具 实现了大部分功能,各模块实现的很清晰,有利于更好的二次开发(适合自己的需求),我自己总结出来的, 可以更快的让你实现输入工具,不需要扩展的也可以很方便的使用这个输入工具. 1) ...

  9. iOS 开发技巧-制作环形进度条

    有几篇博客写到了怎么实现环形进度条,大多是使用Core Graph来实现,实现比较麻烦且效率略低,只是一个小小的进度条而已,我们当然是用最简单而且效率高的方式来实现. 先看一下这篇博客,博客地址:ht ...

随机推荐

  1. Knockout.js(三):计算属性(Computed Observable)

    在Knockout2.0之前,计算属性被称之为依赖属性,在2.0版本中,ko.dependentObservable重命名为ko.computed,因为它在读.解释和类型上更简单.在实际使用中,ko. ...

  2. 【数形结合】Erratic Expansion

    [UVa12627]Erratic Expansion 算法入门经典第8章8-12(P245) 题目大意:起初有一个红球,每一次红球会分成三红一蓝,蓝球会分成四蓝(如图顺序),问K时的时候A~B行中有 ...

  3. 【状压dp】Islands and Bridges

    Islands and Bridges Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11034   Accepted: 2 ...

  4. 【状压dp】互不侵犯KING

    互不侵犯KING Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3866  Solved: 2264[Submit][Status][Discuss] ...

  5. BZOJ 1475 方格取数(二分图最大点权独立集)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1475 [题目大意] 给出一个n*n的方格,从中取一些不相邻的数字,使得和最大 [题解] ...

  6. 【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

    hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. #include<iostream> #include<cs ...

  7. 【二分查找】POJ2456-Aggressive cows

    [题目大意] 有N间牛舍和M头牛,告诉你每个牛舍的位置,求出两头牛之间最小距离的最大值. [思路] 二分判断两头牛之间的最小距离d,通过贪心法进行验证. #include<iostream> ...

  8. Activity(活动)生命周期(2)--活动状态

    每个活动在其生命周期中最多会有4种状态 一.运行状态 当一个活动位于返回栈的栈顶的时候,这时活动就处于运行状态.系统一般不会回收,因为这会带来非常差的用户体验 二.暂停状态 当一个活动不处于栈顶状态的 ...

  9. [转]tx:advice标签简介

    <Spring高级程序设计>第16章事务管理,通过本章的学习,你知道了如何使用Spring去管理事务,而这种方式几乎不会对你的源代码产生任何影响.你现在知道了如何使用本地和全局事务,并知道 ...

  10. Ubuntu中APache+mod_pyhon

    安装apache 1.sudo apt-get install Apache2 Apxs(Apache extension tool既apache扩展模块的工具)的安装: 1.sudo apt-get ...