Search code examples
iosswiftcameraavcapturesession

Pictures taken with the camera come out really dark on iOS w/ Swift


The camera preview looks perfect, but when I take a picture and save it to the Camera Roll the picture comes out extremely dark. Tried a bunch of threads on here but nothing solved it. Here's my code.

This sets up the camera/preview and works fine:

 captureSession.sessionPreset = AVCaptureSessionPreset640x480

        let devices = AVCaptureDevice.devices()

        // 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 as? AVCaptureDevice
                }
            }
        }

        if captureDevice != nil {
            beginSession()
        }

func beginSession() {
    var err : NSError? = nil

    if captureSession.canAddInput(AVCaptureDeviceInput(device: captureDevice, error: &err)) {
        captureSession.addInput(AVCaptureDeviceInput(device: captureDevice, error: &err))

        if err != nil {
            println("error: \(err?.localizedDescription)")
        }

        let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        self.view.layer.addSublayer(previewLayer)
        self.view.bringSubviewToFront(cameraButton)
        previewLayer?.frame = self.view.layer.frame

        // start camera
        captureSession.startRunning()

   }

This is called when the picture is taken:

@IBAction func photoTaken(sender: UIButton) {

    stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
    if captureSession.canAddOutput(stillImageOutput) {
        captureSession.addOutput(stillImageOutput)
    }
    var videoConnection = stillImageOutput.connectionWithMediaType(AVMediaTypeVideo)

    if videoConnection != nil {

        // Show next step button
        self.view.bringSubviewToFront(self.nextStep)
        self.nextStep.hidden = false

        // Secure image
        stillImageOutput.captureStillImageAsynchronouslyFromConnection(videoConnection) {
            (imageDataSampleBuffer, error) -> Void in
                var imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)

                self.image = UIImage(data: imageData)

        }

        // Freeze camera preview
        captureSession.stopRunning()


    }

}

This is called after the picture is taken when the user hits the button to proceed (it saves the image to the camera roll for now, but will eventually do more when I get the images to look good):

@IBAction func nextStepTapped(sender: UIButton) {

    // Save to camera roll & proceeed
    UIImageWriteToSavedPhotosAlbum(self.image, nil, nil, nil)

}

My guess is that the issue is within the photoTaken() function, but I have no idea. This is my first time writing an app in Swift/Xcode, so any help would greatly be appreciated. Again, the issue is that the saved photo is extremely dark and I've tried pretty much everything I could find on the internet related to this problem, but nothing works. Thanks!

Edit: Might be worth noting that I'm testing this on an iPhone 4S. Could that have anything to do with it?


Solution

  • The issue was that I was calling this as the photo was being taken:

     stillImageOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
         if captureSession.canAddOutput(stillImageOutput) {
             captureSession.addOutput(stillImageOutput)
         }
    

    I moved that section from photoTaken() (called when a picture is taken) to beginSession() (called to initiate the camera) and now it works. Setting up the output after the photo button was pressed probably caused a lag/delay and didn't enable the camera to fully go through the motions.