Uploading an image into a Web Service from an ImageView - swift

I'm trying to upload an image taken by the device camera, or selected from the device Gallery, later present it at the screen with an ImageView, and at last upload it to a Rest API. I already have a default image stored in the Rest API and my App is already loading this image, but when I try to change the image I have issues.
This is my code after the Post API call, the data of my JSON:
let defaultServiceResponse = data["defaultServiceResponse"] as! NSDictionary
self.idResponse = defaultServiceResponse["idResponse"] as! Int
let loginModel = LoginModel()
if self.idResponse == 0 {
let userInfo = data["userInfo"] as! NSDictionary
loginModel.imageProfileUrl = userInfo["imageProfileUrl"] as! String
let url = URL(string: loginModel.imageProfileUrl)
let data = try? Data(contentsOf: url!)
self.userImage.image = UIImage(data: data!)!
Then I have a second class where I'm trying to upload the image:
class PhotoViewController: UIViewController, UIImagePickerControllerDelegate,
UINavigationControllerDelegate {
#IBOutlet weak var imagePicked: UIImageView!
#IBAction func openCameraButton(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .camera;
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
#IBAction func openPhotoLibraryButton(sender: AnyObject) {
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary;
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imagePicked.image = image
dismiss(animated:true, completion: nil)
}
#IBAction func saveButt(sender: AnyObject) {
let imageData = UIImageJPEGRepresentation(imagePicked.image!, 0.6)
let compressedJPGImage = UIImage(data: imageData!)
UIImageWriteToSavedPhotosAlbum(compressedJPGImage!, nil, nil, nil)
let alert = UIAlertView(title: "Wow",
message: "Your image has been saved to Photo Library!",
delegate: nil,
cancelButtonTitle: "Ok")
alert.show()
}
When I tap the openCamara button and openLibrary button it does the correct function each time, but when I choose the photo (either from the Camera or the Gallery) it doesn't appear anything at the ImageView, and the error I receive is: "Creating an image format with an unknown type is an error
"
And I'm not sending back the image into the Rest API because I haven't any idea of how can I do that.
Can somebody help me showing where is the error that is not letting me show the picture at the screen on the ImageView?
And if it's posible can somebody show me the best way to return that image into my Rest API?

#Zita Noriega Estrada
this code will remove your all errors.
func isValidData(_ result: Result<Any>, completion: #escaping (_ : NSDictionary?, _ : Bool?, _ : NSError?) -> Void) {
self.getValidDict(result, completion: {(dict, error) in
var success = false
var errorNew = error
if dict != nil {
success = ((dict?["dataKey"] as AnyObject).boolValue)!
if !success {
errorNew = NSError(domain: "", code: 400, userInfo: [NSLocalizedDescriptionKey: dict?.value(forKey: "messageKey")! as Any])
}
}
completion (dict, success, errorNew)
})
}
func getValidDict(_ result: Result<Any>, completion: #escaping (_ : NSDictionary?, _ : NSError?) -> Void) {
var dict: NSDictionary!
let errorNew = result.error as NSError?
if let json = result.value {
dict = (json as AnyObject).value(forKey: "responseKey") as! NSDictionary
}
completion (dict, errorNew)
}

Use Alamofire to upload image to server.
Try this code:
func uploadImage {
uploadImage(image: image, completion: { (success, error) in
if success! {
} else {
}
})
}
func uploadImage(_ image: UIImage!, completion: #escaping (_ : Bool?, _: NSError?) -> Void) {
let parameters: Parameters = ["image": image]
Alamofire.upload(multipartFormData: {
multipartFormData in
// For Image
for (key, value) in parameters {
if value != nil {
if let imageData = UIImageJPEGRepresentation(value!, 0.5) {
multipartFormData.append(imageData, withName: key, fileName: "file.png", mimeType: "image/png")
}
}
}
}, to: "apiName", method: .post, encodingCompletion: {
encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.response {
[weak self] response in
guard self != nil
else {
return
}
upload.responseJSON(completionHandler: { response in
self?.isValidData(response.result, completion: {(dict, success, error) in
completion (success, error)
})
})
}
case .failure(let encodingError):
print("error:\(encodingError)")
completion (false, encodingError as NSError?)
}
})
}

