firebase image size increase - swift

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.

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")
})
}
}

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

Swift: Get the correct file size for JPEG image

I have a UIImage object, say from the camera roll via PHAsset. The image is saved as a .jpg file:
asset.requestContentEditingInput(with: nil) { (input, nil) in
print(input?.fullSizeImageURL) // somefile.jpg
}
To get the file size should not data.count from this return the correct file size in bytes?
PHImageManager.default().requestImageData(for: asset, options: nil) { data, _, _, _ in
if let _data = data {
print(_data.count) // 6759240
}
}
The output for a particular image is 6759240 while fileSize() returns 2978548.0 (which is the right file size) bytes.
func fileSize(forURL url: Any) -> Double {
var fileURL: URL?
var fileSize: Double = 0.0
if (url is URL) || (url is String)
{
if (url is URL) {
fileURL = url as? URL
}
else {
fileURL = URL(fileURLWithPath: url as! String)
}
var fileSizeValue = 0.0
try? fileSizeValue = (fileURL?.resourceValues(forKeys: [URLResourceKey.fileSizeKey]).allValues.first?.value as! Double?)!
if fileSizeValue > 0.0 {
fileSize = (Double(fileSizeValue))
}
}
return fileSize
}
Does it mean someUIImage?.jpegData(compressionQuality: 1)?.count does not return the correct size of JPEG image file (if saved)?
One more thing, Is there any way to determine the image file size before writing it on the disk?
All of these is to compare the file size between the original and compressed image.
This sounds like a misunderstanding of what the various terms and calls refer to.
You have no direct access to a file stored in the user's Photo library. There may in fact be no such file; you should make no assumptions about the storage format. When you ask PHImageManager for an image's data, you are given the bitmap data, ready for use. Thus you should expect this data to be big, in exact proportion to the dimensions of the image. 6759240 is more than 6MB, which sounds about right on an older iPhone; a newer iPhone, takes 4032x3024 photos which is more than 8MB.
Then in a different part of your code you call fileSize(forURL:). Now you're looking at an actual file, in the file system, in a place where you can access it. If this is an image file, it is compressed; just how much it is compressed depends on the format. 2978548 is about 3MB which is pretty good for a JPEG compressed without too much lossiness.
Finally, you ask about UIImage jpegData(compressionQuality: 1)?.count. You do not show any code that actually calls that. But this is data ready for saving as a file directly with write(to:) and a URL, and I would expect it to be the same as fileSize(forURL:) if you were to check the very same file later.

Load UIImage from PHAsset Image absoluteString Swift 4

I am saving a list of file names/paths so I can load the image at a later time to upload it.
When the user selects the images from the camera roll, I get back this
file:///Users/admin/Library/Developer/CoreSimulator/Devices/B31CE61D-FB46-41F0-B254-B66B9335E1E4/data/Media/DCIM/100APPLE/IMG_0005.JPG
But when I try to load up the image,
if let image = UIImage(named: filepath) {
imageView.image = image
}
It doesn't load.
How do I load an image from a filepath?
The code I use to get the file path
func getURL(ofPhotoWith mPhasset: PHAsset, completionHandler : #escaping ((_ responseURL : URL?) -> Void)) {
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
mPhasset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
completionHandler(contentEditingInput!.fullSizeImageURL)
})
}
func add(images: [PHAsset]) {
for image in images {
getURL(ofPhotoWith: image) { (imgURL) in
if let imgURL = imgURL {
print ("ImageURL: \(imgURL.absoluteString)")
}
}
}
}
I am saving a list of file names/paths so I can load the image at a later time to upload it.
PHContentEditingInput is the wrong tool for that job. As the names of that class and the functions you're using to get one suggest, it's for content editing — tasks like applying a filter to an asset in the library.
When PHContentEditingInput gives you a file URL, it's granting you temporary access to that file. PhotoKit makes no guarantee that the asset in question will always be backed by a file at that URL, and even if it is, PhotoKit revokes temporary access to that URL when the owning PHContentEditingInput is deallocated.
A user's Photos library isn't a directory full of image files — it's a database, where each asset can have data resources stored in one or more files, which might or might not even be in local storage at all times. If you want to upload assets to an external service and preserve all the original data, you need an API that's meant for getting data resources. PhotoKit gives you two choices for that:
If you want just some image representation of the current state of the asset, use PHImageManager. This downloads and/or generates image data ready for you to save as a file, incorporating whatever edits the user has already applied to the asset:
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isNetworkAccessAllowed = true
PHImageManager.default().requestImageData(for: myAsset, options: options) { data, uti, orientation, info in
// save `data` to file / upload to web service
// use `uti` to find out what file type it is
}
If you want the original image data resources — that is, enough data that you could back up and restore the asset, including features like in-progress edits, Live Photo modes, and RAW format image data — use PHAssetResource and PHAssetResourceManager:
let resources = PHAssetResource.resources(for: myAsset)
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
for resource in resources {
let outputURL = myOutputDirectory.appendingPathComponent(resource.originalFilename)
PHAssetResourceManager.default().writeData(for: resource, to: outputURL, options: options) { error in
// handle error if not nil
}
}
I am saving a list of file names/paths so I can load the image at a later time to upload it when the user selects the images from the camera roll
Don't. The thing to save so that you can retrieve something from the camera roll at a later time is the PHAsset's localIdentifier. You can use that to get the same asset again later, and now you can ask for the associated image.

Get pdf from Firebase Storage

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