代码地址如下:
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. python 定义二维数组

    1. myList = [([0] * n) for i in range(m)],n是列,m是行 >>> array=[([0]*3) for i in range(4)] > ...

  2. AGC 012 D - Colorful Balls

    题面在这里! 为什么atcoder都是神仙题啊qwq 首先发现如果要让 x,y 互换位置的话,要么通过他们直接换 (也就是x和y满足两种操作之一),要么间接换,通过一些其他的元素形如 x可以和 a[1 ...

  3. Linux下KVM虚拟机基本管理及常用命令(转)

    说明:可能有重复 一.KVM的基本管理 1.查看KVM虚拟机配置文件 #Kvm虚拟机默认配置文件位置 [root@kvm qemu]# pwd /etc/libvirt/qemu [root@kvm ...

  4. CSS3技巧:fit-content水平居中

    当我们让一个模块水平居中首先想到的肯定是margin:0 auto;有木有?那么今天给大家介绍一个fit-content属性,不知道有没有同学用过,如果用过那么你可以略过这篇文章,没用过的同学就继续了 ...

  5. jquery滚动条插件nanoscroller的应用

    默认的滚动条的样式,各个版本的兼容性不是很好, 推荐一款jQuery 插件nanoscroller ,可以自定义滚动条的样式. 应用: 1.引入样式 nanoscroller.css <link ...

  6. 每天5分钟玩转Docker

    总结的这个八爪鱼图,不懂的时候随时翻翻书.....

  7. PostgreSQL配置文件--AUTOVACUUM参数

    8 AUTOVACUUM参数 AUTOVACUUM PARAMETERS 8.1 autovacuum 字符型 默认: autovacuum = on Enable autovacuum subpro ...

  8. Google Python 命名规范

    Google Python命名规范 module_name,  模块 package_name,  包 ClassName,  类 method_name,  方法 ExceptionName,    ...

  9. Java笔记15:多线程

    Java实现多线程有两种方式:一是继承Thread类:二是实现Runable接口. 一.Thread实现 publicclass ThreadDemo2 { publicstaticvoid main ...

  10. 使用kubeadm部署Kubernetes v1.13.3

    kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具. 这个工具能通过两条指令完成一个kubernetes集群的部署: 1. 安装要求 在开始之前,部署Kubernetes集群 ...