Добавление объектов поверх камеры в приложении (Swift 3), а не в камере?

У меня есть наложение поверх вида камеры, состоящее из красных кружков, которое хранится в заполнителях Assets.xcasset ImgOverlay, а вид с камеры (предварительный просмотр) отображается позади или под наложением. Все в порядке. Так, как это должно быть. Когда я запускаю приложение на iPhone, наложение выглядит так, как должно. См. Рис.1 Но у меня также нарисован синий круг, который находится под обзором камеры и появляется только в том случае, если вид с камеры отсутствует. То есть выключить или запустить на симуляторе. См. Рис.2 ниже.

Рисунок 1. Красные круги над камерой, в iPhone

Рисунок 2. Красные круги, включая нарисованный синий круг в симуляторе. Код, который у меня есть, находится здесь. Я делаю что-то не так, но не вижу этого. Мне нужны синие круги, видимые в iPhone, а не только в симуляторе. Я пытаюсь нарисовать все круги, поэтому я могу отказаться от красных кругов, которые находятся в файле типа image.png. Я предпочитаю рисовать круги для большей точности на любом устройстве и отображать их вместо красных кругов, а затем сохранять составное изображение кругов и вид с камеры. Мне пока не удалось объединить изображения при сохранении, но первый шаг на iPhone - это увидеть синий круг... Так что он почти полностью работает. Я не вижу, что я делаю не так?

ViewController.swift

import UIKit
import AVFoundation
import Foundation

class ViewController: UIViewController {

@IBOutlet weak var navigationBar: UINavigationBar!
@IBOutlet weak var imgOverlay: UIImageView!
@IBOutlet weak var btnCapture: UIButton!

@IBOutlet weak var shapeLayer: UIView!

let captureSession = AVCaptureSession()
let stillImageOutput = AVCaptureStillImageOutput()
var previewLayer : AVCaptureVideoPreviewLayer?

//var shapeLayer : CALayer?

// If we find a device we'll store it here for later use
var captureDevice : AVCaptureDevice?

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    //=======================

    let midX = self.view.bounds.midX
    let midY = self.view.bounds.midY

    let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)

    let shapeLayer = CAShapeLayer()

    shapeLayer.path = circlePath.cgPath
    //change the fill color
    shapeLayer.fillColor = UIColor.clear.cgColor
    //you can change the stroke color
    shapeLayer.strokeColor = UIColor.blue.cgColor
    //you can change the line width
    shapeLayer.lineWidth = 2.5

    view.layer.addSublayer(shapeLayer)
    print("Shape layer drawn")
    //=====================
    captureSession.sessionPreset = AVCaptureSessionPresetHigh

    if let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] {
        // Loop through all the capture devices on this phone
        for device in devices {
            // Make sure this particular device supports video
            if (device.hasMediaType(AVMediaTypeVideo)) {
                // Finally check the position and confirm we've got the back camera
                if(device.position == AVCaptureDevicePosition.back) {
                    captureDevice = device
                    if captureDevice != nil {
                        print("Capture device found")
                        beginSession()
                    }
                }
            }
        }
    }
}

@IBAction func actionCameraCapture(_ sender: AnyObject) {

    print("Camera button pressed")
    saveToCamera()
}

func beginSession() {

    do {
        try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
        stillImageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]

        if captureSession.canAddOutput(stillImageOutput) {
            captureSession.addOutput(stillImageOutput)
        }

    }
    catch {
        print("error: \(error.localizedDescription)")
    }

    guard let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) else {
        print("no preview layer")
        return
    }
    // this is what displays the camera view. But - it's on TOP of the drawn view, and under the overview. ??
    self.view.layer.addSublayer(previewLayer)
    previewLayer.frame = self.view.layer.frame



    captureSession.startRunning()
    print("Capture session running")


    self.view.addSubview(navigationBar)
    self.view.addSubview(imgOverlay)
    self.view.addSubview(btnCapture)
        }

func saveToCamera() {

    if let videoConnection = stillImageOutput.connection(withMediaType: AVMediaTypeVideo) {
          stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (CMSampleBuffer, Error) in

            if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(CMSampleBuffer) {
                if let cameraImage = UIImage(data: imageData) {


                   UIImageWriteToSavedPhotosAlbum(cameraImage, nil, nil, nil)

                }
            }
        })
    }
}



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

}

1 ответ

Решение

Ты очень близко...

У тебя есть:

@IBOutlet weak var shapeLayer: UIView!

но затем вы также создаете CAShapeLayer с именем shapeLayer:

let shapeLayer = CAShapeLayer()

который вы добавляете в качестве подслоя вашего "основного" представления. Затем вы добавляете все остальное поверх вашего основного вида, покрывая shapeLayer.

В viewDidLoad() измените раздел рисования синих кругов на этот:

    let midX = self.view.bounds.midX
    let midY = self.view.bounds.midY

    let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)

    let shapeLayerPath = CAShapeLayer()

    shapeLayerPath.path = circlePath.cgPath
    //change the fill color
    shapeLayerPath.fillColor = UIColor.clear.cgColor
    //you can change the stroke color
    shapeLayerPath.strokeColor = UIColor.blue.cgColor
    //you can change the line width
    shapeLayerPath.lineWidth = 2.5

    // add the blue-circle layer to the shapeLayer ImageView
    shapeLayer.layer.addSublayer(shapeLayerPath)

    print("Shape layer drawn")
    //=====================

Затем в конце beginSession()...

    self.view.addSubview(navigationBar)
    self.view.addSubview(imgOverlay)
    self.view.addSubview(btnCapture)

    // shapeLayer ImageView is already a subview created in IB
    // but this will bring it to the front
    self.view.addSubview(shapeLayer)

    // note: since these elements are added as @IBOutlet in IB,
    // these could be:

    // self.view.bringSubview(toFront: navigationBar)
    // self.view.bringSubview(toFront: imgOverlay)
    // self.view.bringSubview(toFront: btnCapture)
    // self.view.bringSubview(toFront: shapeLayer)

Посмотрите, что вы получите:)

Редактировать: следующий вопрос перенесен в " Объединение изображений в CameraView с наложением". (Свифт 3)?

Другие вопросы по тегам