简体   繁体   中英

How to add a rectangle mask inside the camera custom view in swift?

在此处输入图像描述

I have a custom view which I added as a view on top of camera layer.

I only want to capture a picture which fits the rectangle. However I can't figure out how to add that rectangle as a transparent mask inside camera layer.

Any advices or code snippets would be highly appreciated!

I implemented @Sasha's answer to be used in a custom camera. Below is my function to create the mask.

func createOverlay() -> UIView {
    let overlayView = UIView(frame: view.frame)
    overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.7)

    let path = CGMutablePath()

    path.addRoundedRect(in: CGRect(x: 50, y: 100, width: overlayView.frame.width-100, height: overlayView.frame.height - 300), cornerWidth: 5, cornerHeight: 5)

    
    path.closeSubpath()
    
    let shape = CAShapeLayer()
    shape.path = path
    shape.lineWidth = 5.0
    shape.strokeColor = UIColor.white.cgColor
    shape.fillColor = UIColor.white.cgColor
    
    overlayView.layer.addSublayer(shape)
    
    path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))

    let maskLayer = CAShapeLayer()
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.path = path
    maskLayer.fillRule = CAShapeLayerFillRule.evenOdd

    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true
    
    return overlayView
}

And I add it in to my custom camera preview layer using this function:

func setupPreviewLayer() {
    self.cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    self.cameraPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
    self.cameraPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
    self.cameraPreviewLayer?.frame = self.view.bounds
    self.view.layer.insertSublayer(cameraPreviewLayer!, at: 0)
    let overlay = createOverlay()
    self.view.addSubview(overlay)
}

The final product looks like this: Object Detection Frame

For my convenience, I've implemented this inside a viewDidLoad method and used a circle but not a rectangle. Also I'm addressing your issue mentioned;

However I can't figure out how to add that rectangle as a transparent mask inside camera layer.

Here is my full code.

import UIKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var cameraPreviewView: UIView!
    @IBOutlet weak var overlayView: UIView!

    var session: AVCaptureSession?
    var stillImageOutput: AVCapturePhotoOutput?
    var videoPreviewLayer: AVCaptureVideoPreviewLayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        session = AVCaptureSession()
        session?.sessionPreset = AVCaptureSession.Preset.photo

        let backCamera =  AVCaptureDevice.default(for: AVMediaType.video)
        var error: NSError?
        var input: AVCaptureDeviceInput!

        do {
            input = try AVCaptureDeviceInput(device: backCamera!)
        } catch let error1 as NSError {
            error = error1
            input = nil
        }

        if error == nil && (session?.canAddInput(input))! {
            session?.addInput(input)
            stillImageOutput = AVCapturePhotoOutput()
        }

        if (session?.canAddOutput(stillImageOutput!))! {
            session?.addOutput(stillImageOutput!)
            videoPreviewLayer = AVCaptureVideoPreviewLayer(session: session!)
            videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
            videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
            cameraPreviewView.layer.addSublayer(videoPreviewLayer!)
            session?.startRunning()

            // I'm adding a circle not a rectangle. Make that adjustment in your code.
            let radius : CGFloat = 50.0
            let xOffset : CGFloat = 100 //  Position according to your wish
            let yOffset : CGFloat = 100 //  Position according to your wish

            let path = CGMutablePath()

            path.addArc(center: CGPoint(x: xOffset, y: yOffset),
                        radius: radius,
                        startAngle: 0.0,
                        endAngle: 2.0 * .pi,
                        clockwise: false)

            path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))

            let maskLayer = CAShapeLayer()
            maskLayer.backgroundColor = UIColor.black.cgColor
            maskLayer.path = path
            maskLayer.fillRule = .evenOdd

            overlayView.layer.mask = maskLayer
            overlayView.clipsToBounds = true
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        videoPreviewLayer?.frame = cameraPreviewView.bounds
    }
}

Make sure to add Privacy - Camera Usage Description inside your info.plist file.

Here is rectangle mask with rounded corners with borders

var overlay: UIView = UIView()

func createOverlay() -> UIView {
    
    let overlayView = UIView(frame: view.frame)
    overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.4)



    let path = CGMutablePath()

    path.addRoundedRect(in: CGRect(x: 15, y: overlayView.center.y-100, width: overlayView.frame.width-30, height: 200), cornerWidth: 5, cornerHeight: 5)

    
    path.closeSubpath()
    
    let shape = CAShapeLayer()
    shape.path = path
    shape.lineWidth = 3.0
    shape.strokeColor = UIColor.blue.cgColor
    shape.fillColor = UIColor.blue.cgColor
    
    overlayView.layer.addSublayer(shape)
    
    path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))

    let maskLayer = CAShapeLayer()
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.path = path
    maskLayer.fillRule = CAShapeLayerFillRule.evenOdd

    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true
    
    return overlayView
}

func addTransparentOverlayWithCirlce(){
    overlay = createOverlay()
    view.addSubview(overlay)
    self.view.sendSubviewToBack(overlay)
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM