在previewLayer上绘图:AVCaptureVideoPreviewLayer

时间:2018-02-21 14:41:27

标签: ios swift uiview

我有一个小应用程序,一个显示实时(视频)预览的SimpleCamera,屏幕上有一个按钮可以拍照。然后显示照片,您可以保存或丢弃它。一切正常,我使用此代码在屏幕预览周围绘制一个灰色边框。这也很好。但是我可以在预览屏幕上绘制这些内容吗?我无法弄清楚如何添加第一个代码块下面显示的下一位代码?

    // Provide a camera preview
    cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    view.layer.addSublayer(cameraPreviewLayer!)
    cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    cameraPreviewLayer?.frame = view.layer.frame
    //Add preview layer for drawing
    let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
    previewLayer.frame = self.view.layer.frame
    previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    self.view.layer.addSublayer(previewLayer)
    //Add Rectangle
    let cgRect = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    let myView = UIImageView()
    myView.frame = cgRect
    myView.backgroundColor = UIColor.clear
    myView.isOpaque = false
    myView.layer.cornerRadius = 10
    myView.layer.borderColor =  UIColor.lightGray.cgColor
    myView.layer.borderWidth = 3
    myView.layer.masksToBounds = true
    previewLayer.addSublayer(myView.layer)
    // Bring the camera button to front
    view.bringSubview(toFront: cameraButton)
    captureSession.startRunning()

