Micah Montoya
Micah Montoya

Reputation: 767

Swift 3 taking picture and saving

Working in Swift 3. I found numerous questions with answers and then also blogs, yet everything I've tried didn't work. I am just trying to capture a camera shot I take and save it to the documents. But it isn't being saved as it doesn't show up under devices documents when viewed from within xcode and I don't get any errors or similar. I'm at a bit of a lost here.

Code that have for getting the image and saving it

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
    var pickedImage = UIImage()
    pickedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
    picker.dismiss(animated: true, completion: nil)

    let currentDateTime = Date()
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyyMMddHHmmss"
    let fileNameWithExtension = "ts_\(formatter.string(from: currentDateTime)).png"
    //create path
    let imagePath = fileInDocumentsDirectory(filename: fileNameWithExtension)
    imageStringPathSet = fileNameWithExtension
    imageSet = pickedImage

    if saveImage(image: pickedImage, path: imagePath) {
        cameraButton.setImage(#imageLiteral(resourceName: "ic_camerashot_yes60dp"), for: UIControlState.normal)
        return
    }
    cameraButton.setImage(#imageLiteral(resourceName: "ic_camerashot_no60dp"), for: UIControlState.normal)
}
func fileInDocumentsDirectory(filename: String)-> URL {
    return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(filename)
}
func saveImage(image: UIImage, path: URL) -> Bool {
    print(path)
    guard let pngImageData = UIImagePNGRepresentation(image) else {
        print("error")
        return false
    }

    var resultValid = false
    do {
        let results = try pngImageData.write(to: path, options: [.atomicWrite])
        print(results) //prints ()
        resultValid = true
    }
    catch {
        resultValid = false
        print(error)
    }
    return resultValid
}

When I print the path it prints

file:///var/mobile/Containers/Data/Application/01EB6A70-34C6-4481-BE5B-7F7AB5E6703F/Documents/ts_20161221145652.png

Which I believe is correct. If everything works correctly, it changes an image on the screen yet it never changes and the imageStringPathSet isn't set either which is a class variable. Anyone have any ideas on what I need to do to get this to work?

Solution

Turns out the cause was that I was resetting everything in the view in viewWillAppear. Once I fixed this, things worked fine. Thanks everyone for your feedback. Hope this helps someone else to not do what I did.

Upvotes: 0

Views: 2377

Answers (1)

user7014451
user7014451

Reputation:

As per the request in the comments, here's my code that (a) uses the UIImagePickerController to either select from the camera roll, then (b) uses the UIActivityViewController to let the user choose among several possible ways to save/attach the image to several sources of output.

While this isn't saving to the document directory, it may be a better route to go. Please pay attention to a few notes after the code listing.

My "select" view controller, which allows a user to either pick from the camera roll or take a picture:

extension SelectViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    // MARK: Camera App

    func openCameraApp() {
        if UIImagePickerController.availableCaptureModes(for: .rear) != nil {
            picker.allowsEditing = false
            picker.sourceType = UIImagePickerControllerSourceType.camera
            picker.cameraCaptureMode = .photo
            picker.modalPresentationStyle = .fullScreen
            present(picker,
                    animated: true,
                    completion: nil)
        } else {
            noCamera()
        }
    }
    func noCamera(){
        let alertVC = UIAlertController(
            title: "No Camera",
            message: "Sorry, this device has no camera",
            preferredStyle: .alert)
        let okAction = UIAlertAction(
            title: "OK",
            style:.default,
            handler: nil)
        alertVC.addAction(okAction)
        present(
            alertVC,
            animated: true,
            completion: nil)
    }

    // MARK: Photos Albums

    func showImagePicker() {
        picker.allowsEditing = false
        picker.sourceType = .photoLibrary
        //        picker.modalPresentationStyle = .Popover
        present(picker,
                animated: true,
                completion: nil)
        picker.popoverPresentationController?.sourceView = self.view
    }
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
        image = chosenImage
        self.performSegue(withIdentifier: "ShowEditView", sender: self)
        dismiss(animated: true, completion: nil)
    }
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        dismiss(animated: false, completion: nil)
    }

    // MARK: Seque to EditViewController

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ShowEditView" {
            if let vc = segue.destination as? EditViewController {
                vc.image = image
            }
        }
    }
}

My "edit" view controller, which is embedded in a UINavigationBar with a button on it set to System Item == Action:

// MARK: Image actions

@IBAction func shareImage(_ sender: UIBarButtonItem) {
    let context = CIContext()
    let final = context.createCGImage(imgEdited, from: imgEdited.extent)
    let shareImage = UIImage(cgImage: final!)
    let vc = UIActivityViewController(activityItems: [shareImage], applicationActivities: [])
    vc.excludedActivityTypes =  [
        //UIActivityTypePostToTwitter,
        //UIActivityTypePostToFacebook,
        UIActivityType.postToWeibo,
        //UIActivityTypeMessage,
        //UIActivityTypeMail,
        UIActivityType.print,
        //UIActivityTypeCopyToPasteboard,
        UIActivityType.assignToContact,
        //UIActivityTypeSaveToCameraRoll,
        UIActivityType.addToReadingList,
        //UIActivityTypePostToFlickr,
        UIActivityType.postToVimeo,
        UIActivityType.postToTencentWeibo
    ]
    present(vc,
                            animated: true,
                            completion: nil)
    vc.popoverPresentationController?.sourceView = self.view
    vc.completionWithItemsHandler = {(activity, success, items, error) in
    }
}

Notes:

  • Keep in mind that when using the UIImagePickerController in an iOS 10 device, it will crash unless you add this to your info.plist:

    <key>NSCameraUsageDescription</key>
    <string>Used to capture new image for photo effect</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Used to select an image for photo effect</string>
    

    You may use whatever you wish in the tag.

  • The UIActivityViewController will present all commented out options in it's excludedActivityTypes. (I keep these options listed just for self documentation.) If a user has Facebook and wants to post to it, they'll be prompted to login if they aren't yet.

Upvotes: 1

Related Questions