Firebase retrieve image from URL save with Firebase database - swift

I have saved an image to the Firebase storage and also saved the imageURL to Firebase database, but how can I get the image back by the URL saved in firebase database? Here is how I save it
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
userPhoto.image = image
dismissViewControllerAnimated(true, completion: nil)
var data = NSData()
data = UIImageJPEGRepresentation(userPhoto.image!, 0.8)!
// set upload path
let filePath = "\(FIRAuth.auth()!.currentUser!.uid)/\("userPhoto")"
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
self.storageRef.child(filePath).putData(data, metadata: metaData){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
} else {
// store downloadURL
let downloadURL = metaData!.downloadURL()!.absoluteString
// store downloadURL at database
self.databaseRef.child("users").child(FIRAuth.auth()!.currentUser!.uid).updateChildValues(["userPhoto": downloadURL])
}
}
}

Here's one way of doing it, by downloading the data and then creating a UIImage for it:
self.storage.referenceForURL(url).dataWithMaxSize(25 * 1024 * 1024, completion: { (data, error) -> Void in
let image = UIImage(data: data!)
chatMessage.image = image!
self.messages.append(chatMessage)
self.tableView.reloadData()
self.scrollToBottom()
})
This code comes from the Zero To App talk at Google I/O. Complete code is available in this gist

Related

download image from firebase storage in swift

Have the image location as gs://olio-ae400.appspot.com/Listings/Food/-M3g8pZDGmApicUAQtOi/MainImage
I want to download from this firebase storage location to imageview.
Have used below code,but the unable to download image from url?
let storage = Storage.storage()
var reference: StorageReference!
reference = storage.reference(forURL: "gs://olio-ae400.appspot.com/Listings/Food/-M3g8pZDGmApicUAQtOi/MainImage")
reference.downloadURL { (url, error) in
print("image url is",url!)
let data = NSData(contentsOf: url!)
let image = UIImage(data: data! as Data)
self.img.image = image
}
Getting error at downloadURL line while retrieving the url for it in the response.
What is the correct way for it to download the image?
Install the pod firebaseUI.
import FirebaseUI
fetch the reference from the storage and set the reference to the imageview directly using SDwebimage as shown below.
let ref2 = Storage.storage().reference(forURL: "gs://hungry-aaf15.appspot.com/Listings/Food/-MV04bNvewyGPHMYUkK9/MainImage")
cell.img.sd_setImage(with: ref2)
Specify path and it's extension, then Use:
let path = "Listings/Food/-M3g8pZDGmApicUAQtOi/MainImage.jpg"
let reference = Storage.storage().reference(withPath: path)
reference.getData(maxSize: (1 * 1024 * 1024)) { (data, error) in
if let err = error {
print(err)
} else {
if let image = data {
let myImage: UIImage! = UIImage(data: image)
// Use Image
}
}
}
For Swift 5.6 and Xcode 13.4
I opened name "Images" folder in Firebase and uploaded my image which name "Corleone" in jpg format.
Firstly I fetch image data then assigned to imageView. Lastly, i downloaded image URL. You can use two method differently.
You can copy all what i wrote and past your project inside of viewDidload or buttonAction.
let storage = Storage.storage().reference().child("Images/Corleone.jpg")
storage.getData(maxSize: 1 * 1024 * 1024) { data, error in
if error != nil {
print(error?.localizedDescription ?? "errror")
}else{
let image = UIImage(data: data!)
self.imageView.image = image
storage.downloadURL { url, error in
if error != nil {
print(error?.localizedDescription ?? "error")
}else {
print(url ?? "url") //https://firebasestorage.googleapis.com/v0/b/epeycompare.appspot.com/o/Images%2FCorleone.jpg?alt=media&token=04c6369d-8036-4aef-8052-bac21c89eeda
}
}
}
}

Swift 5 How to add exif data to image get from PHAsset

