// // CameraViewController.swift // Twear // // Created by yangbin on 2021/12/22. // import UIKit import AVFoundation import Photos import TZImagePickerController import MBProgressHUD //let rect = CGRect(x: 30, y: 100, width: SCREEN_WIDTH-60, height: SCREEN_HEIGHT-100-100-100)// 底部工具栏 高度100 距离上面 下面都是100 class CameraViewController: UIViewController, BluetoothSyncDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate, TZImagePickerControllerDelegate { let WIDTH = UIScreen.main.bounds.width let HEIGHT = UIScreen.main.bounds.height // 音视频采集会话 let captureSession = AVCaptureSession() // 后置摄像头 @IBOutlet weak var backButton: UIButton! @IBOutlet weak var photographButton: UIButton! @IBOutlet weak var albumButton: UIButton! @IBOutlet weak var toggleButton: UIButton! @IBOutlet weak var countDownImageView: UIImageView! var isFromDevice: Bool = true var backFacingCamera: AVCaptureDevice? var time: Int = 3 // 前置摄像头 var frontFacingCamera: AVCaptureDevice? // 当前正在使用的设备 var currentDevice: AVCaptureDevice? // 静止图像输出端 var stillImageOutput: AVCaptureStillImageOutput? // 相机预览图层 var cameraPreviewLayer:AVCaptureVideoPreviewLayer? //照片拍摄后预览视图 var photoImageview:UIImageView! override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(true, animated: true) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if GCDTimer.shared.isExistTimer(WithTimerName: "camera_set") { GCDTimer.shared.cancleTimer(WithTimerName: "camera_set") } } override func viewDidLoad() { super.viewDidLoad() let authStatus = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) if authStatus == AVAuthorizationStatus.notDetermined { AVCaptureDevice.requestAccess(for: AVMediaType.video) { (granted) in if granted { self.setupUI() } else { self.back(1) } } } else if authStatus == AVAuthorizationStatus.restricted || authStatus == AVAuthorizationStatus.denied { self.cameraAccessAlert() } else { self.setupUI() } } func getPhotoData() { let options = PHFetchOptions() // 按图片生成时间排序 options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)] let allPhotos = PHAsset.fetchAssets(with: .image, options: options) if allPhotos.count > 0, let asset = allPhotos.lastObject { let size = CGSize(width: asset.pixelWidth, height: asset.pixelHeight) // let asset = object as! PHAsset PHCachingImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: .none) { (img, dic) in self.albumButton.setImage(img, for: .normal) } } // }) } func saveImageToPhotoLibrary() { // 判断权限 switch PHPhotoLibrary.authorizationStatus() { case .authorized: break // self.saveImage(image: stillImage) case .notDetermined: PHPhotoLibrary.requestAuthorization { (status) in if status == .authorized { // self?.saveImage(image: stillImage) } else { // self?.back(1) print("User denied") } } case .restricted, .denied: let alert = UIAlertController(title: LocString("提示"), message: LocString("请在“设置-隐私-照片“选项中,允许'YTWatch'访问你的照片"), preferredStyle: .alert) let confirm = UIAlertAction(title: LocString("确定"), style: .default) alert.addAction(confirm) default: break } } func cameraAccessAlert() { let alertVC = UIAlertController(title: LocString("提示"), message: LocString("请在“设置-隐私-相机”选项中,允许'YTWatch'访问你的相机"), preferredStyle: .alert) let confirm = UIAlertAction(title: LocString("确定"), style: .destructive) { [weak self] (action) in self?.back(1) } let cancel = UIAlertAction(title: LocString("取消"), style: .default) { [weak self] (action) in self?.back(1) } alertVC.addAction(cancel) alertVC.addAction(confirm) present(alertVC, animated: true, completion: nil) } func setupUI() { createUI() view.bringSubviewToFront(backButton) view.bringSubviewToFront(toggleButton) view.bringSubviewToFront(photographButton) view.bringSubviewToFront(albumButton) view.bringSubviewToFront(countDownImageView) BluetoothManager.shared.registerSyncDelegate(self) if !isFromDevice { BluetoothManager.shared.openCamera(true) } albumButton.imageView?.layer.cornerRadius = 18 albumButton.imageView?.layer.masksToBounds = true albumButton.imageView?.contentMode = .scaleAspectFill // albumButton.contentHorizontalAlignment = .fill // albumButton.contentVerticalAlignment = .fill getPhotoData() } //MARK: - 获取设备,创建自定义视图 func createUI(){ // 将音视频采集会话的预设设置为高分辨率照片--选择照片分辨率 self.captureSession.sessionPreset = AVCaptureSession.Preset.hd1280x720 // 获取设备 let devices = AVCaptureDevice.devices(for: AVMediaType.video) for device in devices { if device.position == AVCaptureDevice.Position.back { self.backFacingCamera = device } else if device.position == AVCaptureDevice.Position.front { self.frontFacingCamera = device } } //设置当前设备为前置摄像头 self.currentDevice = self.backFacingCamera do { // 当前设备输入端 let captureDeviceInput = try AVCaptureDeviceInput(device: currentDevice!) self.stillImageOutput = AVCaptureStillImageOutput() // 输出图像格式设置 self.stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] self.captureSession.addInput(captureDeviceInput) self.captureSession.addOutput(self.stillImageOutput!) } catch { // let alert = UIAlertController(title: "提示", message: "请打开相机权限: 设置-隐私-相机", preferredStyle: .alert) // let confirm = UIAlertAction(title: "确定", style: .default) // alert.addAction(confirm) // return } // 创建预览图层 self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession) self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill self.cameraPreviewLayer?.frame = view.layer.bounds self.view.layer.addSublayer(cameraPreviewLayer!) // Entry point / (_main) undefined. for architecture arm64 // 启动音视频采集的会话 self.captureSession.startRunning() } @objc func pinchCamera(_ recognizer: UIPinchGestureRecognizer) { // if let zoomFactor = currentDevice?.videoZoomFactor { // // if zoomFactor < 5.0 { // let newZoomFactor = min(zoomFactor + 1.0, 5.0) do { try currentDevice?.lockForConfiguration() currentDevice?.ramp(toVideoZoomFactor: recognizer.scale, withRate: 1.0) currentDevice?.unlockForConfiguration() } catch { print(error) } // } // } } func didReceiveCameraCommand(status: UInt8) { switch status { case 0x00://进入拍照 countDown() case 0x01:// 拍照 print("拍照") case 0x02:// 关闭 back(1) default: break } } @IBAction func photograph(_ sender: UIButton) { countDown() } @IBAction func openPhotoAlbum(_ sender: Any) { photoAlbum() } //相册 private func photoAlbum() { if PHPhotoLibrary.authorizationStatus().rawValue == 2 { MBProgressHUD.show(LocString("请在“设置-隐私-照片“选项中,允许'YTWatch'访问你的照片")) return } let picker = TZImagePickerController(maxImagesCount: 1, columnNumber: 3, delegate: self) picker?.modalPresentationStyle = .fullScreen picker?.allowPickingOriginalPhoto = false //原图 picker?.allowPickingVideo = false //视频 picker?.allowCameraLocation = false //位置 picker?.allowPickingGif = false //GIF picker?.allowTakePicture = false //内部拍照 picker?.allowCrop = false //裁剪 // picker?.didFinishPickingPhotosHandle = {[weak self] (photos, assets, isSelectOriginalPhoto) -> Void in // // } self.present(picker!, animated: true, completion: nil) // let picker = UIImagePickerController() // picker.sourceType = .photoLibrary // picker.delegate = self // //控制相册中显示视频和照片 // picker.mediaTypes = ["public.image"] //// picker.allowsEditing = true // picker.modalPresentationStyle = .fullScreen // // present(picker, animated: true, completion: nil) // let picker = TZImagePickerController(maxImagesCount: 0, columnNumber: 3, delegate: self) // picker?.modalPresentationStyle = .fullScreen // picker?.allowPickingOriginalPhoto = false //原图 // picker?.allowPickingVideo = false //视频 // picker?.allowCameraLocation = false //位置 // picker?.allowPickingGif = false //GIF // picker?.allowTakePicture = false //内部拍照 // picker?.allowCrop = true //裁剪 // // picker?.didFinishPickingPhotosHandle = {[weak self] (photos, assets, isSelectOriginalPhoto) -> Void in // // } // self.present(picker!, animated: true, completion: nil) } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { } func countDown() { if UIApplication.shared.applicationState == .background { return } if GCDTimer.shared.isExistTimer(WithTimerName: "camera_set") { GCDTimer.shared.cancleTimer(WithTimerName: "camera_set") } time = 3 countDownImageView.isHidden = false countDownImageView.image = UIImage(named: "camera_\(time)") GCDTimer.shared.scheduledDispatchTimerNotNow(WithTimerName: "camera_set", timeInterval: 1, queue: .main, repeats: true) { // if self.time == 0 { // // // } else { if self.time == 1 { self.countDownImageView.isHidden = true GCDTimer.shared.cancleTimer(WithTimerName: "camera_set") self.photoAction() } self.time -= 1 self.countDownImageView.image = UIImage(named: "camera_\(self.time)") // } } } //照相按钮 @objc func photoAction(){ // 获得音视频采集设备的连接 let videoConnection = stillImageOutput?.connection(with: AVMediaType.video) // 输出端以异步方式采集静态图像 stillImageOutput?.captureStillImageAsynchronously(from: videoConnection!, completionHandler: { (imageDataSampleBuffer, error) -> Void in if imageDataSampleBuffer == nil { return } // 获得采样缓冲区中的数据 let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer!) // 将数据转换成UIImage if let stillImage = UIImage(data: imageData!) { // func saveImageToPhotoLibrary() { // 判断权限 switch PHPhotoLibrary.authorizationStatus() { case .authorized: self.saveImage(image: stillImage) case .notDetermined: PHPhotoLibrary.requestAuthorization { [weak self](status) in if status == .authorized { self?.saveImage(image: stillImage) } else { // self?.back(1) print("User denied") } } case .restricted, .denied: let alert = UIAlertController(title: LocString("提示"), message: LocString("请在“设置-隐私-照片“选项中,允许'YTWatch'访问你的照片"), preferredStyle: .alert) let confirm = UIAlertAction(title: LocString("确定"), style: .default) alert.addAction(confirm) default: break } // } //显示当前拍摄照片 // UIImageWriteToSavedPhotosAlbum(stillImage, nil, nil, nil) // self.photoImageview.isHidden = false // // self.photoImageview.image = stillImage } }) } private func saveImage(image: UIImage) { PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAsset(from: image) }, completionHandler: { (isSuccess, error) in DispatchQueue.main.async { if isSuccess {// 成功 self.albumButton.setImage(image, for: .normal) } } }) } @IBAction func toggleCamera(_ sender: Any) { captureSession.beginConfiguration() // 在前置和后置之间切换摄像头 let newDevice = (currentDevice?.position == AVCaptureDevice.Position.back) ? frontFacingCamera : backFacingCamera // 移除之前所有的输入会话 for input in captureSession.inputs { captureSession.removeInput(input as! AVCaptureDeviceInput) } // 将输入端切换到新的采集设备 let cameraInput: AVCaptureDeviceInput do { cameraInput = try AVCaptureDeviceInput(device: newDevice!) } catch { print(error) return } // 添加输入端 if captureSession.canAddInput(cameraInput) { captureSession.addInput(cameraInput) } currentDevice = newDevice // 提交配置 captureSession.commitConfiguration() } @IBAction func back(_ sender: Any) { BluetoothManager.shared.unRegisterSyncDelegate(self) BluetoothManager.shared.openCamera(false) IsCameraOpen = false self.dismiss(animated: true) self.dismiss(animated: true) // navigationController?.popViewController(animated: true) } //取消按钮/重拍 @objc func cancelAction(){ //隐藏Imageview self.photoImageview.isHidden = true } //保存按钮-保存到相册 @objc func saveAction(){ //保存照片到相册 UIImageWriteToSavedPhotosAlbum(self.photoImageview.image!, nil, nil, nil) self.cancelAction() } } extension CameraViewController { //MARK: - 放大方法 @objc func zoomIn() { if let zoomFactor = currentDevice?.videoZoomFactor { if zoomFactor < 5.0 { let newZoomFactor = min(zoomFactor + 1.0, 5.0) do { try currentDevice?.lockForConfiguration() currentDevice?.ramp(toVideoZoomFactor: newZoomFactor, withRate: 1.0) currentDevice?.unlockForConfiguration() } catch { print(error) } } } } //MARK: - 缩小方法 @objc func zoomOut() { if let zoomFactor = currentDevice?.videoZoomFactor { if zoomFactor > 1.0 { let newZoomFactor = max(zoomFactor - 1.0, 1.0) do { try currentDevice?.lockForConfiguration() currentDevice?.ramp(toVideoZoomFactor: newZoomFactor, withRate: 1.0) currentDevice?.unlockForConfiguration() } catch { print(error) } } } } //MARK: - 切换摄像头 @objc func toggleCamera1() { captureSession.beginConfiguration() // 在前置和后置之间切换摄像头 let newDevice = (currentDevice?.position == AVCaptureDevice.Position.back) ? frontFacingCamera : backFacingCamera // 移除之前所有的输入会话 for input in captureSession.inputs { captureSession.removeInput(input as! AVCaptureDeviceInput) } // 将输入端切换到新的采集设备 let cameraInput: AVCaptureDeviceInput do { cameraInput = try AVCaptureDeviceInput(device: newDevice!) } catch { print(error) return } // 添加输入端 if captureSession.canAddInput(cameraInput) { captureSession.addInput(cameraInput) } currentDevice = newDevice // 提交配置 captureSession.commitConfiguration() } }