您的位置:首页 > 移动开发 > Swift

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吧

使用方法:

//
//  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!");
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  自定义相册相机