2019独角兽企业重金招聘Python工程师标准>>>
贡献者:赵大财
博客:https://my.oschina.net/zhaodacai GitHub:https://github.com/dacaizhao
邮箱: [email protected] 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
init(title:String?,fetchResult:PHFetchResult){
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 , 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 , thumbnailSize: CGSize) -> [UIImage] {
var imageArr:[UIImage] = []
for i in 0.. [DCAlbumItem]{
dCAlbumItems.removeAll()
let smartOptions = PHFetchOptions()
let smartAlbums = PHAssetCollection.fetchAssetCollections(with: .smartAlbum,
subtype: PHAssetCollectionSubtype.albumRegular,
options: smartOptions)
self.convertCollection(smartAlbums as! PHFetchResult)
//列出所有用户创建的相册
let userCollections = PHCollectionList.fetchTopLevelUserCollections(with: nil)
self.convertCollection(userCollections as! PHFetchResult)
//相册按包含的照片数量排序(降序)
self.dCAlbumItems.sort { (item1, item2) -> Bool in
return item1.fetchResult.count > item2.fetchResult.count
}
return dCAlbumItems
}
//转化处理获取到的相簿
fileprivate func convertCollection(_ collection:PHFetchResult){
for i in 0.. 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!");
}
}
}
}