【iOS特性】3D Touch - 手搓Live Photo效果

前言

上次对 Live Photo 有了基本的认识和使用,这次尝试实现Live Photo 制作过程,末尾附上完整示例链接需要的自取。

代码实现Live Photo效果

注意:

  • 经试验使用 tmp 缓存目录读取视频会失败,建议拷贝到 Document 目录

前面我们知道 Live Photo其实就是一个 JPG 加上一个 MOV,只不过这个 MOV里面写入了一些元数据,能让相册正确的识别,基于这个原理我们完全可以自己实现 Live Photo 效果。

实现思路

  1. 从相册中选取一个视频并拷贝到 Document 目录

  2. 从视频中截取首帧图

  3. 根据首帧图和视频合成 Live Photo图片并存入相册

  4. PHLivePhotoView 展示 Live Photo图片

1.相册选取视频

实现UIImagePickerControllerDelegate协议,从选取的结果中读取 UIImagePickerControllerMediaURL 视频路径

- (void)chooseVideoFromLibrary {
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    imagePicker.mediaTypes = @[@"public.movie"];//只获取视频数据
    imagePicker.delegate = self;
    [self presentViewController:imagePicker animated:YES completion:^{}];
}

#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    [picker dismissViewControllerAnimated:YES completion:nil];
    NSURL *videoUrlPath = info[UIImagePickerControllerMediaURL];
    if (videoUrlPath) {
        // 获取视频文件名称并将视频文件移动到document目录下
        NSString * lastPading = [[[videoUrlPath absoluteString] componentsSeparatedByString:@"/"] lastObject];
        NSString * originPath = [self getFilePathWithKey:lastPading];
        self.videoUrl = originPath;
        [[NSFileManager defaultManager] copyItemAtURL:videoUrlPath toURL:[NSURL fileURLWithPath:originPath] error:nil];

        // 截图首帧图片
        self.coverImage.image = [self getVideoImageWithTime:0.0 videoPath:videoUrlPath];
    }
}

2.截图首帧图

- (UIImage *)getVideoImageWithTime:(Float64)currentTime videoPath:(NSURL *)path {
    AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:path options:nil];
    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;
}

3.合成Live Photo

首先引入#import <Photos/Photos.h>框架,调用performChanges方法存储

#pragma mark - 保存live photo
- (void)saveButtonClick {
    NSString * assetIdentifier = [[NSUUID UUID] UUIDString];
    NSString *imagePath = [self getFilePathWithKey:@"image.jpg"];
    NSString *movPath = [self getFilePathWithKey:@"mov.mov"];

    // 当前首帧图
    NSData *imageData = UIImageJPEGRepresentation(self.coverImage.image, 1.0);

    // 移除旧临时文件
    [[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
    [[NSFileManager defaultManager] removeItemAtPath:movPath error:nil];

    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t globle = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //任务一 写入 图片
    dispatch_group_async(group, globle, ^{
        JPEG *jpeg = [[JPEG alloc] initWithData:imageData];
        [jpeg write:imagePath assetIdentifier:assetIdentifier];
    });
    //任务二 写入 视频
    dispatch_group_async(group, globle, ^{
        QuickTimeMov *quickMov = [[QuickTimeMov alloc] initWithPath:self.videoUrl];
        [quickMov write:movPath assetIdentifier:assetIdentifier];
    });

    __weak typeof (self)ws = self;
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 写入相册
        PHAuthorizationStatus authstatus = [PHPhotoLibrary authorizationStatus];
        if (authstatus == PHAuthorizationStatusAuthorized) { //已经授权
            [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
               PHAssetCreationRequest * request = [PHAssetCreationRequest creationRequestForAsset];
               [request addResourceWithType:PHAssetResourceTypePhoto fileURL:[NSURL URLWithString:imagePath] options:nil];
               [request addResourceWithType:PHAssetResourceTypePairedVideo fileURL:[NSURL URLWithString:movPath] options:nil];
            } completionHandler:^(BOOL success, NSError * _Nullable error) {
               if (success) {
                   NSLog(@"保存成功");
               }
            }];
        }
    });
}

4.展示Live Photo

  • 通过 PHLivePhoto+ (PHLivePhotoRequestID)requestLivePhotoWithResourceFileURLs:placeholderImage:targetSize:contentMode:resultHandler:方法合成 Live Photo

  • 引入#import <PhotosUI/PhotosUI.h>框架使用 PHLivePhotoView 展示Live Photo

PHLivePhotoView * livePhotoView = [[PHLivePhotoView alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(livePhotoLabel.frame), CGRectGetWidth(self.view.frame), 300)];

[PHLivePhoto requestLivePhotoWithResourceFileURLs:@[[NSURL fileURLWithPath:movPath], [NSURL fileURLWithPath:imagePath]] placeholderImage:self.coverImage.image targetSize:self.coverImage.image.size contentMode:PHImageContentModeAspectFit resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nonnull info) {
    if (livePhoto) {
        livePhotoView.livePhoto = livePhoto;
    }
}];

效果图

在这里插入图片描述

项目链接

代码量有点多,我放到了github上,需要的自取

参考

友情提示

见原文:【iOS特性】3D Touch - 手搓Live Photo效果)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值