Got the following. I made a simple IOS / Swift app that needs to send an image to a specific e-mail. What i already got working:
Take picture
Grap picture from existing photo's
Image is shown in Image View
Send button thats leads me to mail with already configured: recipient, subject and messagebody.
What i need to get working is how i can add the selected image from Image View to be added to the e-mail when i press send.
Following code is the one i use:
FOR TAKING AND SELECTING IMAGES:
#IBOutlet var imageView: UIImageView!
#IBOutlet weak var PicLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func FotoKnop(sender: AnyObject) {
}
#IBAction func chooseImageFromPhotoLibrary() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .PhotoLibrary
presentViewController(picker, animated: true, completion: nil)
}
#IBAction func chooseFromCamera() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .Camera
presentViewController(picker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
imageView.image = image
self.dismissViewControllerAnimated(true, completion: nil)
}
For e-mail
#IBAction func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["jvanhattem#it-serve.nl"])
mailComposerVC.setSubject("Mail vanuit PicMail")
mailComposerVC.setMessageBody("Onderstaand de doorgestuurde informatie", isHTML:
false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate Method
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
Any thoughts would be great!
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["jvanhattem#it-serve.nl"])
mailComposerVC.setSubject("Mail vanuit PicMail")
mailComposerVC.setMessageBody("Onderstaand de doorgestuurde informatie", isHTML:
false)
//Add Image as Attachment
if let image = imageView.image {
let data = UIImageJPEGRepresentation(image, 1.0)
mailComposerVC.addAttachmentData(data!, mimeType: "image/jpg", fileName: "image")
}
return mailComposerVC
}
Related
I have a slight problem. I'm trying to make a camera in Swift Xcode, however, I've run into one problem and that is that "ImagePicked.image = image" keeps showing error. I have no idea why it does this. Photo of the interface of the app
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var ImagePicked: UIImageView!
#IBAction func openCamera(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera) { //Is the camera an available source type?
let imagePicker = UIImagePickerController() //Declare variable imagePicker
imagePicker.delegate = self
imagePicker.sourceType = .camera;
imagePicker.allowsEditing = false //Tell Image Pickr not to edit camptured photo
self.present(imagePicker, animated: true, completion: nil) //Show the photo to the user
}
func openLibrary(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { //Check if device has access to photo library
let imagePicker = UIImagePickerController() //Set up variable imagePicker
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary; //Set the source type to library
imagePicker.allowsEditing = true //Allow editing, so the user can move and crop their photo
self.present(imagePicker, animated: true, completion: nil) //Show UIImagePickerController to the user
}
}
func saveImage(_ sender: Any) {
let ImageData = ImagePicked.image!.jpegData(compressionQuality: 0.6)
let compressedJPGImage = UIImage(data: ImageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPGImage!, nil, nil, nil)
let alertController = UIAlertController(title: "Complete", message: "Your image has been saved.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default); alertController.addAction(okAction); self.present(alertController, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard (info[.originalImage] as? UIImage) != nil else {
fatalError ("Expected a dictionary containtaining an image, but was provided with the following: \(info)")
ImagePicked.image = image //PROBLEM
dismiss(animated: true, completion: nil)
}
}
func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
}
Update didFinishPickingMediaWithInfo as below,
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
guard let image = info[.originalImage] as? UIImage else { return }
ImagePicked.image = image
picker.dismiss(animated: true, completion: nil)
}
As #rmaddy commented, you should rearrange the methods as below,
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var ImagePicked: UIImageView!
#IBAction func openCamera(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera) { //Is the camera an available source type?
let imagePicker = UIImagePickerController() //Declare variable imagePicker
imagePicker.delegate = self
imagePicker.sourceType = .camera;
imagePicker.allowsEditing = false //Tell Image Pickr not to edit camptured photo
self.present(imagePicker, animated: true, completion: nil) //Show the photo to the user
}
}
func openLibrary(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { //Check if device has access to photo library
let imagePicker = UIImagePickerController() //Set up variable imagePicker
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary; //Set the source type to library
imagePicker.allowsEditing = true //Allow editing, so the user can move and crop their photo
self.present(imagePicker, animated: true, completion: nil) //Show UIImagePickerController to the user
}
}
func saveImage(_ sender: Any) {
let ImageData = ImagePicked.image!.jpegData(compressionQuality: 0.6)
let compressedJPGImage = UIImage(data: ImageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPGImage!, nil, nil, nil)
let alertController = UIAlertController(title: "Complete", message: "Your image has been saved.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default); alertController.addAction(okAction); self.present(alertController, animated: true, completion: nil)
}
func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
I have an app lets user add his image. For this I use UIImagePicker.
Please take a look at the following function:
It opens a view as a popup when image is tapped.
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
let userDetails:Dictionary = (UserDefaults.standard.value(forKey: "myUserDetails") as? [String:Any])!
let UserID:Int = userDetails["UserID"] as! Int
let popOverVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "imager") as! imagerVC
popOverVC.UserID = UserID
self.addChildViewController(popOverVC)
popOverVC.view.frame = self.view.frame
self.view.addSubview(popOverVC.view)
popOverVC.didMove(toParentViewController: self)
popOverVC.callback = { image in
// do something with the image
self.profile_image.image = image
if let data = UIImagePNGRepresentation(image) {
//save profile image as NewUserID
UserDefaults.standard.set(data, forKey: String(UserID))
UserDefaults.standard.synchronize()
}
}
}
This is the View code that activates the camera and this view is opened as popOverVC from the code above.
import UIKit
class imagerVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var UserID:Int = 0
#IBOutlet weak var myImageView: UIImageView!
var callback : ((UIImage) -> ())?
#IBOutlet weak var btn_end: UIButton!
#IBOutlet weak var from_camera: UIBarButtonItem!
#IBOutlet weak var from_gallery: UIBarButtonItem!
#IBAction func btn_end_pressed(_ sender: UIButton) {
self.view.removeFromSuperview()
}
#IBAction func btn_closer(_ sender: UIButton) {
self.view.removeFromSuperview()
}
#IBAction func photofromLibrary(_ sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
picker.modalPresentationStyle = .popover
present(picker, animated: true, completion: nil)
picker.popoverPresentationController?.barButtonItem = sender
}
#IBAction func shootPhoto(_ sender: UIBarButtonItem) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
UserDefaults.standard.set(true, forKey: "is_selfie")
UserDefaults.standard.synchronize()
DispatchQueue.main.async {
self.picker.allowsEditing = false
self.picker.sourceType = UIImagePickerControllerSourceType.camera
self.picker.cameraCaptureMode = .photo
self.picker.modalPresentationStyle = .fullScreen
self.present(self.picker,animated: true,completion: nil)
}
} else {
noCamera()
}
}
let picker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
myImageView.contentMode = .scaleAspectFit //3
myImageView.image = chosenImage //4
myImageView.layer.borderWidth = 1
myImageView.layer.masksToBounds = false
myImageView.layer.borderColor = UIColor.black.cgColor
myImageView.layer.cornerRadius = myImageView.frame.height/4
myImageView.clipsToBounds = true
callback?(chosenImage)
dismiss(animated:true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
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)
}
}
I have two problems. Maybe they are related.
The main problem is that after the camera view loads and the picture is taken, When I press the button Use photo, the camera does not get dismissed at once and there is a lag of about a minute till the camera view is dismissed. The callback function by the way get triggered as soon "use photo" button is pressed.
I am not sure if this is connected but I get the following warning:
Instance method 'imagePickerController(_:didFinishPickingMediaWithInfo:)' nearly matches requirement yet when i let Xcode autocorrect me the camera functionality ceases to function.
I tried wrapping the line
dismiss(animated:true, completion: nil)
in DispatchQueue.main.async to make it run on main thread but that did not work
Not sure why but lag does not occur in physical IPad, only iPhone devices
Any help rendered is greatly appreciated
this is as expected behaviour on simulators. It should not lag on device and as you said its working on device then its cool. !!!
I am currently in the process of creating a camera app, however when someone takes a picture and it goes to the the crop screen, it doesn't actually fit it to that specific size. How can I change my code to make it only spit out a 800x800 image?
import UIKit
import Firebase
class CameraControllerViewController: UIViewController,UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var postBtn: UIButton!
#IBOutlet weak var pickedimage: UIImageView!
#IBOutlet weak var libBtn: UIButton!
#IBOutlet weak var camBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func camerabuttonaction(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera;
imagePicker.allowsEditing = false
self.present(imagePicker, animated:true, completion: nil)
}
}
#IBAction func photolibraryaction(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary;
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
#IBAction func saveaction(_ sender: Any) {
let imageData = UIImageJPEGRepresentation(pickedimage.image!, 0.6)
let compressedJPEGImage = UIImage(data: imageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPEGImage!, nil, nil, nil)
saveNotice()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]! ) {
pickedimage.image = image
camBtn.isHidden = true
libBtn.isHidden = true
postBtn.isHidden = false
self.dismiss(animated: true, completion: nil);
}
func saveNotice() {
AppDelegate.instance().showActivityIndicator()
//let alertController = UIAlertController(title: "Image Saved", message: "Your picture was saved.", preferredStyle: .alert)
//let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil)
//alertController.addAction(defaultAction)
//present(alertController, animated: true, completion: nil)
let uid = Auth.auth().currentUser!.uid
let ref = Database.database().reference()
let storage = Storage.storage().reference(forURL: "gs://new-glaance.appspot.com")
let key = ref.child("posts").childByAutoId().key
let imageRef = storage.child("posts").child(uid).child("\(key).jpg")
let data = UIImageJPEGRepresentation(self.pickedimage.image!, 0.6)
let uploadTask = imageRef.putData(data!, metadata: nil) { (metadata,error) in
if error != nil {
print(error!.localizedDescription)
AppDelegate.instance().dismissActivityIndicator()
return
}
imageRef.downloadURL(completion: { (url, error) in
if let url = url {
let feed = ["userID": uid,
"pathToImage": url.absoluteString,
"likes":0,
"author": Auth.auth().currentUser!.displayName!,
"postID": key] as [String: Any]
let postFeed = ["\(key)":feed]
ref.child("posts").updateChildValues(postFeed)
AppDelegate.instance().dismissActivityIndicator()
}
})
}
uploadTask.resume()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I don't know of a way to constrain a crop to a particular aspect ratio. Instead I'd suggest creating your own method for cropping images.
I have an app on Github called CropImg that does just that. It doesn't constrain the crop to square, but that would be easy to add.
This is related to a previous question that was solved (See here: Sharing variables). I saw nothing that addresses what to do if your variable still isn't being recognized but your code to pass the variable appears solid.
I'm getting an unresolved identifier error 'email' when attempting to utilize a user's email address as part of a file path to upload an image to Firebase Storage. Code is here:
import UIKit
import Firebase
import MobileCoreServices
import FirebaseStorage
class ThirdViewController: UIViewController {
#IBOutlet weak var uploadButton: UIButton!
#IBOutlet weak var progressView: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(patternImage: UIImage(named:"Book Funnel")!)
// Do any additional setup after loading the view.
}
#IBAction func uploadButtonWasPressed(sender: AnyObject) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .photoLibrary
imagePicker.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
func uploadImageToFirebaseStorage(data: NSData) {
let storageRef = FIRStorage.storage().reference(withPath: email/"/image.jpg")
let uploadMetadata = FIRStorageMetadata()
uploadMetadata.contentType = "image/jpeg"
let uploadTask = storageRef.put(data as Data, metadata: uploadMetadata) { (metadata, error) in
_ = metadata?.downloadURL
if (error != nil) {
print("I recieved an error! \(error?.localizedDescription)")
} else {
print ("Upload complete! Here's some metadata! \(metadata)")
}
let alert = UIAlertController(title: "Success!", message: "Image uploaded", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "okay", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
uploadTask.observe(.progress) { [weak self] (snapshot) in
guard let strongSelf = self else { return }
guard let progress = snapshot.progress else { return }
strongSelf.progressView.progress = Float(progress.fractionCompleted)
}
}
var toPass: String!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
extension ThirdViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let mediaType: String = info[UIImagePickerControllerMediaType] as? String else {
dismiss(animated: true, completion: nil)
return
}
if mediaType == (kUTTypeImage as String) {
if let originalImage = info[UIImagePickerControllerOriginalImage] as? UIImage, let imageData = UIImageJPEGRepresentation(originalImage, 0.8) {
uploadImageToFirebaseStorage(data: imageData as NSData)
}
} else {
print("Please select an image")
}
dismiss(animated: true, completion: nil)
func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "segueTest") {
//Checking identifier is crucial as there might be multiple
// segues attached to same view
if let fourthVC = segue.destination as? FourthViewController {
fourthVC.toPass = "email"
}
}
}
}
}
Ok, im a bit further now. I got the email button working within the app, but it doesnt add the picture that i have selected in UIImageview in the e-mail. Can someone tell me how to add the picture selected to the email body?
#IBAction func FotoKnop(sender: AnyObject) {
}
#IBAction func chooseImageFromPhotoLibrary() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .PhotoLibrary
presentViewController(picker, animated: true, completion: nil)
}
#IBAction func chooseFromCamera() {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .Camera
presentViewController(picker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
imageView.image = image
self.dismissViewControllerAnimated(true, completion: nil)
}
// start e-mail
#IBAction func sendEmailButtonTapped(sender: AnyObject) {
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
}
}
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["jvanhattem#it-serve.nl"])
mailComposerVC.setSubject("Mail vanuit PicMail")
mailComposerVC.setMessageBody("Onderstaand de doorgestuurde informatie", isHTML:
false)
return mailComposerVC
}
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate Method
func mailComposeController(controller: MFMailComposeViewController!, didFinishWithResult result: MFMailComposeResult, error: NSError!) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
You should have a look at documentation for MFMailComposeViewController
You can set the recepients and attachment using setToRecipients: and addAttachmentData:mimeType:fileName:
Try this code fur your email function:
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self // Extremely important to set the --mailComposeDelegate-- property, NOT the --delegate-- property
mailComposerVC.setToRecipients(["nurdin#gmail.com"])
mailComposerVC.setSubject("Sending you an in-app e-mail...")
mailComposerVC.setMessageBody("Sending e-mail in-app is not so bad!", isHTML: false)
return mailComposerVC
}
And this code in your function for the action or where you want to add...
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
// On Success
} else {
// Error handling here
}