Related

Check if picture is selected from photo library

The user can select a picture as a profile picture in my app.
After that he can click on done and the picture gets uploaded.
If the user does not select a picture my code still upload a blank picture by clicking on done.
How can I check if the user selected a picture and then trigger the function?
I need an if else statement but don't know how to get the status "is a picture selected?"
I could maybe also use a default value. But that would mean to download the actual picture and reupload it again as default. That does not sound good.
#IBOutlet weak var tapToChangeProfileButton: UIButton!
var imagePicker: UIImagePickerController!
var ref: DatabaseReference!
#IBAction func updateProfile(_ sender: UIButton) {
uploadPic(arg: true, completion: { (success) -> Void in
if success {
addUrlToFirebaseProfile()
} else {
}
})
func uploadPic(arg: Bool, completion: #escaping (Bool) -> ()) {
guard let imageSelected = self.image else {
completion(false);
return
}
guard let imageData = imageSelected.jpegData(compressionQuality: 0.1) else {
completion(false);
return
}
let storageRef = Storage.storage().reference(forURL: "gs://....e.appspot.com")
let storageProfileRef = storageRef.child("profilePictures").child(Auth.auth().currentUser!.uid)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
storageProfileRef.putData(imageData, metadata: metadata, completion: {
(storageMetadata, error) in
if error != nil {
//print(error?.localizedDescription)
completion(false);
return
}
storageProfileRef.downloadURL(completion: { (url, error) in
if let metaImageURL = url?.absoluteString {
print(metaImageURL)
self.urltoPicture = metaImageURL
completion(true)
}
else
{
completion(false); return
}
})
})
}
func addUrlToFirebaseProfile(){
ref = Database.database().reference()
let userID = Auth.auth().currentUser!.uid
ref.child("user/\(userID)").updateChildValues(["profileText": profileText.text!])
print(urltoPicture)
ref.child("user/\(userID)").updateChildValues(["picture": urltoPicture])
}
self.navigationController?.popViewController(animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
let imageTap = UITapGestureRecognizer(target: self, action: #selector(openImagePicker))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(imageTap)
tapToChangeProfileButton.addTarget(self, action: #selector(openImagePicker), for: .touchUpInside)
imagePicker = UIImagePickerController()
imagePicker.allowsEditing = true
imagePicker.sourceType = .photoLibrary
imagePicker.delegate = self
}
#objc func openImagePicker(_ sender:Any){
self.present(imagePicker, animated: true, completion: nil)
}
extension ImagePickerViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController){
picker.dismiss(animated: true, completion: nil)
}
internal func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any])
{
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
self.profileImageView.image = pickedImage
image = pickedImage
}
picker.dismiss(animated: true, completion: nil)
}
}
As I see from your code, whenever you get an image from imagePickerController you store it into variable self.image. Then whenever you click Done you just upload this self.image
Make variable self.image can be nil then remember to unset it after uploading successfully
Code will be like this
var image : UIImage? = nil
#IBAction func updateProfile(_ sender: UIButton) {
uploadPic(arg: true, completion: { (success) -> Void in
if success {
addUrlToFirebaseProfile()
self.image = nil // reset image to nil if success
} else {
}
})
}
You are setting self.image if the user selects a photo.
But you are not unsetting self.image if the user doesn't select a photo. It needs to be set to nil (not to an empty UIImage()).

I can't understand why posts are not loading in firebase

