swift3.0 自定义相册相机
2016-11-28 00:00
411 查看
贡献者:赵大财
博客:https://my.oschina.net/zhaodacai GitHub:https://github.com/dacaizhao
邮箱: dacai_zhao@163.com QQ:327532817
=============================
地址:https://github.com/dacaizhao/swiftCameraAlbum 给我Star吧
使用方法:
实现工具类
之上代码兼容9.0 你也可以自己尝试替换10
博客:https://my.oschina.net/zhaodacai GitHub:https://github.com/dacaizhao
邮箱: dacai_zhao@163.com QQ:327532817
=============================
地址:https://github.com/dacaizhao/swiftCameraAlbum 给我Star吧
使用方法:
// // ViewController.swift // swiftCameraAlbum // // Created by point on 2016/11/28. // Copyright © 2016年 dacai. All rights reserved. // import UIKit class ViewController: UIViewController { @IBOutlet weak var cameraView: UIView! //相机显示 @IBOutlet weak var focusView: UIImageView! //聚焦图片 @IBOutlet weak var takePicListCollectionView: TakePicListCollectionView!//展示列表 fileprivate var imgArr: [UIImage] = [UIImage]() //拍照的图片 override func viewDidLoad() { super.viewDidLoad() //启动照相机 DCCameraAlbum.shareCamera.start(view: cameraView, frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: view.frame.size.height-150)) //设置聚焦图片 DCCameraAlbum.shareCamera.focusView = focusView // } //获取指定的相册 需要一定回调时间 @IBAction func getAlbumThumb(_ sender: UIButton) { //默认的就是第一个 //DCCameraAlbum.shareCamera.getAlbumItemFetchResultsDefault(thumbnailSize: <#T##CGSize#>, finishedCallback: <#T##([UIImage]) -> ()#>) //你还可以这样做 你可以查看任何一个相册 需要一定的等待时间 所以是回调 let itemArr = DCCameraAlbum.shareCamera.getAlbumItem() let resulet = itemArr.first?.fetchResult let size = CGSize(width: 100, height: 100) DCCameraAlbum.shareCamera.getAlbumItemFetchResults(assetsFetchResults: resulet!, thumbnailSize: size) { [unowned self] (imgarr) in let vc = DCAlbumListViewController() vc.imgArr = imgarr self.present(vc, animated: true, completion: nil) } } // MARK:- 获取相册列表 @IBAction func getAlbumListClick(_ sender: UIButton) { let vc = DCAlbumViewController() vc.dcAlbumItem = DCCameraAlbum.shareCamera.getAlbumItem() present(vc, animated: true, completion: nil) } // MARK:- 拍摄照片 @IBAction func takePicClick(_ sender: UIButton) { DCCameraAlbum.shareCamera.takePhoto { [unowned self] (image) in self.imgArr.append(image) self.takePicListCollectionView.imgArr = self.imgArr } } // MARK:- 闪光灯管理 @IBAction func flashSegment(_ sender: UISegmentedControl) { switch sender.selectedSegmentIndex { case 0: DCCameraAlbum.shareCamera.flashLamp(mode: .auto) case 1: DCCameraAlbum.shareCamera.flashLamp(mode: .on) case 2: DCCameraAlbum.shareCamera.flashLamp(mode: .off) default: break } } }
实现工具类
// // DCCameraAlbum.swift // DCCameraAlbum // // Created by point on 2016/11/28. // Copyright © 2016年 dacai. All rights reserved. // import UIKit import AVFoundation import Photos struct Platform { static let isSimulator: Bool = { var isSim = false #if arch(i386) || arch(x86_64) isSim = true #endif return isSim }() } enum flashMode:Int { case off case on case auto } class DCCameraAlbum: NSObject { // MARK:- 相机属性 fileprivate lazy var session : AVCaptureSession = AVCaptureSession() fileprivate lazy var inputDevice : AVCaptureDeviceInput = AVCaptureDeviceInput() //输入源 fileprivate lazy var imageOutput : AVCaptureStillImageOutput = AVCaptureStillImageOutput() //输出 lazy var priviewLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer() //视 fileprivate var currentView: UIView! //管理控制器 fileprivate var isUsingBackCamera:Bool = true //是否正在使用后置摄像头 fileprivate var videoInput : AVCaptureDeviceInput? fileprivate var currentD :AVCaptureDevice! var focusView :UIView! //聚焦的View fileprivate var effectiveScale:CGFloat = 1.0 //默认缩放 fileprivate var beginGestureScale:CGFloat = 1.0 // fileprivate let maxScale:CGFloat = 2.0 //最大缩放 fileprivate let minScale:CGFloat = 1.0 //最小缩放 // MARK:- 相册属性 fileprivate var dCAlbumItems:[DCAlbumItem] = [] //相册列表 fileprivate var imageManager:PHCachingImageManager! //带缓存的图片管理对象 //单例 internal static let shareCamera:DCCameraAlbum = { let camera = DCCameraAlbum() return camera }() //初始化 override init() { super.init() if Platform.isSimulator { print("请不要使用模拟器测试") } else { installCameraDevice() //初始化摄像机 } } } // MARK:- =============相册 class DCAlbumItem { //相簿名称 var title:String? //相簿内的资源 var fetchResult:PHFetchResult<PHAsset> init(title:String?,fetchResult:PHFetchResult<PHAsset>){ self.title = title self.fetchResult = fetchResult } } // MARK: - 获取相册集合 extension DCCameraAlbum { // MARK: - 获取指定图片 func getOriginalPicture(picAsset:PHAsset , finishedCallback: @escaping (_ image: UIImage) -> ()) { PHImageManager.default().requestImage(for: picAsset, targetSize: PHImageManagerMaximumSize , contentMode: .aspectFit, options: nil, resultHandler: { (image, _: [AnyHashable: Any]?) in finishedCallback(image!) }) } // MARK: - 获取指定的相册缩略图列表 func getAlbumItemFetchResults(assetsFetchResults: PHFetchResult<PHAsset> , thumbnailSize: CGSize , finishedCallback: @escaping (_ result : [UIImage] ) -> ()){ cachingImageManager() let imageArr = fetchImage(assetsFetchResults: assetsFetchResults, thumbnailSize: thumbnailSize) finishedCallback(imageArr) } // MARK: - 获取默认的照相机照片缩略图列表 func getAlbumItemFetchResultsDefault(thumbnailSize: CGSize , finishedCallback: @escaping (_ result : [UIImage] ) -> ()) { cachingImageManager() let allPhotosOptions = PHFetchOptions() //按照创建时间倒序排列 allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate",ascending: false)] //只获取图片 allPhotosOptions.predicate = NSPredicate(format: "mediaType = %d",PHAssetMediaType.image.rawValue) let assetsFetchResults = PHAsset.fetchAssets(with: .image, options: allPhotosOptions) let imageArr = fetchImage(assetsFetchResults: assetsFetchResults, thumbnailSize: thumbnailSize) finishedCallback(imageArr) } //缓存管理 fileprivate func cachingImageManager(){ imageManager = PHCachingImageManager() imageManager.stopCachingImagesForAllAssets() } //获取图片 fileprivate func fetchImage(assetsFetchResults: PHFetchResult<PHAsset> , thumbnailSize: CGSize) -> [UIImage] { var imageArr:[UIImage] = [] for i in 0..<assetsFetchResults.count { print(i) let asset = assetsFetchResults[i] self.imageManager.requestImage(for: asset, targetSize: thumbnailSize, contentMode: PHImageContentMode.aspectFill, options: nil) { (image, nfo) in imageArr.append(image!) } } return imageArr } } // MARK: - 获取相册列表 extension DCCameraAlbum { func getAlbumItem() -> [DCAlbumItem]{ dCAlbumItems.removeAll() let smartOptions = PHFetchOptions() let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: PHAssetCollectionSubtype.albumRegular, options: smartOptions) self.convertCollection(smartAlbums as! PHFetchResult<AnyObject>) //列出所有用户创建的相册 let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil) self.convertCollection(userCollections as! PHFetchResult<AnyObject>) //相册按包含的照片数量排序(降序) self.dCAlbumItems.sort { (item1, item2) -> Bool in return item1.fetchResult.count > item2.fetchResult.count } return dCAlbumItems } //转化处理获取到的相簿 fileprivate func convertCollection(_ collection:PHFetchResult<AnyObject>){ for i in 0..<collection.count{ //获取出但前相簿内的图片 let resultsOptions = PHFetchOptions() resultsOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)] resultsOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue) guard let c = collection[i] as? PHAssetCollection else { return } let assetsFetchResult = PHAsset.fetchAssets(in: c,options: resultsOptions) //没有图片的空相簿不显示 if assetsFetchResult.count > 0{ self.dCAlbumItems.append(DCAlbumItem(title: c.localizedTitle, fetchResult: assetsFetchResult )) } } } } // MARK:- =============相机 // MARK: - 开始 extension DCCameraAlbum { func start(view: UIView , frame: CGRect){ currentView = view addPrviewLayerToView(frame: frame) setUpGesture() //添加手势 if session.isRunning == false { session.startRunning() //不要用,模拟器测试-_-! } } } // MARK: - 结束 extension DCCameraAlbum { func stop(){ if session.isRunning == true { session.stopRunning() } } } // MARK: - 拍照 extension DCCameraAlbum { func takePhoto(finishedCallback : @escaping (_ result : UIImage ) -> ()){ let captureConnetion = imageOutput.connection(withMediaType: AVMediaTypeVideo) captureConnetion?.videoScaleAndCropFactor = effectiveScale imageOutput.captureStillImageAsynchronously(from: captureConnetion) { (imageBuffer, error) in let jpegData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageBuffer) let jpegImage = UIImage(data: jpegData!) //图片入库 UIImageWriteToSavedPhotosAlbum(jpegImage!, self,nil, nil) finishedCallback(jpegImage!) } } } // MARK: - 闪光灯 extension DCCameraAlbum { func flashLamp(mode:flashMode){ do{ try currentD.lockForConfiguration() }catch{ } if currentD.hasFlash == false { return } if mode.rawValue == 0 { currentD.flashMode = .off} if mode.rawValue == 1 { currentD.flashMode = .on} if mode.rawValue == 2 { currentD.flashMode = .auto} currentD.unlockForConfiguration() } } // MARK: - 前后摄像头 extension DCCameraAlbum { func beforeAfterCamera(){ //获取之前的镜头 guard var position = videoInput?.device.position else { return } //获取当前应该显示的镜头 position = position == .front ? .back : .front //创建新的device guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { return } // 1.2.取出获取前置摄像头 let d = devices.filter({ return $0.position == position }).first currentD = d //input guard let videoInput = try? AVCaptureDeviceInput(device: d) else { return } //切换 session.beginConfiguration() session.removeInput(self.videoInput!) session.addInput(videoInput) session.commitConfiguration() self.videoInput = videoInput } } // MARK: - 初始化相机相关 extension DCCameraAlbum:UIGestureRecognizerDelegate{ fileprivate func installCameraDevice(){ // 1.创建输入 // 1.1.获取所有的设备(包括前置&后置摄像头) guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { return } // 1.2.取出获取前置摄像头 guard let d = devices.filter({ return $0.position == .back }).first else{ return} currentD = d // 1.3.通过前置摄像头创建输入设备 guard let inputDevice = try? AVCaptureDeviceInput(device: d) else { return } self.videoInput = inputDevice //输出 imageOutput = AVCaptureStillImageOutput() imageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG] //加入 if session.canAddInput(inputDevice) == true { session.addInput(self.videoInput) } if session.canAddOutput(imageOutput) == true { session.addOutput(imageOutput) } //视图 priviewLayer = AVCaptureVideoPreviewLayer(session:session) priviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill //闪光灯 do{ try d.lockForConfiguration() }catch{ } if d.hasFlash == false { return } d.flashMode = AVCaptureFlashMode.auto d.unlockForConfiguration() } //显示View fileprivate func addPrviewLayerToView(frame:CGRect) -> Void{ priviewLayer.frame = frame //currentView.layer.masksToBounds = true currentView.layer.insertSublayer(priviewLayer, at: 0) } //添加手势 + 缩放 + 聚焦 fileprivate func setUpGesture() { let pinGesutre = UIPinchGestureRecognizer(target: self, action: #selector(pinFunc(_:))) pinGesutre.delegate = self currentView.addGestureRecognizer(pinGesutre) let tapGesutre = UITapGestureRecognizer(target: self, action: #selector(tipFunc(_:))) currentView.addGestureRecognizer(tapGesutre) } //添加上聚焦 @objc func tipFunc(_ ges:UITapGestureRecognizer) { let currentPoint = ges.location(in: currentView) currentView.isUserInteractionEnabled = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { self.currentView.isUserInteractionEnabled = true } do{ try currentD.lockForConfiguration() }catch{ } if currentD.isFocusModeSupported(.autoFocus) { currentD.focusPointOfInterest = currentPoint currentD.focusMode = .autoFocus } if currentD.isExposureModeSupported(.autoExpose) { currentD.exposurePointOfInterest = currentPoint currentD.exposureMode = .autoExpose } currentD.unlockForConfiguration() focusView.center = currentPoint focusView.isHidden = false UIView.animate(withDuration: 0.3, animations: { self.focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25); }) { (_) in UIView.animate(withDuration: 0.5, animations: { self.focusView.transform = CGAffineTransform.identity }) { (_) in self.focusView.isHidden = true } } } func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { if gestureRecognizer .isKind(of: UIPinchGestureRecognizer.classForCoder()) { beginGestureScale = self.effectiveScale } return true } //添加缩放 @objc func pinFunc(_ recognizer:UIPinchGestureRecognizer) { self.effectiveScale = self.beginGestureScale * recognizer.scale; if (self.effectiveScale < 1.0) { self.effectiveScale = 1.0; } let maxScaleAndCropFactor = imageOutput.connection(withMediaType: AVMediaTypeVideo).videoMaxScaleAndCropFactor if self.effectiveScale > maxScaleAndCropFactor { self.effectiveScale = maxScaleAndCropFactor; } CATransaction.begin() CATransaction.setAnimationDuration(0.025) priviewLayer.setAffineTransform(CGAffineTransform(scaleX: effectiveScale, y: effectiveScale)) CATransaction.commit() } } // MARK:- =============权限 extension DCCameraAlbum { //必须info.plist 配置上这2句 //Privacy - Camera Usage Description //Privacy - Photo Library Usage Description /** 相机权限检测 */ func cameraPermissions() -> Bool{ let authStatus:AVAuthorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo) switch authStatus { case .denied , .restricted: return false case .authorized: return true case .notDetermined: AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: nil) return true } } /** 相册权限检测 */ func photoPermissions() -> Bool{ let authStatus:PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus() switch authStatus { case .denied , .restricted: return false case .authorized: return true case .notDetermined: let vc = UIImagePickerController() vc.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)! return true } } }
之上代码兼容9.0 你也可以自己尝试替换10
import UIKit import AVFoundation class ViewController: UIViewController, AVCapturePhotoCaptureDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate { @IBOutlet weak var cameraView: UIView! var captureSession = AVCaptureSession(); var sessionOutput = AVCapturePhotoOutput(); var sessionOutputSetting = AVCapturePhotoSettings(format: [AVVideoCodecKey:AVVideoCodecJPEG]); var previewLayer = AVCaptureVideoPreviewLayer(); override func viewWillAppear(_ animated: Bool) { let deviceDiscoverySession = AVCaptureDeviceDiscoverySession(deviceTypes: [AVCaptureDeviceType.builtInDuoCamera, AVCaptureDeviceType.builtInTelephotoCamera,AVCaptureDeviceType.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: AVCaptureDevicePosition.unspecified) for device in (deviceDiscoverySession?.devices)! { if(device.position == AVCaptureDevicePosition.front){ do{ let input = try AVCaptureDeviceInput(device: device) if(captureSession.canAddInput(input)){ captureSession.addInput(input); if(captureSession.canAddOutput(sessionOutput)){ captureSession.addOutput(sessionOutput); previewLayer = AVCaptureVideoPreviewLayer(session: captureSession); previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait; cameraView.layer.addSublayer(previewLayer); } } } catch{ print("exception!"); } } } }
相关文章推荐
- 自定义相机、相册(相机篇)
- swift3.0调用相机和相册 简单实用
- iOS图片处理(一)————调用系统相机和相册获取图片,给相机添加自定义覆盖物
- iOS获取相册/相机图片-------自定义获取图片小控件
- iOS--相机(自定义相机) 保存照片到相册
- iOS图片处理(一)调用系统相机和相册获取图片,给相机添加自定义覆盖物
- JS 使用 Android + IOS 相册 + 相机 进行自定义头像 + 限制裁剪后图片尺寸 + base64 string 与 图片互相转换
- 【swift3.0】【自定义相册】【Photos.framework】
- swift3.0中自定义的相机,不好别喷,给点提示,多多指教
- 手机相机和相册:仿微信自定义相册
- 保存图片到【相机胶卷】和【自定义相册】
- iOS访问相册和相机
- iOS判断应用是否获取到系统相机 相册的授权 以及如何请求授权
- iOS 访问相册或者相机时崩溃
- Android自定义相机,带边框截图
- 调用相机拍摄和相册
- Android 调用系统相机以及相册源码
- Android调用手机相机和相册
- 相机 + 相册中获取相片并裁剪显示
- iOS10 关于相机相册崩溃问题