Saving Profile Picture and Header Photo to Firebase - swift

So I have a viewcontroller for a user to edit their profile picture and header photo. I have it to where the user selects a photo and it will save to firebase database and then will download the image and display it in the proper UIImage Views. Only problem I am having is that if I only edit the profile picture and hit save it saves both the profile picture and header photo even though I did not edit header photo. It also saves the data from the profile picture selected for both the profile picture and header photo which erases the original header photo and displaying the selected profile image in both UIImage Views. I'm not sure why it is doing this, I'm sure I am missing something important but I'm not sure what it is. Here is my entire viewcontroller for this.
import UIKit
import Foundation
import Firebase
import FirebaseDatabase
import FirebaseAuth
class NewEditProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPickerViewDataSource, UIPickerViewDelegate {
#IBOutlet weak var imageView1: UIImageView!
#IBOutlet weak var imageView2: UIImageView!
#IBOutlet weak var usernameDisplay: UITextField!
#IBOutlet weak var artistBandDJ: UILabel!
#IBOutlet weak var editArtistBandDJ: UIButton!
let you = ["Artist", "Band", "DJ", "Musician", "Producer"]
var picker:UIPickerView!
var ref = DatabaseReference.init()
var imagePicker = UIImagePickerController()
var imagePicked = 0
var databaseRef = Database.database().reference()
var selectedImage1: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
self.ref = Database.database().reference()
imagePicker.delegate = self
imagePicker.sourceType = .photoLibrary
imagePicker.allowsEditing = true
guard let uid = Auth.auth().currentUser?.uid else { return }
self.databaseRef.child("users/profile").child(uid).observeSingleEvent(of: .value) { (snapshot:DataSnapshot) in
let dict = snapshot.value as? [String:Any]
self.usernameDisplay.text = dict!["username"] as? String
self.artistBandDJ.text = dict!["What do you consider yourself?"] as? String
if(dict!["photoURL"] != nil) {
let databaseProfilePic = dict!["photoURL"] as! String
if let data = NSData(contentsOf: NSURL(string: databaseProfilePic)! as URL) {
self.setProfilePic(imageView: self.imageView1,imageToSet:UIImage(data: data as Data)!)
}
}
if(dict!["headerURL"] != nil) {
let databaseHeaderPic = dict!["headerURL"] as! String
if let data2 = NSData(contentsOf: NSURL(string:databaseHeaderPic)! as URL) {
self.setHeaderPic(imageView2: self.imageView2, imageToSet2: UIImage(data: data2 as Data)!)
}
}
}
}
#IBAction func chooseImage1(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
imagePicked = (sender as AnyObject).tag
present(imagePicker, animated: true)
}
}
#IBAction func chooseImage2(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
imagePicked = (sender as AnyObject).tag
present(imagePicker, animated: true)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let pickedImage = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
let pickedImage2 = info[UIImagePickerController.InfoKey.editedImage] as? UIImage
if imagePicked == 1 {
self.imageView1.image = pickedImage
} else if imagePicked == 2 {
self.imageView2.image = pickedImage2
}
dismiss(animated: true)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true)
}
#IBAction func saveButton(_ sender: Any) {
self.saveFIRData()
self.saveHeaderPhoto()
self.savePicker()
self.saveUpdateName()
self.dismiss(animated: true, completion: nil)
}
#IBAction func backButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
func saveFIRData() {
guard let image = imageView1.image else { return }
self.uploadProfileImage(image){ url in
if url != nil {
self.saveProfileImage(profileURL: url!){ success in
if success != nil{
print("yes")
}
}
}
}
}
func saveHeaderPhoto() {
guard let image2 = imageView2.image else { return }
self.uploadHeaderImage(image2){ url in
self.saveHeaderImage(profileURL2: url!){ success in
if success != nil {
print("yes")
}
}
}
}
#IBAction func editButton(_ sender: Any) {
self.editButtonTapped()
}
func editButtonTapped() {
let vc = UIViewController()
vc.preferredContentSize = CGSize(width: 150, height: 150)
let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: 150, height: 150))
picker.delegate = self
picker.dataSource = self
vc.view.addSubview(picker)
let editBandDJAlert = UIAlertController(title: "What do you consider yourself?", message: nil, preferredStyle: UIAlertController.Style.alert)
editBandDJAlert.setValue(vc, forKey: "contentViewController")
editBandDJAlert.addAction(UIAlertAction(title: "Done", style: .default, handler: nil))
editBandDJAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(editBandDJAlert, animated:true)
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return you.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return you[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
artistBandDJ.text = you[row]
}
internal func setProfilePic(imageView:UIImageView,imageToSet:UIImage) {
imageView1.layer.cornerRadius = imageView1.bounds.height / 2
imageView1.layer.masksToBounds = true
imageView1.image = imageToSet
}
internal func setHeaderPic(imageView2:UIImageView,imageToSet2:UIImage) {
imageView2.layer.masksToBounds = true
imageView2.image = imageToSet2
}
func savePicker() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let selectedValue = artistBandDJ.text
let ref = Database.database().reference().root
let userObject = [
"What do you consider yourself?":selectedValue
]
ref.child("users/profile").child(uid).updateChildValues(userObject as [AnyHashable : Any])
}
func saveUpdateName() {
guard let uid = Auth.auth().currentUser?.uid else { return }
let updatedName = usernameDisplay.text
let ref = Database.database().reference().root
let userObject = [
"username":updatedName
]
ref.child("users/profile").child(uid).updateChildValues(userObject as [AnyHashable : Any])
}
}
extension NewEditProfileViewController {
func uploadProfileImage(_ image:UIImage, completion: #escaping (_ url: URL?)->()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storageRef = Storage.storage().reference().child("users/\(uid)")
let imageData = imageView1.image?.jpegData(compressionQuality: 0.8)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
storageRef.putData(imageData!, metadata: metaData) { (metaData, error) in
if error == nil{
print("success for profile photo")
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func uploadHeaderImage(_ image2:UIImage, completion: #escaping (_ url2: URL?)->()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let storageRef = Storage.storage().reference().child("users/\(uid)")
let imageData2 = imageView2.image?.jpegData(compressionQuality: 0.8)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
storageRef.putData(imageData2!, metadata: metaData) { (metaData, error) in
if error == nil{
print("success for header")
storageRef.downloadURL(completion: { (url, error) in
completion(url)
})
}else{
print("error in save image")
completion(nil)
}
}
}
func saveProfileImage(profileURL:URL, completion: #escaping ((_ url: URL?) -> ())){
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Database.database().reference().child("users/profile/\(uid)")
let userObject = [
"photoURL": profileURL.absoluteString
] as [String:Any]
self.ref.child("users/profile").child(uid).updateChildValues(userObject)
}
func saveHeaderImage(profileURL2:URL, completion: #escaping ((_ url: URL?) -> ())){
guard let uid = Auth.auth().currentUser?.uid else { return }
let databaseRef = Database.database().reference().child("users/profile/\(uid)")
let userObject = [
"headerURL": profileURL2.absoluteString
] as [String:Any]
self.ref.child("users/profile").child(uid).updateChildValues(userObject)
}
}

It looks like you're overriding everything when the users presses the save button. This could be solved by adding a property var headerChanged = false to the view controller. Then in chooseImage1 you set it to true.
When saveButton is called you check whether it has changed or not by checking the flag (headerChanged).

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()).

How to use a stored url from Firebase Database as an image in an UIImageView

I'm new to coding and trying to build an iOS App. I am storing images uploaded by users into my firebase storage and then saving the URL as a string ("https//.....). I am able to get a snapshot to show up in project terminal after I use print(snapshot). It prints, snap (profileImageUrl) https://firebasestorage.... How do I use this snapshot to get the ImageView to show the profile picture most recently saved?
import UIKit
import Firebase
import SDWebImage
class EditProfileViewController: UIViewController {
#IBOutlet weak var ProfileImage: UIImageView!
var selectedImage: UIImage?
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle = 0
var postProfileImage = [String]()
let dbref = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
override func viewDidLoad() {
super.viewDidLoad()
self.ref?.child("users").child(Auth.auth().currentUser!.uid).child("profileImageUrl").observe(.value, with: { (snapshot) in
print(snapshot)
})
ProfileImage.layer.borderWidth = 3.0
ProfileImage.layer.masksToBounds = false
ProfileImage.layer.borderColor = UIColor.white.cgColor
ProfileImage.layer.cornerRadius = ProfileImage.frame.size.width / 2
ProfileImage.clipsToBounds = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(EditProfileViewController.handleSelectProfileImageView))
ProfileImage.addGestureRecognizer(tapGesture)
ProfileImage.isUserInteractionEnabled = true
}
#objc func handleSelectProfileImageView() {
let pickerController = UIImagePickerController()
pickerController.delegate = self
present(pickerController, animated: true, completion: nil)
}
#IBAction func Cancel(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
let user = Auth.auth().currentUser
let fileData = NSData()
#IBAction func DoneButton(_ sender: UIBarButtonItem) {
guard let imageSelected = self.ProfileImage.image else {
print ("Avatar is nil")
return
}
var dict: Dictionary<String, Any> = [
"profileImageUrl": "",
]
guard let imageData = imageSelected.jpegData(compressionQuality: 0.4) else {
return
}
let storageRef = Storage.storage().reference(forURL: "(I have my storage url here")
let imageName = NSUUID().uuidString
let storageProfileRef = storageRef.child("Profile_Images").child(Auth.auth().currentUser!.uid).child("\(imageName).png")
let metadata = StorageMetadata()
metadata.contentType = "image/jpeg"
storageProfileRef.putData(imageData, metadata: metadata, completion:
{ (StorageMetadata, error) in
if (error != nil) {
return
}
storageProfileRef.downloadURL { (url, error) in
if let metaImageUrl = url?.absoluteString {
dict["profileImageUrl"] = metaImageUrl
Database.database().reference().child("users").child(Auth.auth().currentUser!.uid).updateChildValues(dict, withCompletionBlock: {
(error, ref) in
if error == nil {
print("Done")
}
}
)
}
}
})
dismiss(animated: true, completion: nil)
}
}
extension EditProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//print("did Finish Picking Media")
if let image = info[UIImagePickerController.InfoKey(rawValue: "UIImagePickerControllerOriginalImage")] as? UIImage{
selectedImage = image
ProfileImage.image = image
}
dismiss(animated: true, completion: nil)
}
}
I could really use some help!
You can add an extension to UIImageView as below:
extension UIImageView {
func load(url: URL, onLoadCompletion: ((_ isImageLoaded: Bool) -> Void)? = nil) {
self.image = nil
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
onLoadCompletion?(true)
}
} else {
onLoadCompletion?(false)
}
} else {
onLoadCompletion?(false)
}
}
}
}
Assuming your image view outlet is something like this:
#IBOutlet weak var imageView: UIImageView!
Below is the usage when adding a loader:
if let url = URL(string: "https://firebase-storage-url") {
// show a loader here if needed
imageView.load(url: url) { (imageLoaded) in
if imageLoaded {
// hide loader
} else {
// show a place holder image
// hide loader
}
}
} else {
// show a default image
}
Below is the usage without any extra work and just loading the image:
if let url = URL(string: "https://firebase-storage-url") {
imageView.load(url: url)
}