firebase does not write, although it seems to be syntactically correct. The application compiles, but no writes take place.
The documentation also seems to be correct.
the logic is simple. The user uploads a file from the phone, the file is sent to the repository
#IBAction func addButtonTouchUpInside(_ sender: Any) {
ProgressHUD.show("Waiting...", interaction: false)
if let profileImg = self.selectedImage, let imageData = image?.jpegData(compressionQuality: 0.4){
let photoIdString = NSUUID().uuidString
let storageRef = Storage.storage().reference(forURL: https://example.com).child("posts").child(photoIdString)
storageRef.putData(imageData, metadata: nil, completion: {(metadata, error) in
if error != nil {
ProgressHUD.showError(error!.localizedDescription)
return
}
let photoUrl = storageRef.downloadURL(completion: {url, error in
if error != nil {
print("Failed to download url:", error!)
return
} else {
let url = url?.absoluteString
self.sendDataToDatabase(photoUrl: url!)
}
})
})
}
}
func sendDataToDatabase(photoUrl: String){
let ref = Database.database().reference()
let postsReference = ref.child("posts")
let newPostId = postsReference.childByAutoId().key
let newPostReference = postsReference.child(newPostId!)
newPostReference.setValue(["photoUrl": photoUrl], withCompletionBlock: {
(Error, ref) in
if Error != nil {
ProgressHUD.showError(Error!.localizedDescription)
return
}
ProgressHUD.showSuccess("Success")
})
}
}
extension PerformViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate{
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
print("Did finish picking media")
if let image = info[UIImagePickerController.InfoKey.originalImage ] as? UIImage{
selectedImage = image
photo.image = image
}
dismiss(animated: true, completion: nil)
}
}

UIImagePickerController not initiating next function

I'm using Swift 5 and have integrated MessageKit into my app. Here's the expected functionality:
User selects the image via picker
uploadImage function is initiated
Image is uploaded and displayed
What's actually happening:
User selects the image via picker
Nothing happens from there.
I'm not getting a single error message. I've put in print statements to see if it's even entering the uploadImage() function but it's not kicking off. I've change the uipickerimagecontroller code to exact code in other places of my app that is working and even that's not kicking off the function. I know my code isn't pretty but I'm still learning (please don't judge lol). Can anyone help:
Variable setup
private var isSendingPhoto = true {
didSet {
DispatchQueue.main.async {
self.messageInputBar.leftStackViewItems.forEach { item in
item.inputBarAccessoryView?.isUserInteractionEnabled = !self.isSendingPhoto
}
}
}
}
ViewDidLoad
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messageInputBar.delegate = self as? InputBarAccessoryViewDelegate
messagesCollectionView.messagesDisplayDelegate = self
title = "MaybeDrinks"
// 1
let cameraItem = InputBarButtonItem(type: .system)
cameraItem.tintColor = .primary
cameraItem.image = #imageLiteral(resourceName: "camera")
// 2
cameraItem.addTarget(
self,
action: #selector(cameraButtonPressed),
for: .primaryActionTriggered
)
cameraItem.setSize(CGSize(width: 60, height: 30), animated: false)
messageInputBar.leftStackView.alignment = .center
messageInputBar.setLeftStackViewWidthConstant(to: 50, animated: false)
messageInputBar.setStackViewItems([cameraItem], forStack: .left, animated: false) // 3
}
private func sendPhoto(_ image: UIImage) {
isSendingPhoto = true
uploadImage(image) { [weak self] url in
guard let `self` = self else {
return
}
self.isSendingPhoto = false
guard let url = url else {
return
}
var message = Message(messageuser: self.sender, image: image)
message.downloadURL = url
self.save(message)
self.messagesCollectionView.scrollToBottom()
}
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
// 1
if let asset = info[.phAsset] as? PHAsset {
let size = CGSize(width: 500, height: 500)
PHImageManager.default().requestImage(
for: asset,
targetSize: size,
contentMode: .aspectFit,
options: nil) { result, info in
print("I'm in image picker")
guard let image = result else {
return
}
self.sendPhoto(image)
}
// 2
} else if let image = info[.originalImage] as? UIImage {
sendPhoto(image)
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
// MARK: - Actions
#objc private func cameraButtonPressed() {
let picker = UIImagePickerController()
picker.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
picker.allowsEditing = true
if UIImagePickerController.isSourceTypeAvailable(.camera) {
picker.sourceType = .camera
} else {
picker.sourceType = .photoLibrary
}
present(picker, animated: true, completion: nil)
}
Upload Image function
private func uploadImage(_ image: UIImage, completion: #escaping (URL?) -> Void) {
print("im in upload")
// STEP 1. Declare URL, Request and Params
let url = URL(string: "https://localhost/messagepost.php")!
// declaring reqeust with further configs
var request = URLRequest(url: url)
// POST - safest method of passing data to the server
request.httpMethod = "POST"
// values to be sent to the server under keys (e.g. ID, TYPE)
let params = ["sender_id": user_id, "uuid": uuid, "sender": me, "recipient_id": rid, "recipient": recipient, "puuid": puuid]
// body
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// Compressing image and converting image to 'Data' type
guard let scaledImage = image.scaledToSafeUploadSize,
let data = scaledImage.jpegData(compressionQuality: 0.4) else {
return
}
// assigning full body to the request to be sent to the server
request.httpBody = createBodyWithParams(params, filePathKey: "file", imageDataKey: data, boundary: boundary)
print(request.httpBody as Any, "\(puuid).jpg")
URLSession.shared.dataTask(with: request) { (data, response, error) in
DispatchQueue.main.async {
// error occured
if error != nil {
Helper().showAlert(title: "Server Error", message: error!.localizedDescription, in: self)
return
}
do {
// save mode of casting any data
guard let data = data else {
Helper().showAlert(title: "Data Error", message: error!.localizedDescription, in: self)
return
}
// fetching JSON generated by the server - php file
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary
// save method of accessing json constant
guard let parsedJSON = json else {
return
}
// uploaded successfully
if parsedJSON["status"] as! String == "200" {
let newurl = parsedJSON["path"]
print("did you upload", newurl as Any)
print("did you upload", parsedJSON["message"] as Any)
self.isSendingPhoto = true
guard let url = newurl else {
return
}
//uploadImage(image)
var message = Message(messageuser: self.sender, image: image)
message.downloadURL = url as? URL
self.save(message)
self.messagesCollectionView.scrollToBottom()
} else {
// show the error message in AlertView
if parsedJSON["message"] != nil {
let message = parsedJSON["message"] as! String
Helper().showAlert(title: "Error", message: message, in: self)
print("where am i", parsedJSON["message"] as Any)
}
}
} catch {
Helper().showAlert(title: "JSON Error", message: error.localizedDescription, in: self)
print("where am i 2")
}
}
}.resume()
let imageName = [UUID().uuidString, String(Date().timeIntervalSince1970)].joined()
}
private func save(_ message: Message) {
self.messagesCollectionView.scrollToBottom()
}
Make sure your view controller declares conformance to both UIImagePickerControllerDelegate and UINavigationControllerDelegate in either the class declaration:
class DirectMessageViewController: MessagesViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
[...]
}
or in one or more extensions:
extension DirectMessageViewController: UIImagePickerControllerDelegate {
[...]
}
extension DirectMessageViewController: UINavigationControllerDelegate {
[...]
}

