I am trying to read/display an image from Firebase. I am first encoding the image and then posting this encoded String to Firebase. This runs fine. When I try and decode the encoded string from Firebase and convert it to an image, I am getting a nil value exception.
This is how I am saving the image to Firebase
var base64String: NSString!
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
var uploadImage = image as! UIImage
var imageData = UIImagePNGRepresentation(uploadImage)!
self.base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let ref = Firebase(url: "https://XXX.firebaseio.com")
var quoteString = ["string": self.base64String]
var usersRef = ref.childByAppendingPath("goalImages")
var users = ["image": quoteString]
usersRef.setValue(users)
displayAlert("Image Posted", message: "Your image has been successfully posted!")
}
This is how I am trying to read the image from Firebase
// ViewController.swift
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var image: UIImageView!
var base64String: NSString!
#IBAction func buttonClicked(sender: AnyObject) {
sender.setTitle("\(sender.tag)", forState: UIControlState.Normal)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let ref = Firebase(url: "https://XXX.firebaseio.com/goalImages/image/string")
ref.observeEventType(.Value, withBlock: { snapshot in
self.base64String = snapshot.value as! NSString
let decodedData = NSData(base64EncodedString: self.base64String as String, options: NSDataBase64DecodingOptions())
//Next line is giving the error
var decodedImage = UIImage(data: decodedData!)
self.image.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The error says: "fatal error: unexpectedly found nil while unwrapping an Optional value"; decodedData is nil. Could someone explain what is going wrong.
Instead of
let decodedData = NSData(base64EncodedString: self.base64String as String,
options: NSDataBase64DecodingOptions())
try adding IgnoreUnknownCharacters
NSDataBase64DecodingOptions.IgnoreUnknownCharacters
Use Example: Encode a jpg, store and read from firebase
encode and write our favorite starship
if let image = NSImage(named:"Enterprise.jpeg") {
let imageData = image.TIFFRepresentation
let base64String = imageData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
let imageRef = myRootRef.childByAppendingPath("image_path")
imageRef.setValue(base64String)
read and decode
imageRef.observeEventType(.Value, withBlock: { snapshot in
let base64EncodedString = snapshot.value
let imageData = NSData(base64EncodedString: base64EncodedString as! String,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = NSImage(data:imageData!)
self.myImageView.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
EDIT 2019_05_17
Update to Swift 5 and Firebase 6
func writeImage() {
if let image = NSImage(named:"Enterprise.jpg") {
let imageData = image.tiffRepresentation
if let base64String = imageData?.base64EncodedString() {
let imageRef = self.ref.child("image_path")
imageRef.setValue(base64String)
}
}
}
func readImage() {
let imageRef = self.ref.child("image_path")
imageRef.observeSingleEvent(of: .value, with: { snapshot in
let base64EncodedString = snapshot.value as! String
let imageData = Data(base64Encoded: base64EncodedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
let decodedImage = NSImage(data: imageData)
self.myImageView.image = decodedImage
})
}
Firebase Engineer here:
I highly recommend using the new Firebase Storage API for uploading images to Firebase. It's simple to use, low cost, and backed by Google Cloud Storage for huge scale.
You can upload from NSData or an NSURL pointing to a local file (I'll show NSData, but the principle is the same):
// Data in memory
let data: NSData = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
// This can be stored in the Firebase Realtime Database
// It can also be used by image loading libraries like SDWebImage
}
}
You can even pause and resume uploads, and you can easily monitor uploads for progress:
// Upload data
let uploadTask = storageRef.putData(...)
// Add a progress observer to an upload task
uploadTask.observeStatus(.Progress) { snapshot in
// Upload reported progress
if let progress = snapshot.progress {
let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
}
}
Related
I'm trying to load data from the firebase. I successfully load the data like usename and email, but somehow it fails to load the image. I'm attaching my code which I have used to load the data from firebase. Please help. thank you.
code :
import UIKit
import FirebaseDatabase
import Firebase
class ProfileVC: UIViewController {
#IBOutlet weak var currentphoto: UIImageView!
#IBOutlet weak var usernameLabel: UILabel!
#IBOutlet weak var BioOrEmailLabel: UILabel!
var databasereff : DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
databasereff = Database.database().reference()
if let userid = Auth.auth().currentUser?.uid
{
databasereff.child("users").child(userid).observeSingleEvent(of: .value, with: { (snapshot) in
let dict = snapshot.value as? [String:Any]
let username = dict?["username"] as? String
let email = dict?["email"] as? String
if let photourl = dict?["profileimageUrl"] as? String
{
let url = URL(string: photourl)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil{
print(error?.localizedDescription)
return
}
OperationQueue.main.addOperation {
self.currentphoto.image = UIImage(data: data!)
}
}).resume()
}
self.usernameLabel.text = username
self.BioOrEmailLabel.text = email
})
{
(error) in
print(error.localizedDescription)
}
}
// Do any additional setup after loading the view.
}
}
You need to create FIRStorage reference to retrieve files from Firebase Data Base.
First:
import FirebaseStorage
Second take a storage reference:
var storage: FIRStorage!
Then Initialize it
storage = FIRStorage.storage()
Now:
let dbRef = database.reference().child("myFiles")
dbRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
// Get download URL from snapshot
let downloadURL = snapshot.value() as! String
// Create a storage reference from the URL
let storageRef = storage.referenceFromURL(downloadURL)
// Download the data, assuming a max size of 1MB (you can change this as necessary)
storageRef.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
// Create a UIImage, add it to the array
let pic = UIImage(data: data)
picArray.append(pic)
})
})
In your case path is different so just change the path and Cheers!
Reference: from here
I'm trying to download video preview base on remote video URL. In my project, the server cannot return snapshot image of the videos, that's why I have to do it manually.
In table view, I have code like this in cellForItemAt to get video preview
DataManager.sharedInstance.getCachedImage(url: movie.url!, handler: { (image) in
cell.ivCover.image = image
})
and my getCachedImage function in DataManager:
func getCachedImage(url: String, handler: #escaping(_ result:UIImage) -> Void){
DispatchQueue.global().async {
let userDefaults = UserDefaults.standard
if let imageData = userDefaults.object(forKey: url){
if let finalImg = UIImage(data: imageData as! Data){
DispatchQueue.main.async {
handler(finalImg)
}
print("USING CACHED IMG")
}else{
DispatchQueue.main.async {
handler(#imageLiteral(resourceName: "cover"))
}
print("Cannot parse cached data to image. Use default")
}
}else{
let asset = AVURLAsset(url: URL(string: url)!)
let generate = AVAssetImageGenerator(asset: asset)
generate.appliesPreferredTrackTransform = true
var thumbTime = asset.duration
thumbTime.value = 1
var imgRef:CGImage?
do{
print("Downloading thum from url: \(url)")
imgRef = try generate.copyCGImage(at: thumbTime, actualTime: nil)
}catch let error{
print("Error download thum: \(error.localizedDescription)")
}
var finalImg:UIImage
if let _ = imgRef{
finalImg = UIImage(cgImage: imgRef!)
userDefaults.set(UIImagePNGRepresentation(finalImg), forKey: url)
}else{
finalImg = #imageLiteral(resourceName: "cover")
print("Download thumnail failed. Use default")
}
DispatchQueue.main.async {
handler(finalImg)
}
}
}
}
The problem is that, sometimes I scroll the Collection view, UI is freezed, sometimes it's not. Please note that this video is on REMOTE SERVER, NOT local video.
I've spent days to figure out the issue but still not able to find out what went wrong. Please help!
Or is there any existing library I can use?
import UIKit
import Photos
class ImportViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func myButton(_ sender: Any) {
let videoURL = "https://youerdomin.com/file.mp4"
print("1")
DispatchQueue.global(qos: .background).async {
print("2")
if let url = URL(string: videoURL), let urlData = NSData(contentsOf: url) {
print("3")
let documentsPath =
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(documentsPath)/tempFile.mp4"
DispatchQueue.main.async {
print("4")
urlData.write(toFile: filePath, atomically: true)
PHPhotoLibrary.shared().performChanges({
print("5")
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
}) { completed, error in
print("6")
if completed {
print("Video is saved!")
}else{
print("7: ",filePath)
}
}
}
}else{
print("8")
}
}
}
}
I'm developing an app which has UICollectionView as like #zhangao0086/DKImagePickerController# example in Github. Now i need to upload the displayed UICollectionviewCell images into server. Can any one suggest me the right tuts for uploading. Thanks in advance.
UICollectionView code as follows:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let asset = self.assets![indexPath.row]
var cell: UICollectionViewCell?
var imageView: UIImageView?
if asset.isVideo {
cell = collectionView.dequeueReusableCellWithReuseIdentifier("CellVideo", forIndexPath: indexPath)
imageView = cell?.contentView.viewWithTag(1) as? UIImageView
} else {
cell = collectionView.dequeueReusableCellWithReuseIdentifier("CellImage", forIndexPath: indexPath)
imageView = cell?.contentView.viewWithTag(1) as? UIImageView
}
if let cell = cell, imageView = imageView {
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
let tag = indexPath.row + 1
cell.tag = tag
asset.fetchImageWithSize(layout.itemSize.toPixel(), completeBlock: { image, info in
if cell.tag == tag {
imageView.image = image
}
})
}
return cell!
}
uploading the image into server
func barButtonItemClicked(barButtonItem: UIBarButtonItem)
{
let myUrl = NSURL(string: "http://moneymonkey.tokiiyo.com/api/signature");
let typeItem: InsuranceType = InsuranceManager.sharedInstance.TypeArray[0]
let compItem: Companies = InsuranceManager.sharedInstance.CompArray[0]
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
let param = [
"api_key" : "AiK58j67",
"api_secret" : "a#9rJkmbOea90-",
"phone" : "\(mobile)",
"policy_type" : "\(typeItem.name)",
"company" : "\(compItem.cname)"
]
print("Policy_type: \(typeItem.name)")
let boundary = generateBoundaryString()
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let imageData = UIImagePNGRepresentation(?) //here what imageView
if(imageData==nil) { return; }
request.HTTPBody = createBodyWithParameters(param, filePathKey: "file", imageDataKey: imageData!, boundary: boundary)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
// You can print out response object
print("******* response = \(response)")
// Print out reponse body
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("****** response data = \(responseString!)")
do{
_ = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
dispatch_async(dispatch_get_main_queue(),{
});
}
catch
{
// report error
print("Oops!! Something went wrong\(error)")
}
}
task.resume()
}
func createBodyWithParameters(parameters: [String: String]?, filePathKey: String?, imageDataKey: NSData, boundary: String) -> NSData {
let body = NSMutableData();
if parameters != nil {
for (key, value) in parameters! {
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
body.appendString("\(value)\r\n")
}
}
let filename = "image.png"
let mimetype = "image/png"
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
body.appendString("Content-Type: \(mimetype)\r\n\r\n")
body.appendData(imageDataKey)
body.appendString("\r\n")
body.appendString("--\(boundary)--\r\n")
return body
}
func generateBoundaryString() -> String {
return "Boundary-\(NSUUID().UUIDString)"
}
J
you can use Alamofire https://github.com/Alamofire/Alamofire
Use like this :
Alamofire.upload(.POST, "YourURl", file: YourFile)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
print(totalBytesWritten)
// This closure is NOT called on the main queue for performance
// reasons. To update your ui, dispatch to the main queue.
dispatch_async(dispatch_get_main_queue()) {
print("Total bytes written on main queue: \(totalBytesWritten)")
}
}
.responseJSON { response in
debugPrint(response)
}
I have UIImage (got from Parse - convert variable PFFile).
How can I save and load image from this variable?
let a = object["image"] as! PFFile
a.getDataInBackgroundWithBlock({ (data:NSData?, error:NSError?) -> Void in
if (error == nil) {
// I have image, but the next I don't know what I do
let image = UIImage(data:data!)
}
})
Save image png
func saveImage(image:UIImage,name:String){
let selectedImage: UIImage = image
let data:NSData = UIImagePNGRepresentation(selectedImage)
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let success = fileManager.createFileAtPath(path, contents: data, attributes: nil)
print(success)
// Check image saved successfully
let getImagePath = (path as NSString).stringByAppendingPathComponent(name)
if fileManager.fileExistsAtPath(getImagePath) {
// image save success
let image = UIImage(contentsOfFile: getImagePath)!
}
else{
// image save error
}
}
Save other file
static func saveFile(fileData:NSData,name:String)->Bool{
let success = NSFileManager.defaultManager().createFileAtPath(path+"/"+name, contents: fileData, attributes: nil)
return success
}
I want to download an image from Facebook and store it to my cache, which I call over HTTPS. If I just use HTTP everything works fine, but if I change it to HTTPS it does not work anymore.
Here is my code:
// Grab the artworkUrl key to get an image URL for thumbnail
var urlString: NSString = rowData["cover"] as NSString
// Check our image cache for the existing key. This is just a dictionary of UIImages
var image: UIImage? = self.imageCache.valueForKey(urlString) as? UIImage
if( !image? ) {
// If the image does not exist, we need to download it
var imgURL: NSURL = NSURL(string: urlString)
// Download an NSData representation of the image at the URL
var request: NSURLRequest = NSURLRequest(URL: imgURL)
var urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if !error? {
//var imgData: NSData = NSData(contentsOfURL: imgURL)
image = UIImage(data: data)
// Store the image in to our cache
self.imageCache.setValue(image, forKey: urlString)
cell.image = image
println(self.imageCache)
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
else {
cell.image = image
}
})
The URL I want to use is this:
https://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/t1.0-9/q71/s720x720/995054_485489274919674_7207866955460529362_n.jpg
The Error is a "Timeout".
With this URL everything works fine:
http://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/t1.0-9/q71/s720x720/995054_485489274919674_7207866955460529362_n.jpg
Thanks,
Tobias
From what I can tell NSURLConnection sometimes runs into trouble with HTTPS connections. Try adding these two methods to your class (and mark it as NSURLConnectionDelegate) (from this answer):
func connection(connection: NSURLConnection!, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace!) -> Bool {
return true
}
func connection(connection: NSURLConnection!, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge!) {
challenge.sender.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust), forAuthenticationChallenge: challenge)
}