How to send multiple images to Firebase and retrieve them in the UIImageView in Swift

I have an app that lets users choose multiple images. The problem is that it doesn't upload and save the image to the user in Firebase and retrieve the image.
This is my code:
import UIKit
import Photos
import Firebase
import BSImagePicker
class Downloadimages: UIViewController {
#IBOutlet weak var imgView: UIImageView!
var ref: DatabaseReference?
var SelectedAssets = [PHAsset]()
var PhotoArray = [UIImage]()
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
// 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 addImagesClicked(_ sender: Any) {
// create an instance
let vc = BSImagePickerViewController()
//display picture gallery
self.bs_presentImagePickerController(vc, animated: true,
select: { (asset: PHAsset) -> Void in
}, deselect: { (asset: PHAsset) -> Void in
// User deselected an assets.
}, cancel: { (assets: [PHAsset]) -> Void in
// User cancelled. And this where the assets currently selected.
}, finish: { (assets: [PHAsset]) -> Void in
// User finished with these assets
for i in 0..<assets.count
{
self.SelectedAssets.append(assets[i])
}
self.convertAssetToImages()
}, completion: nil)
let image = UIImagePickerController()
image.delegate = self as? UIImagePickerControllerDelegate & UINavigationControllerDelegate
image.sourceType = UIImagePickerControllerSourceType.photoLibrary
image.allowsEditing = false
self.present(image, animated: true)
{
//after its completed
}
}
#objc(imagePickerController:didFinishPickingMediaWithInfo:) func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage
{
imgView.image = image
}
else
{
//error
}
self.dismiss(animated: true, completion: nil)
let storageRef = Storage.storage().reference().child("myImage.png")
if let uploadData = UIImagePNGRepresentation(self.imgView.image!){
storageRef.putData(uploadData, metadata: nil, completion:
{
(metadata, error) in
if error != nil {
print("error")
return
}
print(metadata!)
//how do I put the download URL in the metadata into my database
}
)
}
}
func convertAssetToImages() -> Void {
if SelectedAssets.count != 0{
for i in 0..<SelectedAssets.count{
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var thumbnail = UIImage()
option.isSynchronous = true
manager.requestImage(for: SelectedAssets[i], targetSize: CGSize(width: 200, height: 200), contentMode: .aspectFill, options: option, resultHandler: {(result, info)->Void in
thumbnail = result!
})
let data = UIImageJPEGRepresentation(thumbnail, 0.7)
let newImage = UIImage(data: data!)
self.PhotoArray.append(newImage! as UIImage)
}
self.imgView.animationImages = self.PhotoArray
self.imgView.animationDuration = 3.0
self.imgView.startAnimating()
}
print("complete photo array \(self.PhotoArray)")
}
}
and this is my post code
import Foundation
class Post {
var id:String
var author:UserProfile
var text:String
var createdAt:Date
init(id:String, author:UserProfile,text:String,timestamp:Double) {
self.id = id
self.author = author
self.text = text
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, _ data:[String:Any]) -> Post? {
if let author = data["author"] as? [String:Any],
let uid = author["uid"] as? String,
let username = author["username"] as? String,
let photoURL = author["photoURL"] as? String,
let url = URL(string:photoURL),
let text = data["text"] as? String,
let timestamp = data["timestamp"] as? Double {
let userProfile = UserProfile(uid: uid, username: username, photoURL: url)
return Post(id: key, author: userProfile, text: text, timestamp:timestamp)
}
return nil
}
}
this is my userProfile
import Foundation
class UserProfile {
var uid:String
var username:String
var photoURL:URL
init(uid:String, username:String,photoURL:URL) {
self.uid = uid
self.username = username
self.photoURL = photoURL
}
}
and this is
import Foundation
import Firebase
class UserService {
static var currentUserProfile:UserProfile?
static func observeUserProfile(_ uid:String, completion: #escaping ((_ userProfile:UserProfile?)->())) {
let userRef = Database.database().reference().child("users/profile/\(uid)")
userRef.observe(.value, with: { snapshot in
var userProfile:UserProfile?
if let dict = snapshot.value as? [String:Any],
let username = dict["username"] as? String,
let photoURL = dict["photoURL"] as? String,
let url = URL(string:photoURL) {
userProfile = UserProfile(uid: snapshot.key, username: username, photoURL: url)
}
completion(userProfile)
})
}
}