I have this simply code to get an uiImage from Photo Library:
private func getDataOfMedia (asset:PHAsset) -> Data {
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true
requestOptions.isNetworkAccessAllowed = true
let imgManager = PHImageManager.default()
var imgData = Data()
// Request Image
imgManager.requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: requestOptions) { (uiimage, info) in
if let uiimage = uiimage {
DispatchQueue.main.async {
if let imageData = uiimage.jpegData(compressionQuality: 1) {
imgData = imageData
}
}
}
}
return imgData
}
but, of course, I can't see the camera data, location data and exif data of the image saved from func getDataOfMedia(asset: asset), but if I download the same image directly from Photo, I can see camera data, location data and exif data.
How can I do to add camera data, location data and exif data to data that I have from requestimage of PHAsset?
How can I add the unique id, for example asset.localIdentifier, to know that I have download this image?
UPDATE
I managed to extract camera data, location data and exif data from an image from an asset object, with this code:
private func getDataOfImageC (asset:PHAsset, completion: #escaping (Data) -> Void) {
//For get exif data
let options = PHContentEditingInputRequestOptions()
options.isNetworkAccessAllowed = true //download asset metadata from iCloud if needed
asset.requestContentEditingInput(with: options) { (contentEditingInput: PHContentEditingInput?, _) -> Void in
let fullImage = CIImage(contentsOf: contentEditingInput!.fullSizeImageURL!)
let image = UIImage(ciImage: fullImage!)
print(fullImage!.properties)
for (key, value) in fullImage!.properties {
print("key: \(key) - value: \(value)")
}
completion(image.jpegData(compressionQuality: 1)!)
}
}
but turning CIImage to UIImage to Data format, to save it locally, it loses all camera data, location data and exif data.
I hope that someone help me.
After some study, this the code that work for me to save image (not video) from photoLibrary with all properties.
private func saveDataOfImageCI (asset:PHAsset, urlMedia: URL) {
//For get exif data
let options = PHContentEditingInputRequestOptions()
options.isNetworkAccessAllowed = true //download asset metadata from iCloud if needed
asset.requestContentEditingInput(with: options) { (contentEditingInput: PHContentEditingInput?, _) -> Void in
let url = contentEditingInput!.fullSizeImageURL!
let fullImage = CIImage(contentsOf: contentEditingInput!.fullSizeImageURL!)
do {
try CIContext().writeJPEGRepresentation(of: fullImage!,
to: urlMedia,
colorSpace: (fullImage?.colorSpace)!)
} catch {
print("error: \(error.localizedDescription)")
}
//To print properties data (exif, camera data, ....)
for (key, value) in fullImage!.properties {
print("key: \(key) - value: \(value)")
}
}
}

Upload image to Firebase from UIImagePicker

I would like to upload a profile picture to Firebase when my UIImage picker has been chosen. But I don't know how to do it and
I can not understand the documentation, because I'm new in coding). Please, help me. I need to upload picture to Firebase. It will be user picture, so reference to picture should save to Database.
extension ProfileViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
profileImage.image = image
picker.dismiss(animated: true, completion: nil)
}
I don't how to upload and dowload profile image.
Create a storage reference and add folder name and image names.
Storage.storage().reference().child("id").child("profile.png")
and use putData:metadata:completion: method to upload the image. Once image has been uploaded get the image url and update it in user details.
Upload profile image
import FirebaseStorage
import FirebaseAuth
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.originalImage] as? UIImage, let imageData = image.pngData() {
profileImage.image = image
let storageRef = Storage.storage().reference().child("id").child("profile.png")
let metaData = StorageMetadata()
metaData.contentType = "image/png"
storageRef.putData(imageData, metadata: metaData) { (metaData, error) in
if error == nil, metaData != nil {
storageRef.downloadURL { url, error in
if let url = url {
print(url)//URL of the profile image
self.saveProfileImageUrlInUserDetails(url: url)
}
}
} else {
print(error?.localizedDescription)//upload failed
}
}
}
picker.dismiss(animated: true, completion: nil)
}
Save uploaded photo reference in user detail Update the user's profile
func saveProfileImageUrlInUserDetails(url: URL) {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.photoURL = url
changeRequest?.commitChanges(completion: { error in
if error == nil {
//saved
} else {
print(error?.localizedDescription)//failed to udpate
}
})
}
Download profile image
if let profileImgUrl = Auth.auth().currentUser?.photoURL?.absoluteString {
let ref = Storage.storage().reference(forURL: profileImgUrl)
ref.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print(error.localizedDescription)
} else if let data = data, let image = UIImage(data: data) {
self.profileImage.image = image
}
}
}

