Get pdf from Firebase Storage - swift

Let's say I have a PDF file with 10 pages in Firebase Storage.
In the Firebase Storage references it has the code below.
let islandRef = storageRef.child("images/island.jpg")
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
islandRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
// Uh-oh, an error occurred!
} else {
// Data for "images/island.jpg" is returned
let image = UIImage(data: data!)
}
}
I have tried this and did my best to download and also show the pdf file using PDFKit. But I always get an error from Firebase or something wrong in the console.
The way I did it was change the file name to the correct one and also change the number "1" to "10"
I don't know how to use the local files like in the reference.
//edited
let storage = Storage.storage()
let storageRef = storage.reference(forURL: "gs://---.appspot.com")
let dataRef = storageRef.child("Slide.pdf")
let downloadTask = dataRef.getData(maxSize: 100 * 2000 * 2000) { data, error in
if (error != nil) {
print("Uh-oh, an error occurred!")
} else {
print("download success!!")
let pdf:PDFDocument = PDFDocument(data: data!)!
self.userDefaults.setValue(pdf, forKey: "PDF-Slide")
}
}
EDIT
Sorry for asking such a crazy question.
I got it fixed, I had the pdf file downloaded all along, and I was trying to save a pdf file to userdefault so the app always crashed since it doesn't support saving pdfdocuments

FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
String userEmail = user.getEmail();
StorageReference str = FirebaseStorage.getInstance().getReference().child(userEmail+".pdf");
Toast.makeText(this, "pdf"+str, Toast.LENGTH_SHORT).show();

Related

Trouble Uploading Multiple Images to Firebase Storage