define video url as the uiview in your class

My swift code should be able to take a snapshot of a video and then take that image and display in a uiimageview. Instead of using a online link I just want the url to be the uiview in my class.So the video url should be previewView not the https link that I have below. All the code below is in this class
import UIKit;import AVFoundation
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
#IBOutlet var previewView : UIView!
#IBOutlet var captureImageView : UIImageView!
var captureSession: AVCaptureSession!
var stillImageOutput: AVCapturePhotoOutput!
var videoPreviewLayer: AVCaptureVideoPreviewLayer!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Setup your camera here...
captureSession = AVCaptureSession()
captureSession.sessionPreset = .medium
guard let backCamera = AVCaptureDevice.default(for: AVMediaType.video)
else {
print("Unable to access back camera!")
return
}
do {
let input = try AVCaptureDeviceInput(device: backCamera)
//Step 9
stillImageOutput = AVCapturePhotoOutput()
stillImageOutput = AVCapturePhotoOutput()
if captureSession.canAddInput(input) && captureSession.canAddOutput(stillImageOutput) {
captureSession.addInput(input)
captureSession.addOutput(stillImageOutput)
setupLivePreview()
}
}
catch let error {
print("Error Unable to initialize back camera: \(error.localizedDescription)")
}
}
func setupLivePreview() {
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer.videoGravity = .resizeAspect
videoPreviewLayer.connection?.videoOrientation = .portrait
previewView.layer.addSublayer(videoPreviewLayer)
//Step12
DispatchQueue.global(qos: .userInitiated).async { //[weak self] in
self.captureSession.startRunning()
//Step 13
DispatchQueue.main.async {
self.videoPreviewLayer.frame = self.previewView.bounds
}
}
}
#IBAction func startRecord(_ sender: Any) {
}
#IBAction func Save(_ sender: Any) {
//what do I put in the 2 highlighted blocks
let videoURL = "https://www.youtube.com/watch?v=Txt25dw-lIk"
self.getThumbnailFromUrl(videoURL) { [weak self] (img) in
guard let _ = self else { return }
if let img = img {
self?.captureImageView.image = img
}
}
}
func getThumbnailFromUrl(_ url: String?, _ completion: #escaping ((_ image: UIImage?)->Void)) {
guard let url = URL(string: url ?? "") else { return }
DispatchQueue.main.async {
let asset = AVAsset(url: url)
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
let time = CMTimeMake(value: 2, timescale: 1)
do {
let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: img)
completion(thumbnail)
} catch {
print("Error :: ", error.localizedDescription)
completion(nil)
}
}
}
#IBAction func didTakePhoto(_ sender: Any) {
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
stillImageOutput.capturePhoto(with: settings, delegate: self)
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard let imageData = photo.fileDataRepresentation()
else { return }
let image = UIImage(data: imageData)
captureImageView.image = image
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.captureSession.stopRunning()
}
}