Upload image to Firebase Storage and show as Profile Image

I need help with uploading image to Firebase Storage. I have a profile menu in my app. When user tap on this menu he/she can see profile with their info and Profile Image. So I made it so you can select a photo from the gallery. But I need to save photo to Firebase Storage and add ref to Firebase Database by uid.
In addition, the user may not have a photo, so it will be nill because nothing in Database. Look at photo and you will understand everything
extension ProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var selectedImage: UIImage?
if let editedImage = info[.editedImage] as? UIImage {
selectedImage = editedImage
self.profileImage.image = selectedImage!
self.savedImage = selectedImage
picker.dismiss(animated: true, completion: nil)
} else if let originalImage = info[.originalImage] as? UIImage {
selectedImage = originalImage
self.profileImage.image = selectedImage!
self.savedImage = selectedImage
picker.dismiss(animated: true, completion: nil)
}
}
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleSelectProfileImageView) )
profileImage.addGestureRecognizer(tapGesture)
profileImage.isUserInteractionEnabled = true
#objc func handleSelectProfileImageView () {
print("Tapped")
let pickerController = UIImagePickerController()
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
So, how to upload and dowload image.
If the user does not have a photo (ref in Database). He will see image from assets.
If the user have photo he will see image from FB.
image
For Uploading to Firebase storage
let imgData: NSData = NSData(data: UIImageJPEGRepresentation((self.img_Photo?.image)!, 0.5)!)
let _:NSData = NSData(data:UIImagePNGRepresentation(((self.img_Photo?.image)!))!)
self.uploadProfileImageToFirebase(data: imgData)
Function for uploading
func uploadProfileImageToFirebase(data:NSData){
let randomPic = randomString(length: 10)
let storageRef = Storage.storage().reference().child("Pictures").child("\(value(forKey: "UserUID") ?? randomPic).jpg")
if data != nil {
storageRef.putData(data as Data, metadata: nil, completion: { (metadata, error) in
if(error != nil){
print(error)
return
}
guard let userID = Auth.auth().currentUser?.uid else {
return
}
// Fetch the download URL
storageRef.downloadURL { url, error in
if let error = error {
// Handle any errors
if(error != nil){
print(error)
return
}
} else {
// Get the download URL for 'images/stars.jpg'
let urlStr:String = (url?.absoluteString) ?? ""
let values = ["photo_url": urlStr]
self.registerUserIntoDatabaseWithUID(uid: userID, values: values as [String : AnyObject])
}
}
})
}
}
func registerUserIntoDatabaseWithUID(uid:String, values:[String:AnyObject]){
let ref = Database.database().reference(fromURL: "https://domain.firebaseio.com/")
let usersReference = ref.child("users").child((Auth.auth().currentUser?.uid)!)
usersReference.updateChildValues(values) { (error, ref) in
if(error != nil){
print(error)
return
}
self.parentVC?.dismiss(animated: true, completion: nil)
}
}