I have a 'UIImage' and I want to convert it to NSData to upload on firebase storage

I want to upload an Image of type Jpeg to firebase storage
Below is the function to upload to firebase storage
func uploadImageToFirebase (data: NSData){
let StorageRef = Storage.storage().reference().child("User Products")
let uploadMetadata = StorageMetadata()
uploadMetadata.contentType = "image/jpeg"
StorageRef.putData(data as Data, metadata: uploadMetadata) { (metadata, error) in
if (error != nil){
print("I have an error")
}else {
print("upload metadata \(String(describing: metadata))")
}
}
Here I have the picker controller function which is located in another class called CamViewController
here I call the function from Mainviewcontroller class
var discover = MainViewController()
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage
imageCam.image = image
discover.uploadImageToFirebase(data: image)
picker.dismiss(animated: true, completion: nil)
}
I get the error:
Cannot convert value of type UIImage? to expected argument type NSData
You need
func uploadImageToFirebase (_ image:UIImage){
gurad let data = image.pngData() else { return }
..... OR
guard let data = image.jpegData(compressionQuality: 0.5) else { return }
}
discover.uploadImageToFirebase(image)
the error is clear the parameter type is NSData so you can't pass a UIImage

Save image in Realm

I'm trying to pick image from device's Photo Library in method:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
userPhoto.image = info[UIImagePickerControllerOriginalImage] as! UIImage?
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
dismiss(animated: true, completion: nil)
}
and save this picture in Realm (as NSData):
asset.assetImage = UIImagePNGRepresentation(userPhoto.image!)! as NSData?
...
try! myRealm.write
{
user.assetsList.append(asset)
myRealm.add(user)
}
After build succeeded and trying to pick and save image (in the app) i have app error:
'Binary too big'
What i'm doing wrong?
P.S. Sorry for my English :)
After some actions i have this code. But it's overwrite my image.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let imageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)
let image = info[UIImagePickerControllerOriginalImage]as! UIImage
let data = UIImagePNGRepresentation(image)
do
{
try data?.write(to: localPath!, options: Data.WritingOptions.atomic)
}
catch
{
// Catch exception here and act accordingly
}
userPhoto.image = image
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
urlCatch = (localPath?.path)!
self.dismiss(animated: true, completion: nil);
}
Don't save the image itself into realm, just save the location of the image into realm as String or NSString and load the image from that saved path. Performance wise it's always better to load images from that physical location and your database doesn't get too big
func loadImageFromPath(_ path: NSString) -> UIImage? {
let image = UIImage(contentsOfFile: path as String)
if image == nil {
return UIImage()
} else{
return image
}
}
or you just save the image name, if it's in your documents directory anyhow
func loadImageFromName(_ imgName: String) -> UIImage? {
guard imgName.characters.count > 0 else {
print("ERROR: No image name")
return UIImage()
}
let imgPath = Utils.getDocumentsDirectory().appendingPathComponent(imgName)
let image = ImageUtils.loadImageFromPath(imgPath as NSString)
return image
}
and here a rough example how to save a captured image to your directory with a unique name:
#IBAction func capture(_ sender: AnyObject) {
let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo)
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (imageDataSampleBuffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
//self.stillImage = UIImage(data: imageData!)
//self.savedImage.image = self.stillImage
let timestampFilename = String(Int(Date().timeIntervalSince1970)) + "someName.png"
let filenamePath = URL(fileReferenceLiteralResourceName: getDocumentsDirectory().appendingPathComponent(timestampFilename))
let imgData = try! imageData?.write(to: filenamePath, options: [])
})
/* helper get Document Directory */
class func getDocumentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
//print("Path: \(documentsDirectory)")
return documentsDirectory as NSString
}
https://realm.io/docs/objc/latest/#current-limitations
maximum data size is 16 MB . this is limitation of realm
Depending on how your serializing the image data (for example if it's a lossless bitmap), it's quite possible that this data exceed 16MB, which as you've stated is Realm's maximum supported size for binary properties.
When you invoke NSData.length, how large does it say your data is?