Image Classifer does not show results in Classification Label in Xcode

I tried to make an image classification app. For some reason, the classification label doesn't show any results. Below is my code, would appreciate all your helps.enter image description here
===
import UIKit
import CoreML
import Vision
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var myImageView: UIImageView!
let picker = UIImagePickerController()
#IBAction func cameraButton(_ sender: UIBarButtonItem) {
let vc = UIImagePickerController()
vc.sourceType = .camera
vc.allowsEditing = false
vc.delegate = self
present(vc, animated: true)
}
#IBAction func photoButton(_ sender: UIBarButtonItem) {
picker.allowsEditing = false
picker.sourceType = .photoLibrary
picker.mediaTypes = UIImagePickerController.availableMediaTypes(for: .photoLibrary)!
present(picker, animated: true, completion: nil)
}
#IBOutlet weak var classificationLabel: UILabel!
/// Image classification
lazy var classificationRequest: VNCoreMLRequest = {
do {
let model = try VNCoreMLModel(for: AnimalClassifier().model)
let request = VNCoreMLRequest(model: model, completionHandler: { [weak self] request, error in
self?.processClassifications(for: request, error: error)
})
request.imageCropAndScaleOption = .centerCrop
return request
} catch {
fatalError("Failed to load Vision ML model: \(error)")
}
}()
func updateClassifications(for Image: UIImage) {
classificationLabel.text = "Classifying..."
let orientation = CGImagePropertyOrientation(Image.imageOrientation)
guard let ciImage = CIImage(image: Image) else { fatalError("Unable to create \(CIImage.self) from \(Image).") }
DispatchQueue.global(qos: .userInitiated).async {
let handler = VNImageRequestHandler(ciImage: ciImage, orientation: orientation)
do {
try handler.perform([self.classificationRequest])
} catch {
print("Failed to perform classification.\n\(error.localizedDescription)")
}
}
}
func processClassifications(for request: VNRequest, error: Error?) {
DispatchQueue.main.async {
guard let results = request.results else {
self.classificationLabel.text = "Unable to classify image.\n\(error!.localizedDescription)"
return
}
let classifications = results as! [VNClassificationObservation]
if classifications.isEmpty {
self.classificationLabel.text = "Nothing recognized."
} else {
// Display top classifications ranked by confidence in the UI.
let topClassifications = classifications.prefix(2)
let descriptions = topClassifications.map { classification in
// Formats the classification for display; e.g. "(0.37) cliff, drop, drop-off".
return String(format: " (%.2f) %#", classification.confidence, classification.identifier)
}
self.classificationLabel.text = "Classification:\n" + descriptions.joined(separator: "\n")
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
var Image: UIImage
if let possibleImage = info[.editedImage] as? UIImage {
Image = possibleImage
} else if let possibleImage = info[.originalImage] as? UIImage {
Image = possibleImage
} else {
return
}
myImageView.image = Image
dismiss(animated: true)
updateClassifications(for: Image)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
To make your label support multiple lines you need to set the property numberOfLines to 0. So in viewDidLoad for instance do
classificationLabel.numberOfLines = 0