Swift - Alamofire - upload file from photolibrary

I'm trying to implement an upload from my photo-library with Alamofire:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
guard let image = info[UIImagePickerControllerOriginalImage] as? UIImage else {
return
}
let documentDirectory: NSString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as NSString
let imageName = "temp"
let imagePath = documentDirectory.appendingPathComponent(imageName)
if let data = UIImageJPEGRepresentation(image, 80) {
do {
try data.write(to: URL(fileURLWithPath: imagePath), options: .atomic)
} catch let error {
print(error)
}
}
Alamofire.upload(.POST, "\(self.app_url)/user/upload", multipartFormData: { formData in
let filePath = NSURL(fileURLWithPath: image)
formData.appendBodyPart(fileURL: filePath, name: "upload")
formData.appendBodyPart(data: "Alamofire".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!, name: "test")
}, encodingCompletion: { encodingResult in
switch encodingResult {
case .Success:
print("SUCCESS")
case .Failure(let error):
print(error)
}
})
self.dismiss(animated: true, completion: nil)
}
And it prints:
Ambiguous reference to member 'upload(_:to:method:headers:)'
Can anybody explain me how to resolve this issue?
Thanks and Greetings!
In Swift 3 and Alamofire 4
Here is the Full Implementation of how to upload using Alamofire
Add the Following to your ViewController Class:
UIImagePickerControllerDelegate and UINavigationControllerDelegate
Create A Button:
First Create a button and implement the Following method in it for picker view
#IBAction func btnSelectProfileImageClicked(_ sender: Any) {
let ImagePicker = UIImagePickerController()
ImagePicker.delegate = self
ImagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(ImagePicker, animated: true, completion: nil)
}
Then Implement the following UIPicker Methods:
func imagePickerController( _ picker: UIImagePickerController,didFinishPickingMediaWithInfo info:[String : Any] )
{Imgprofile.image = info[UIImagePickerControllerOriginalImage] as? UIImage
self.dismiss(animated: true, completion: nil)}
Make Another Button Which Passes the data to URL using Alamofire and Give an #IBAction outlet to it to it :
Enter Following Data to it
#IBAction func btnUpdateProfileSelected(_ sender: Any) {
Alamofire.upload(multipartFormData: { (multipartFormData) in
multipartFormData.append(UIImageJPEGRepresentation(self.Imgprofile.image!, 1)!, withName: "Prescription", fileName: "Profile_Image.jpeg", mimeType: "image/jpeg")
}, to:" Your URL Here where You want to Upload")
{ (result) in
switch result {
case .success(let upload, _, _):
print(result)
upload.uploadProgress(closure: { (progress) in
print(progress)
})
upload.responseJSON { response in
//print response.result
print(response);
}
case .failure(let encodingError):
print(encodingError);
}
}
}
Thats all
Hope This helps
For Full sample code or any doubts please comment. I will provide you
the sample code for this. Which Includes the Fetching as well as
upload data using Alamofire.
Thanks