无论我把这段代码放在哪里,它都不会显示出来。

    //Add circles
    let midX = screenWidth / 2
    let midY = screenHeight / 2
    let w = screenWidth
    var circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(w * 0.010), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
    let circleRads = [ 0.07, 0.13, 0.17, 0.22, 0.29, 0.36, 0.40, 0.48, 0.60, 0.75 ]
    for pct in circleRads {
        let rad = w * CGFloat(pct)
        circlePath = UIBezierPath(arcCenter: CGPoint(x: midX, y: midY), radius: CGFloat(rad), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
        circlePath.lineWidth = 2.5
        circlePath.stroke()
    }

     // draw text time stamp on image
     let now = Date()
     let formatter = DateFormatter()
     formatter.timeZone = TimeZone.current
     formatter.dateFormat = "yyyy-MM-dd HH:mm"
     let dateString = formatter.string(from: now)
     let paragraphStyle = NSMutableParagraphStyle()
     paragraphStyle.alignment = .center
     let attrs = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Thin", size: 26)!, NSAttributedStringKey.paragraphStyle: paragraphStyle]
     let string = dateString
     string.draw(with: CGRect(x: 12, y: 38, width: 448, height: 448), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)

2 个答案:

答案 0 :(得分:1)

部分回答。我可以在整个屏幕上画一个边框。这是来自AppCoda Swift 4中级iOS 11 Book的SimpleCamera应用程序。这是CameraController.swift文件的代码,在XCode中打开时,边框绘图部分是第176行到第192行。 但我仍然无法弄清楚如何让评论部分绘制一组圆圈,并在图像上加上日期标记并保存。

//
//  CameraController.swift
//  Camera
//
//  Created by Simon Ng on 16/10/2016.
//  Copyright © 2016 AppCoda. All rights reserved.
//

import UIKit
import AVFoundation
import Foundation

class CameraController: UIViewController {

@IBOutlet var cameraButton:UIButton!

//===================================
@IBOutlet weak var navigationBar: UINavigationBar!
@IBOutlet weak var imgOverlay: UIImageView!
@IBOutlet weak var btnCapture: UIButton!
@IBOutlet weak var btnInfo: UIButton!
@IBOutlet weak var btnSocial: UIButton!
@IBOutlet weak var shapeLayer: UIView!
@IBOutlet weak var btnRed: UIButton!
@IBOutlet weak var btnGreen: UIButton!
@IBOutlet weak var btnBlue: UIButton!
@IBOutlet weak var btnYellow: UIButton!
@IBOutlet weak var btnWhite: UIButton!

//===================================

var backFacingCamera: AVCaptureDevice?
var frontFacingCamera: AVCaptureDevice?
var currentDevice: AVCaptureDevice!

var stillImageOutput: AVCapturePhotoOutput!
var stillImage: UIImage?

var cameraPreviewLayer: AVCaptureVideoPreviewLayer?


let captureSession = AVCaptureSession()

var toggleCameraGestureRecognizer = UISwipeGestureRecognizer()
var zoomInGestureRecognizer = UISwipeGestureRecognizer()
var zoomOutGestureRecognizer = UISwipeGestureRecognizer()
//===============================

//let stillImageOutput = AVCaptureStillImageOutput()
var previewLayer : AVCaptureVideoPreviewLayer?


let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
var aspectRatio: CGFloat = 1.0

var viewFinderHeight: CGFloat = 0.0
var viewFinderWidth: CGFloat = 0.0
var viewFinderMarginLeft: CGFloat = 0.0
var viewFinderMarginTop: CGFloat = 0.0

var lineColor : UIColor?
var color: Int = 0
//==============================


override func viewDidLoad() {
    super.viewDidLoad()


     configure()
}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

// MARK: - Action methods

@IBAction func capture(sender: UIButton) {

    // Set photo settings
    let photoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
    photoSettings.isAutoStillImageStabilizationEnabled = true
    photoSettings.isHighResolutionPhotoEnabled = true
    photoSettings.flashMode = .off

    stillImageOutput.isHighResolutionCaptureEnabled = true
    stillImageOutput.capturePhoto(with: photoSettings, delegate: self)
}

// MARK: - Segues

@IBAction func unwindToCameraView(segue: UIStoryboardSegue) {

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // Get the new view controller using segue.destinationViewController.
    // Pass the selected object to the new view controller.
    if segue.identifier == "showPhoto" {
        let photoViewController = segue.destination as! PhotoViewController
        photoViewController.image = stillImage
    }
}

// MARK: - Helper methods

private func configure() {
    // Preset the session for taking photo in full resolution
    captureSession.sessionPreset = AVCaptureSession.Preset.photo

    // Get the front and back-facing camera for taking photos
    let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)

    for device in deviceDiscoverySession.devices {
        if device.position == .back {
            backFacingCamera = device
        } else if device.position == .front {
            frontFacingCamera = device
        }
    }

    currentDevice = backFacingCamera

    guard let captureDeviceInput = try? AVCaptureDeviceInput(device: currentDevice) else {
        return
    }

    // Configure the session with the output for capturing still images
    stillImageOutput = AVCapturePhotoOutput()

    // Configure the session with the input and the output devices
    captureSession.addInput(captureDeviceInput)
    captureSession.addOutput(stillImageOutput)

    // Provide a camera preview
    cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    view.layer.addSublayer(cameraPreviewLayer!)
    cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    cameraPreviewLayer?.frame = view.layer.frame
    //////////////

    //Add circles
    // red circles - radius in %
/*
    let midX = screenWidth / 2
    let midY = screenHeight / 2
    let w = screenWidth
    //let h = screenHeight
    var circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(w * 0.010), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
    let circleRads = [ 0.07, 0.13, 0.17, 0.22, 0.29, 0.36, 0.40, 0.48, 0.60, 0.75 ]
    for pct in circleRads {
        let rad = w * CGFloat(pct)
        circlePath = UIBezierPath(arcCenter: CGPoint(x: midX, y: midY), radius: CGFloat(rad), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi * 2), clockwise: true)
        circlePath.lineWidth = 2.5
        circlePath.stroke()
    }
     // draw text time stamp on image
     let now = Date()
     let formatter = DateFormatter()
     formatter.timeZone = TimeZone.current
     formatter.dateFormat = "yyyy-MM-dd HH:mm"
     let dateString = formatter.string(from: now)
     // print(dateString)
     let paragraphStyle = NSMutableParagraphStyle()
     paragraphStyle.alignment = .center
     let attrs = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Thin", size: 26)!, NSAttributedStringKey.paragraphStyle: paragraphStyle]
     let string = dateString
     string.draw(with: CGRect(x: 22, y: 18, width: 448, height: 448), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
     print("Did the date")
*/
    //Add Rectangular border
     let previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
     previewLayer.frame = self.view.layer.frame
     previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
     self.view.layer.addSublayer(previewLayer)

    let cgRect = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
    let myView = UIImageView()
    myView.frame = cgRect
    myView.backgroundColor = UIColor.clear
    myView.isOpaque = false
    myView.layer.cornerRadius = 10
    myView.layer.borderColor =  UIColor.lightGray.cgColor
    myView.layer.borderWidth = 3
    myView.layer.masksToBounds = true

    previewLayer.addSublayer(myView.layer)
    ///////////////

    // Bring the camera button to front
    view.bringSubview(toFront: cameraButton)
    captureSession.startRunning()


    print("so far 2")
    // Toggle Camera recognizer
    toggleCameraGestureRecognizer.direction = .up
    toggleCameraGestureRecognizer.addTarget(self, action: #selector(toggleCamera))
    view.addGestureRecognizer(toggleCameraGestureRecognizer)

    // Zoom In recognizer
    zoomInGestureRecognizer.direction = .right
    zoomInGestureRecognizer.addTarget(self, action: #selector(zoomIn))
    view.addGestureRecognizer(zoomInGestureRecognizer)

    // Zoom Out recognizer
    zoomOutGestureRecognizer.direction = .left
    zoomOutGestureRecognizer.addTarget(self, action: #selector(zoomOut))
    view.addGestureRecognizer(zoomOutGestureRecognizer)
}

@objc func toggleCamera() {
    captureSession.beginConfiguration()

    // Change the device based on the current camera
    guard let newDevice = (currentDevice?.position == AVCaptureDevice.Position.back) ? frontFacingCamera : backFacingCamera else {
        return
    }

    // Remove all inputs from the session
    for input in captureSession.inputs {
        captureSession.removeInput(input as! AVCaptureDeviceInput)
    }

    // Change to the new input
    let cameraInput:AVCaptureDeviceInput
    do {
        cameraInput = try AVCaptureDeviceInput(device: newDevice)
    } catch {
        print(error)
        return
    }

    if captureSession.canAddInput(cameraInput) {
        captureSession.addInput(cameraInput)
    }

    currentDevice = newDevice
    captureSession.commitConfiguration()
}

@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)
            }
        }
    }
}

@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)
            }
        }
    }
}
}

extension CameraController: AVCapturePhotoCaptureDelegate {

func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    guard error == nil else {
        return
    }

    // Get the image from the photo buffer
    guard let imageData = photo.fileDataRepresentation() else {
        return
    }

    stillImage = UIImage(data: imageData)
    performSegue(withIdentifier: "showPhoto", sender: self)
}

}

答案 1 :(得分:0)

你需要一个CAShapeLayer来添加bezier路径。

let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
self.view.layer.addSublayer(circleLayer)