I've downloaded AVCam app sample from Apple. I added a custom view "GridView" on top of PreviewView, but i would like to size my GridView in order draw my grid on top of the captured image.
How can i get the bound of the capture image?
thanks
You can do something like this:
1- Create a gird
import Foundation
import UIKit
class GridView: UIView
{
private var path = UIBezierPath()
fileprivate var gridWidthMultiple: CGFloat
{
return 4
}
fileprivate var gridHeightMultiple : CGFloat
{
return 4
}
fileprivate var gridWidth: CGFloat
{
return bounds.width/CGFloat(gridWidthMultiple)
}
fileprivate var gridHeight: CGFloat
{
return bounds.height/CGFloat(gridHeightMultiple)
}
fileprivate var gridCenter: CGPoint {
return CGPoint(x: bounds.midX, y: bounds.midY)
}
fileprivate func drawGrid()
{
path = UIBezierPath()
path.lineWidth = 2.0
for index in 1...Int(gridWidthMultiple) - 1
{
let start = CGPoint(x: CGFloat(index) * gridWidth, y: 0)
let end = CGPoint(x: CGFloat(index) * gridWidth, y:bounds.height)
path.move(to: start)
path.addLine(to: end)
}
for index in 1...Int(gridHeightMultiple) - 1 {
let start = CGPoint(x: 0, y: CGFloat(index) * gridHeight)
let end = CGPoint(x: bounds.width, y: CGFloat(index) * gridHeight)
path.move(to: start)
path.addLine(to: end)
}
//Close the path.
path.close()
}
override func draw(_ rect: CGRect)
{
drawGrid()
// Specify a border (stroke) color.
UIColor.systemYellow.setStroke()
path.stroke()
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
2- In ViewController
define a grid var:
var gridView: GridView!
func addGrid() {
gridView = GridView(frame: previewView.bounds)
previewView.addSubview(gridView)
}
Add call addGrid in viewdidLoad or anywhere that suits you.
Then we need to update the frame of the gridView based on the displayed camera live view.
func updateGrid() {
DispatchQueue.main.async {
let p1 = self.previewView.videoPreviewLayer.layerPointConverted(fromCaptureDevicePoint: .zero)
let p2 = self.previewView.videoPreviewLayer.layerPointConverted(fromCaptureDevicePoint: CGPoint(x: 1, y: 1))
self.gridView.frame = CGRect(x: 0, y: p1.y, width: p1.x, height: p2.y - p1.y)
}
}
You call call updateGrid wherever best suits in your case. In here I called it in viewWillAppear after the session starts running:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
sessionQueue.async {
switch self.setupResult {
case .success:
// Only setup observers and start the session if setup succeeded.
self.addObservers()
self.session.startRunning()
self.isSessionRunning = self.session.isRunning
self.updateGrid()
case .notAuthorized:
DispatchQueue.main.async {
let changePrivacySetting = "AVCam doesn't have permission to use the camera, please change privacy settings"
let message = NSLocalizedString(changePrivacySetting, comment: "Alert message when the user has denied access to the camera")
let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"),
style: .cancel,
handler: nil))
alertController.addAction(UIAlertAction(title: NSLocalizedString("Settings", comment: "Alert button to open Settings"),
style: .`default`,
handler: { _ in
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!,
options: [:],
completionHandler: nil)
}))
self.present(alertController, animated: true, completion: nil)
}
case .configurationFailed:
DispatchQueue.main.async {
let alertMsg = "Alert message when something goes wrong during capture session configuration"
let message = NSLocalizedString("Unable to capture media", comment: alertMsg)
let alertController = UIAlertController(title: "AVCam", message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Alert OK button"),
style: .cancel,
handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}
}
}
Output