I have an array of image data(in bytes), and I want to upload them to storage and get the download URL for all of them. But after uploading lots of pictures, there is only one file appears in the storage under the reference. I do get the download URLs, but only the last one works, the rest all say access denied.
I suspect it is because I am putting all the pictures under the same storage reference and the picture substitutes every time. But what can I do to upload multiple images?
My upload code:
var picturesURL: [String] = [] // I want to put the download URL in this array
if self.imageButton.isSelected{
picturesURL = []
for photoData in self.pictures{ // pictures is the array that stores all the photo data
self.storage.child("images/file.png").putData(photoData, metadata: nil) { _, error in
guard error == nil else{
print("Failed to upload")
return
}
self.storage.child("images/file.png").downloadURL (completion: { url, error in
guard let url = url, error == nil else{
print("problems getting url")
return
}
let urlString = url.absoluteString
picturesURL.append(urlString)
print(urlString)
//UserDefaults.standard.set(urlString, forKey: "url")
})
}
}

Swift Vapor 4 upload , validate , resize an image file

I am trying to post a photo to the vapor 4 server.
I am sending a Team name as a string and an image as data.
struct SendTeam: Content {
var name: String
var img: Data
}
I want to upload the photo after validating its size to be not more than 1MB, and mimetype is of type image like (jpg, jpeg, png), then resize that image to 300px*300px and finally save it to the public\uploads directory.
I am not able to figure out how to do that.
Here is my code.
func create(req: Request) async throws -> SendTeam {
let team = try req.content.decode(SendTeam.self)
let path = req.application.directory.publicDirectory + "originals/" + team.name + "-\(UUID())"
try await req.fileio.writeFile(.init(data: team.img), at: path)
if team.name.count < 4 || team.name.count > 20 {
throw Abort(.badRequest, reason: "wrong name")
}
return team
}
Code should work on ubuntu server VPS cloud instance as well.
After Two Days of Testing, I am able to do that using SwiftGD, So I came up with this .. hope it is useful.
Image Validation
// Do not forget to decode the image to File type Not Data type
let img = team.img
if img.data.readableBytes > 1000000 {
errors.append( "error ... image size should not exceed 1 mb")
}
if !["png", "jpeg", "jpg"].contains(img.extension?.lowercased()) {
errors.append("extension is not acceptable")
}
let imageNewNameAndExtension = "\(UUID())"+".\(img.extension!.lowercased())"
The upload an resize part
// The upload Path
let path = req.application.directory.publicDirectory + "uploads/" + imageNewNameAndExtension
// The path to save the resized img
let newPath = req.application.directory.publicDirectory + "uploads/teams/" + imageNewNameAndExtension
// SwiftNIO File handle
let handle = try await req.application.fileio.openFile(path: path,mode: .write,flags:.allowFileCreation(posixMode:0x744),eventLoop: req.eventLoop).get()
// Save the file to the server
req.application.fileio.write(fileHandle:handle,buffer:img.data,eventLoop: req.eventLoop).whenSuccess { _ in
// SwiftGD part to resize the image
let url = URL(fileURLWithPath: path)
let newUrl = URL(fileURLWithPath: newPath)
let image = Image(url: url)
if let im = image {
if let mg = im.resizedTo(width: 250, height: 250){
mg.write(to: newUrl)
}
}
try? handle.close()
}

How to upload a PDF File to firebase that is already in memory

I have seen posts and read the docs on how to upload a file with a url reference to local disk, however, I cannot find anything about how to do this with a file in memory? The file is an array of pdfs. I take it I have to have some kind of URL reference to that file. Where would I URL reference a pdf in memory? Anybody know?
Edit:
I used this code from the Docs, however, I'm getting the following error for putData: Type of expression is ambiguous without more context
Which I think means the constructor is not expecting a type of PDFDoc?
#IBAction func confirmUploadButtonTapped(_ sender: Any) {
let uuid = UUID().uuidString
// Create a root reference
let storage = Storage.storage()
// Create a storage reference from our storage service
let storageRef = storage.reference()
// Data in memory
let data = Data()
// Create a reference to the file you want to upload
let pdfRef = storageRef.child("docRequest/" + uuid + "/" + ".pdf")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = pdfRef.putData(pdfDocument, metadata: nil) { (metadata, error) in
guard let metadata = metadata else {
// Uh-oh, an error occurred!
print(error)
return
}
// Metadata contains file metadata such as size, content-type.
let size = metadata.size
// You can also access to download URL after upload.
pdfRef.downloadURL { (url, error) in
guard let downloadURL = url else {
// Uh-oh, an error occurred!
print(error)
return
}
}
}
If you have the data for the PDF in memory already, you can upload that data to Firebase Storage by calling putData. See for an example the documentation on Upload from data in memory, or this code in the Firebase quickstart project.
This line is the issue
let pdfRef = storageRef.child("docRequest/" + uuid + "/" + ".pdf")
because it will create a path of
docRequest/xxxxx/.pdf
So you should use this
let pdfRef = storageRef.child("docRequest/" + uuid + ".pdf")
when will be a path of
docRequest/xxxxx.pdf
Also, please ensure that when that file is written to storage, you also save the url in Firebase so you can get to it later.
As far as a PDF in memory, the PDFKit (which I think you're using) has functions to work with that, check into pdfData(actions:) renderer to produce a Data object

firebase image size increase

please someone explain why this happen? I was checking so I upload an image directly from firebase and I got its original size, but when I upload it using this code the size increase.
func storeImageInFirebase(){
let storeageRef = Storage.storage().reference()
let imageName = UUID().uuidString
let imagesReference = storeageRef.child("images").child(imageName + ".jpeg")
let imageData = self.imgView.image?.jpegData(compressionQuality: 1)
let metaData = StorageMetadata()
metaData.contentType = "image/jpeg"
imagesReference.putData(imageData!, metadata: metaData){ (metadate, error)
in
guard metadate != nil else{
print("Error: \(String(describing: error?.localizedDescription))")
return
}
// Fetch the download URL
imagesReference.downloadURL(completion: {(url, error)
in
if error != nil {
print("Faild to download url:", error!)
return
}else{
print("original image url ..... \(url?.absoluteString)")
// show the url in real database
var theUsedURL = self.imgURL = (url?.absoluteString)!
self.sendDataToFirebase()
}
})
}
}
enter image description here
JPEG is a lossy file format: it stores the image data in a way that compresses it down, depending on the compression factor used.
Image data in an Image View is always uncompressed: it shows the raw bytes of the image.
Most likely, you are:
reading the compressed data from the JPEG file, then
showing the uncompressed version of that data in the image view, and finally
writing the data back to storage as an uncompressed (or less compressed) JPEG file.
If you want to control how big the compressed image is, you can modify the compressionQuality in:
jpegData(compressionQuality: 1)
If you want the exact same file to be written, you should not recompress the data, but read the uncompressed data and write that exact data directly back to storage.

Swift Firebase Storage How to retrieve image with unknow name(NSUUID)

I am making a function to retrieve the url as the user Image. However, my upload image name function created by NSUUID. Therefore, I would not know what is the name of each user profile picture. How could I improve my code to get the user imgae for every user instead of hard coding the img name?
func getUserProfilePic(){
let uid = FIRAuth.auth()?.currentUser?.uid
let profilePath = refStorage.child("\(uid)").child("profilePic/xxxxx.jpg") // xxxxx = NSUUID
profilePath.dataWithMaxSize(1 * 1024 * 1024) { (data, error) -> Void in
if (error != nil) {
print("got no pic")
} else {
let profilePic: UIImage! = UIImage(data: data!)
self.imageV.image = profilePic
print("got pic")
}
}
}
The path is uid/profilePic/--<-file name->--
upload function
func uploadingPhoto(){
let uid = FIRAuth.auth()?.currentUser?.uid
let imgName = NSUUID().UUIDString + ".jpg"
let filePath = refStorage.child("\(uid!)/profilePic/\(imgName)")
var imageData = NSData()
imageData = UIImageJPEGRepresentation(profilePic.image!, 0.8)!
let metaData = FIRStorageMetadata()
metaData.contentType = "image/jpg"
let uploadTask = filePath.putData(imageData, metadata: metaData){(metaData,error) in
if let error = error {
print(error.localizedDescription)
return
}else{
let downloadURL = metaData!.downloadURL()!.absoluteString
let uid = FIRAuth.auth()?.currentUser?.uid
let userRef = self.dataRef.child("user").child(uid!)
userRef.updateChildValues(["photoUrl": downloadURL])
print("alter the new profile pic and upload success")
}
}
I highly recommend using Firebase Storage and the Firebase Realtime Database together to store that UUID -> URL mapping, and to "list" files. The Realtime Database will handle offline use cases like Core Data as well, so there's really no reason to futz with Core Data or NSUserDefaults. Some code to show how these pieces interact is below:
Shared:
// Firebase services
var database: FIRDatabase!
var storage: FIRStorage!
...
// Initialize Database, Auth, Storage
database = FIRDatabase.database()
storage = FIRStorage.storage()
Upload:
let fileData = NSData() // get data...
let storageRef = storage.reference().child("myFiles/myFile")
storageRef.putData(fileData).observeStatus(.Success) { (snapshot) in
// When the image has successfully uploaded, we get it's download URL
let downloadURL = snapshot.metadata?.downloadURL()?.absoluteString
// Write the download URL to the Realtime Database
let dbRef = database.reference().child("myFiles/myFile")
dbRef.setValue(downloadURL)
}
Download:
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
// Do something with downloaded data...
})
})
For more information, see Zero to App: Develop with Firebase, and it's associated source code, for a practical example of how to do this.
There can be two ways to go about this :-
1.) Store the Firebase Storage path of users profile_picture in your Firebase database and retrieve every time before you start downloading your profile picture.
2.) Store the file path in CoreData every time your user uploads a profile picture and hit that path every time to get file_Path to where you stored that user's profile_pic .
Storing the path :-
func uploadSuccess(metadata : FIRStorageMetadata , storagePath : String)
{
print("upload succeded!")
print(storagePath)
NSUserDefaults.standardUserDefaults().setObject(storagePath, forKey: "storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)")
//Setting storagePath : (file path of your profile pic in firebase) to a unique key for every user "storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)"
NSUserDefaults.standardUserDefaults().synchronize()
}
Retrieving your path, Every time you start downloading your image :-
let storagePathForProfilePic = NSUserDefaults.standardUserDefaults().objectForKey("storagePath.\((FIRAuth.auth()?.currentUser?.uid)!)") as? String
Note :- i am using currentUser ID, you can use USER SPECIFIC id ,if you want to download multiple users profile pics, all you need to do is put their uid in place.