My situation is that I have a working imagepickercontroller that allows the user to pick an image from their camera roll and display it on an imageview inside the application.
The problem is that I also want to be able to do the same thing with videos, and instead, display the video on an avplayer. I've done some research but couldn't find any good sources.
Can someone show me how to do this? possibly by editing the code below?
Thanks in advance!
This is the code I used for importing and displaying images from cameraroll (all above the viewDidLoad()):
#IBOutlet weak var imageView: UIImageView!
// the image picker controller
var imagePicker = UIImagePickerController()
// this is the button you tap to import your photo
#IBAction func imageViewButtonTapped(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum) {
imagePicker.delegate = self
imagePicker.allowsEditing = true
present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info[.editedImage] as? UIImage{
selectedImageFromPicker = editedImage
}else if let originalImage = info[.originalImage] as? UIImage{
selectedImageFromPicker = originalImage
}
if let selectedImage = selectedImageFromPicker {
imageView.image = selectedImage
}
dismiss(animated: true, completion: nil)
}
try this:
import AVFoundation
class VideoHelper {
static func startMediaBrowser(delegate: UIViewController & UINavigationControllerDelegate & UIImagePickerControllerDelegate, sourceType: UIImagePickerController.SourceType) {
guard UIImagePickerController.isSourceTypeAvailable(sourceType) else { return }
let mediaUI = UIImagePickerController()
mediaUI.sourceType = sourceType
mediaUI.mediaTypes = [kUTTypeMovie as String]
mediaUI.allowsEditing = true
mediaUI.delegate = delegate
delegate.present(mediaUI, animated: true, completion: nil)
}
}
and you can use this as:
let source = UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) ? UIImagePickerController.SourceType.camera : UIImagePickerController.SourceType.savedPhotosAlbum
VideoHelper.startMediaBrowser(delegate: self, sourceType: source)
Related
After selecting an image from camera roll, then placing it into an image view, I need to save it to user defaults.
All the code is working, but not reliably, it works maybe 3 out of 5 times.
I believe the problem is the code that adds the image into the array is not great.
I'm very new to Swift and I have no idea how to clean it up, can anyone help please?
Here is my code
class importImageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
var importImage = UIImage()
let defaults = UserDefaults.standard
#IBOutlet weak var saveScreenButton: UIButton!
#IBOutlet weak var importImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func importButton(_ sender: Any) {
let image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerController.SourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
{
//on completion
}
}
// I THINK THE PROBLEM IS IN HERE BUT I CANT SEE IT
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
{
importImageView.image = image
if case importImageView.image = image {
importImage = image
}
}
else
{
}
self.dismiss(animated: true, completion: nil)
}
func saveImage()
{
//encode image to user defaults
let imageData:NSData = importImage.pngData()! as NSData
//save image to user defaults
UserDefaults.standard.set(imageData, forKey: "screenShotImage")
}
#IBAction func saveScreenButton(_ sender: UIButton) {
saveImage()
dismiss(animated: true, completion: nil)
}
}
First of all use Data instead of NSData in saveImage()
func saveImage() {
let imageData = importImage.pngData()
UserDefaults.standard.set(imageData, forKey: "screenShotImage")
}
Now, try fetching the image from UserDefaults in viewDidLoad() and set it as importImageView's image,
override func viewDidLoad() {
super.viewDidLoad()
if let data = defaults.data(forKey: "screenShotImage"), let image = UIImage(data: data) {
importImage = image
importImageView.image = image
}
}
Also, modify the imagePickerController(_: didFinishPickingMediaWithInfo:) definition to,
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
importImageView.image = image
importImage = image
}
self.dismiss(animated: true, completion: nil)
}
I am trying to capture a picture automatically from camera without clicking the camera capture-button and i am using the UIImagePickerController for camera usage.what should I have to add for autocapture?
class ViewController:UIViewController,UINavigationControllerDelegate,UIImagePickerControllerDelegate
{
var imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
imagePicker.delegate = self
self.openCamera()
}
func openCamera() {
if(UIImagePickerController .isSourceTypeAvailable(UIImagePickerController.SourceType.camera)) {
imagePicker.sourceType = UIImagePickerController.SourceType.camera
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
} else {
let alert = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
self.imagePicker.dismiss(animated: true, completion: nil)
guard let selectedImage = info[.originalImage] as? UIImage
else{
print("Image not found!")
return
}
}
Here I am clicking the capture button. But I want to take automatically a picture after autofocusing.
It is possible using UIImagePickerController as I R&D on this functionality.
If you want to autocapture an image from camera then you can use this below mentioned code.
1. First you need to Add AVFoundation framework in your project.
Select project -> Add AVFoundation framework in Frameworks, Libraries, and Embedded Content Section
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIGestureRecognizerDelegate {
let objCaptureSession = AVCaptureSession()
var objPreviewLayer : AVCaptureVideoPreviewLayer?
var objCaptureDevice : AVCaptureDevice?
var objImagePicker = UIImagePickerController()
var objTimer: Timer?
var flagRepeatRecording: Bool = false
var objOutputVolumeObserve: NSKeyValueObservation?
let objAudioSession = AVAudioSession.sharedInstance()
override func viewDidAppear(_ animated: Bool) {
if !flagRepeatRecording {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
objImagePicker = UIImagePickerController()
objImagePicker.delegate = self
objImagePicker.sourceType = .camera
objImagePicker.allowsEditing = false
objImagePicker.showsCameraControls = false
//imagePicker.mediaTypes = [kUTTypeMovie as String] // If you want to start auto recording video by camera
} else {
debugPrint("Simulator has no camera")
}
self.present(self.objImagePicker, animated: true, completion: {
self.objImagePicker.takePicture() // If you want you auto start video capturing then replace this code with take picture() method startVideoCapture()
NotificationCenter.default.addObserver(self, selector: #selector(self.cameraIsReady), name: .AVCaptureSessionDidStartRunning, object: nil)
flagRepeatRecording = true
}
}
#objc func cameraIsReady(notification: NSNotification) {
DispatchQueue.main.async {
self.objImagePicker.takePicture()
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// let tempImage = info[UIImagePickerController.InfoKey.mediaURL] as! NSURL?
// let pathString = tempImage?.relativePath
self.dismiss(animated: true, completion: {})
// UISaveVideoAtPathToSavedPhotosAlbum(pathString!, self, nil, nil)
self.objTimer?.invalidate()
self.objTimer = nil
}
}
In my application the user can either open the camera roll to select a picture or open the camera to take directly one by himself.
In both cases, the picture selected/taken will also be saved locally for further reference.
The downside is that the saving operation usually freeze the screen until it is finished.
I found an animation in this post and I want to display it in front of the imagePickerController but I can't manage to do so.
class SinglePageViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate, UINavigationBarDelegate {
var spinner: UIActivityIndicatorView?
lazy var showCameraImagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera
imagePicker.allowsEditing = false
return imagePicker
}()
lazy var showPhotoImagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
return imagePicker
}()
#IBOutlet weak var photoButton: UIButton!
#IBAction func onPhotoButton(_ sender: Any) {
self.present(self.showCameraImagePickerController, animated: true, completion: nil)
}
#IBOutlet weak var galleryButton: UIButton!
#IBAction func onGalleryButton(_ sender: Any) {
self.present(self.showPhotoImagePickerController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
//start animation
let screenSize: CGRect = UIScreen.main.bounds
spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width / 2 - 150, y: screenSize.height / 2 - 150, width: 300, height: 300))
spinner?.isHidden = false
spinner?.startAnimating()
spinner?.color = UIColor.red
switch picker {
case showCameraImagePickerController:
// snap pic, save to doc, save to album
self.showCameraImagePickerController.view.addSubview(spinner!)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: { _ in
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image) {
// additionally save to photo album
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
print("saved \(self.titleLabel.text!).png")
self.imageView.image = image
}
})
case showPhotoImagePickerController:
//switch pic, save to doc. no album
self.showPhotoImagePickerController.view.addSubview(spinner!)
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false, block: { _ in
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
if self.saveImage(imageName: "\(self.titleLabel.text!).png", image: image) {
print("saved new \(self.titleLabel.text!).png")
self.imageView.image = image
self.spinner?.stopAnimating()
self.spinner?.removeFromSuperview()
self.spinner = nil
self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)
} else {
self.spinner?.stopAnimating()
self.spinner?.removeFromSuperview()
self.spinner = nil
self.showPhotoImagePickerController.dismiss(animated: true, completion: nil)
}
})
default:
return
}
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
spinner?.stopAnimating()
spinner?.removeFromSuperview()
spinner = nil
self.showCameraImagePickerController.dismiss(animated: true, completion: nil)
}
func saveImage(imageName: String, image: UIImage?) -> Bool {
//create an instance of the FileManager
let fileManager = FileManager.default
//get the image path
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imgDir + imageName)
print(imagePath)
//get the image we took with camera
let image = rotateImage(image: image!)
//get the PNG data for this image
let data = UIImagePNGRepresentation(image)
//store it in the document directory
if fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil) {
newItem?.image = true
return true
} else {
print("error while saving")
return false
}
}
}
as you can see I tried playing with bringSubView(toFront:) and also with the zPosition but with no results.
following this similar question I looked into the documentation for cameraOverlayView but it says that it only works when the imagePicker is presented in camera mode, which doesn't cover the case when I open the photo library
I also recently tried to use a workaround, meaning that I dismiss the imagePickerController as soon as possible and update the image afterwards, but that is not optimal anymore because of some changes in the structure of app.
EDIT
to make myself clearer I'll state again what I need: show the spinner animation in front of the imagePicker, as soon as I tap a photo to choose it, and until I finish saving, then dismiss the imagePicker.
I do not want to first dismiss the picker and then save while showing the spinner in the main view.
EDIT2
updated the code with the new one from the answer. only problem is that if I don't put a timer the spinner shows itself only at the end of the saving process for a brief moment (checked with breakpoints).
This results in no animation during the couple of seconds of saving process and just a brief apparition of the spinner at the end before dismissing the imagePicker.
Just putting a 0.1sec delay triggers the spinner immediately and I get the expected behaviour (animation while saving).
No idea why
Please see a complete example where spinner will show while the image is being saved and once finishes saving spinner will be removed.
class ViewController: UIViewController {
/// Image picker controller
lazy var imagePickerController: UIImagePickerController = {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary;
imagePicker.allowsEditing = false
return imagePicker
}()
var spinner: UIActivityIndicatorView?
#IBAction func imagePickerButton(_ sender: UIButton) {
self.present(self.imagePickerController, animated: true, completion: nil)
}
}
// MARK: ImagePicker Delegate to get the image picked by the user
extension ViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
//start animation
let screenSize: CGRect = UIScreen.main.bounds
spinner = UIActivityIndicatorView(frame: CGRect(x: screenSize.width/2 - 50, y: screenSize.height/2 - 50, width: 100, height: 100))
spinner?.isHidden = false
spinner?.startAnimating()
spinner?.color = UIColor.black
self.imagePickerController.view.addSubview(spinner!)
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
UIImageWriteToSavedPhotosAlbum(image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
#objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
spinner?.stopAnimating()
spinner?.removeFromSuperview()
spinner = nil
self.imagePickerController.dismiss(animated: true, completion: nil)
if error == nil {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
}
Im trying to get image from gallery in Swift.
func showPicker(type : UIImagePickerControllerSourceType) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = type
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
then:
self.showPicker(type: .savedPhotosAlbum)
However, when i enter gallery on my device and pick photo nothing happen, instead in log it says : [Generic] Creating an image format with an unknown type is an error
How to dismiss gallery and save image?
UIImagepickerView
set delegate UIImagePickerControllerDelegate, UINavigationControllerDelegate
let imagePicker = UIImagePickerController()
//in did load
imagePicker.delegate = self
// MARK: - UIImagePickerControllerDelegate Methods
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
imgview.image = image
} else{
print("Something went wrong")
}
dismiss(animated: true, completion: nil)
}
I am asking if it is possible to set the image of a UIImageView using a gestureRecognizer, or is it necessary to overlay a button on top of the UIImageView.
I have an outlet collection of UIImageViews, called imageViews. There are four of these, and their tags have been set from 1 to 4. In my viewDidLoad, to add the gesture recognizer to each of the image views in the collection, i have used:
override func viewDidLoad() {
super.viewDidLoad()
for i in (0..<imageViews.count) {
let imageViewTapped = UITapGestureRecognizer(target: self, action: #selector(selectImage(tap:)))
imageViewTapped.numberOfTapsRequired = 1
imageViews[i].addGestureRecognizer(imageViewTapped)
}
}
Next, I created my gestureRecognizer as a function in the viewController class. This is where the image picker controller is created and where the image view that was tapped is identified:
func selectImage(tap: UITapGestureRecognizer) {
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
imagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
self.present(imagePicker, animated: true, completion: nil)
guard let viewTappedTag = tap.view?.tag else {return}
self.selectedImageView = imageViews[viewTappedTag - 1]
}
selectedImageView is a variable in the viewController class with a type of UIImageView. My thinking was that this variable could hold the UIImageView that was tapped, which is identified by the gestureRecognizer, as shown above. This could then be passed to the delegate later on.
Next, I created the delegates, the didFinishPickingMediaWithInfo and didCancel, though I will only show the former for brevity. Both were created inside the viewController class:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var chosenImage = UIImage()
chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.selectedImageView.image = chosenImage
dismiss(animated: true, completion: nil)
}
Unfortunatley, the image of the image view that was tapped is not updated to the one that was chosen from the library. What is the correct way to do this? And I feel as though I am bloating my viewController with all of this code, can this be moved to a seperate class? Am i wrong in doing it like this, and instead one should just overlay a button?
EDIT
The best I could come up with so far is a switch statement in my imagePickerController, where imageViewOne, imageViewTwo etc are outlets for each UIImageView:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var chosenImage = UIImage()
chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
switch self.viewTappedTag {
case 1:
imageViewOne.image = chosenImage
case 2:
imageViewTwo.image = chosenImage
case 3:
imageViewThree.image = chosenImage
case 4:
imageViewFour.image = chosenImage
default:
imageViewOne.image = chosenImage
}
dismiss(animated: true, completion: nil)
}
where viewTappedTag is a viewController class variable, the value of which is defined by the tag of the view that was tapped and is set in the gestureRecognizer. Can anyone improve on this?
Update the code as following
Declare a variable in the class as follows
var selectedImageViewIndex = 0 //by default selected image view is 0th image view
func selectImage(tap: UITapGestureRecognizer) {
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = false
imagePicker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
self.present(imagePicker, animated: true, completion: nil)
guard let viewTappedTag = tap.view?.tag else {return}
self.selectedImageView = imageViews[viewTappedTag - 1]
//Add the following line
self.selectedImageViewIndex = viewTappedTag - 1
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var chosenImage = UIImage()
chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.selectedImageView.image = chosenImage
//Add the following line
self.imageView[self.selectedImageViewIndex].image = chosenImage
dismiss(animated: true, completion: nil)
}
Though I would advice not to use viewTappedTag - 1 and instead get the value of index and tapped image tag from a mapped object.
In the end I used a switch statement to achieve my goal:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var chosenImage = UIImage()
chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
switch self.viewTappedTag {
case 1:
imageViewOne.image = chosenImage
case 2:
imageViewTwo.image = chosenImage
case 3:
imageViewThree.image = chosenImage
case 4:
imageViewFour.image = chosenImage
default:
imageViewOne.image = chosenImage
}
dismiss(animated: true, completion: nil)
}