{"id":21374084,"url":"https://github.com/jolincheng/CZHChooseCoverController","last_synced_at":"2025-07-13T08:32:25.704Z","repository":{"id":199196324,"uuid":"108816956","full_name":"jolincheng/CZHChooseCoverController","owner":"jolincheng","description":null,"archived":false,"fork":false,"pushed_at":"2022-04-06T04:45:11.000Z","size":18625,"stargazers_count":37,"open_issues_count":0,"forks_count":12,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-10-09T06:35:16.646Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jolincheng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-10-30T07:35:33.000Z","updated_at":"2023-10-09T06:35:19.515Z","dependencies_parsed_at":null,"dependency_job_id":"ba190aa6-51db-413d-b083-a9579505ede4","html_url":"https://github.com/jolincheng/CZHChooseCoverController","commit_stats":null,"previous_names":["jolincheng/czhchoosecovercontroller"],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jolincheng%2FCZHChooseCoverController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jolincheng%2FCZHChooseCoverController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jolincheng%2FCZHChooseCoverController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jolincheng%2FCZHChooseCoverController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jolincheng","download_url":"https://codeload.github.com/jolincheng/CZHChooseCoverController/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225868624,"owners_count":17537088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-22T08:29:40.851Z","updated_at":"2024-11-22T08:30:12.865Z","avatar_url":"https://github.com/jolincheng.png","language":"Objective-C","funding_links":[],"categories":["OOM-Leaks-Crash"],"sub_categories":["Crop video cover"],"readme":"# CZHChooseCoverController\n\n\n\n![合成 1.gif](http://upload-images.jianshu.io/upload_images/6709174-f9c9f8667d18c705.gif?imageMogr2/auto-orient/strip)\n\n###### 起初看到这个功能我是拒绝的，之前做的视频上传都是获取特定的帧数当封面，没有刻意的去选择封面，但是需求已定，随后网上也找了下，没有类似的，于是乎就自己写了一个，有什么改进的地方可以互相交流，话不多说直接上代码了\n\n1.打开相册，系统相册用的很顺手，所以一直就用系统的相册\n```\n//两个代理\n@interface ViewController ()\u003cUIImagePickerControllerDelegate, UINavigationControllerDelegate\u003e\n\n@property (weak, nonatomic) IBOutlet UIImageView *coverImageView;\n\n@end\n```\n```\n//代理方法\n//打开相册\n- (void)openImagePickerController:(UIImagePickerControllerSourceType)type\n{\n    if (![UIImagePickerController isSourceTypeAvailable:type]) return;\n\n    UIImagePickerController *ipc = [[UIImagePickerController alloc] init];\n\n    //视频最大时间\n    ipc.videoMaximumDuration = 30;\n    ipc.view.backgroundColor = [UIColor whiteColor];\n    ipc.sourceType = type;\n    ipc.delegate = self;\n    //只打开视频\n    ipc.mediaTypes = @[(NSString *)kUTTypeMovie];\n    //视频上传质量\n    ipc.videoQuality = UIImagePickerControllerQualityTypeHigh;\n    [self presentViewController:ipc animated:YES completion:nil];\n}\n\n\n#pragma mark - UIImagePickerControllerDelegate\n/**\n* 从UIImagePickerController选择完图片后就调用（拍照完毕或者选择相册图片完毕）\n*/\n\n- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary\u003cNSString *,id\u003e *)info {\n\n    CZHWeakSelf(self);\n\n    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];\n\n    if ([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {\n        //如果是视频\n        NSURL *url = info[UIImagePickerControllerMediaURL];\n        //计算相册视频时长\n        NSDictionary *videoDic = [CZHTool getLocalVideoSizeAndTimeWithSourcePath:url.absoluteString];\n        int videoTime = [[videoDic valueForKey:@\"duration\"] intValue];\n        //视频限制的长度\n        NSUInteger limitTime = 30;\n        if (videoTime \u003e limitTime) {\n            [picker dismissViewControllerAnimated:YES completion:nil];\n            return;\n            }\n            //把系统相册mov格式转换成mp4格式\n            [CZHTool convertMovTypeIntoMp4TypeWithSourceUrl:url convertSuccess:^(NSURL *path) {\n            CZHStrongSelf(self);\n            [picker dismissViewControllerAnimated:YES completion:nil];\n            //选择封面控制器\n            CZHChooseCoverController *chooseCover = [[CZHChooseCoverController alloc] init];\n            //本地路径\n            chooseCover.videoPath = path;\n            //选择封面的block，把封面image回调\n            chooseCover.coverImageBlock = ^(UIImage *coverImage) {\n                self.coverImageView.image = coverImage;\n\n                //上传视频操作\n                //[self changeWithUploadSource:path];\n                //上传封面操作\n                //[self uploadCoverWithImage:coverImage];\n            };\n            [self presentViewController:chooseCover animated:YES completion:nil];\n        }];\n    }\n}\n\n// 取消图片选择调用此方法\n- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {\n    // dismiss UIImagePickerController\n    [self dismissViewControllerAnimated:YES completion:nil];\n}\n```\n\n2.选择封面控制器\n```\n//截取几张图片放在底部用作展示，我是用collectionview做展示\n    AVURLAsset * asset = [AVURLAsset assetWithURL:self.videoPath];\n    CMTime  time = [asset duration];\n    self.timeValue = time.value;\n    self.timeScale = time.timescale;\n    if (time.value \u003c 1) {\n        [self dismissViewControllerAnimated:YES completion:nil];\n        return;\n    }\n\n    NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];\n    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:self.videoPath options:opts];\n    AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset];\n    generator.appliesPreferredTrackTransform = YES;\n    /**The actual time of the generated images will be within the range [requestedTime-toleranceBefore, requestedTime+toleranceAfter] and may differ from the requested time for efficiency.\n    Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request frame-accurate image generation; this may incur additional decoding delay.\n    Default is kCMTimePositiveInfinity.*/\n    \n    generator.requestedTimeToleranceAfter = kCMTimeZero;\n    generator.requestedTimeToleranceBefore = kCMTimeZero;\n    //总帧数/展示的总数量\n    long long baseCount = time.value / PHOTP_COUNT;\n    //取出PHOTP_COUNT张图片,存放到数组，用于collectionview\n    for (NSInteger i = 0 ; i \u003c PHOTP_COUNT; i++) {\n\n        NSError *error = nil;\n            //每隔baseCount帧取一帧存起来,一共PHOTP_COUNT张\n            CGImageRef img = [generator copyCGImageAtTime:CMTimeMake(i * baseCount, time.timescale) actualTime:NULL error:\u0026error];\n        {\n            UIImage *image = [UIImage imageWithCGImage:img];\n\n            [self.photoArrays addObject:image];\n        }\n        ///释放内存\n    CGImageRelease(img);\n    }\n```\n\n```\n//把存的存的几张图片用collectionview展示出来\n    CGRect collectionViewF = CGRectMake(0,  CZH_ScaleHeight(461), ScreenWidth, CZH_ScaleHeight(62.5));\n    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:collectionViewF collectionViewLayout:layout];\n    collectionView.dataSource = self;\n    collectionView.backgroundColor = [UIColor clearColor];\n    [collectionView registerClass:[CZHChooseCoverCell class]    forCellWithReuseIdentifier:ID];\n    [self.view addSubview:collectionView];\n    self.collectionView  = collectionView;\n\n    //在collectionview上面覆盖一个slider用于滑动选择图片\n    UIImage *selected = [UIImage imageNamed:@\"slider_select\"];\n    UIImage *deselected = [UIImage imageNamed:@\"slider_deselect\"];\n\n    UISlider *slider = [[UISlider alloc] init];\n    slider.frame = CGRectMake(0,  CZH_ScaleHeight(461), ScreenWidth, CZH_ScaleHeight(62.5));\n\n    [slider setThumbImage:deselected forState:UIControlStateNormal];\n    [slider setThumbImage:selected forState:UIControlStateHighlighted];\n    //透明的图片\n    UIImage *image = [CZHTool imageWithColor:[UIColor clearColor] size:CGSizeMake(1, 1)];\n\n    [slider setMinimumTrackImage:image forState:UIControlStateNormal];\n    [slider setMaximumTrackImage:image forState:UIControlStateNormal];\n\n    slider.maximumValue = self.timeValue;\n    slider.minimumValue = 0;\n    [slider addTarget:self action:@selector(valueChange:) forControlEvents:UIControlEventValueChanged];\n    [self.view addSubview:slider];\n\n    //默认选取第一帧展示\n    [self chooseWithTime:0];\n\n```\n\n```\n//滑动slider的操作\n- (void)valueChange:(UISlider *)sender {\n\n    int timeValue = sender.value;\n\n    [self chooseWithTime:timeValue];\n}\n\n\n- (void)chooseWithTime:(CMTimeValue)time {\n\n    NSDictionary *opts = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];\n    AVURLAsset *urlAsset = [AVURLAsset URLAssetWithURL:self.videoPath options:opts];\n    AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset];\n    generator.appliesPreferredTrackTransform = YES;\n    /**The actual time of the generated images will be within the range [requestedTime-toleranceBefore, requestedTime+toleranceAfter] and may differ from the requested time for efficiency.\n    Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request frame-accurate image generation; this may incur additional decoding delay.\n    Default is kCMTimePositiveInfinity.*/\n    \n    generator.requestedTimeToleranceAfter = kCMTimeZero;\n    generator.requestedTimeToleranceBefore = kCMTimeZero;\n\n\n    NSError *error = nil;\n    CGImageRef img = [generator copyCGImageAtTime:CMTimeMake(time, self.timeScale) actualTime:NULL error:\u0026error];\n    {\n        UIImage *image = [UIImage imageWithCGImage:img];\n\n        self.imageView.image = image;\n    }\n    ///释放内存\n    CGImageRelease(img);\n}\n\n```\n\n```\n//点击返回按钮和完成按钮的操作\n- (void)buttonClick:(UIButton *)sender {\n    if (sender.tag == CZHChooseCoverControllerButtonTypeBack) {\n        [self dismissViewControllerAnimated:YES completion:nil];\n        } else if (sender.tag == CZHChooseCoverControllerButtonTypeComplete) {\n            //封面图片回调\n        if (_coverImageBlock) {\n            _coverImageBlock(self.imageView.image);\n        }\n    [self dismissViewControllerAnimated:YES completion:nil];\n    }\n}\n```\n\n\nps.模拟器相册没有视频的话可以用下面代码把项目的视频保存到相册\n```\n    NSMutableArray *videoArray = [NSMutableArray array];\n    //工程中类型是MP4的文件数组\n    NSArray *movs = [[NSBundle mainBundle] pathsForResourcesOfType:@\"mp4\" inDirectory:nil];\n    [videoArray addObjectsFromArray:movs];\n    for (id item in videoArray) {\n        //循环保存到相册\n        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(item)) {\n            UISaveVideoAtPathToSavedPhotosAlbum(item, self, nil, NULL);\n        }\n    }\n```\n\n[更多查看blog](http://blog.csdn.net/HurryUpCheng)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolincheng%2FCZHChooseCoverController","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjolincheng%2FCZHChooseCoverController","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjolincheng%2FCZHChooseCoverController/lists"}