Retrieving image from Firebase Storage - android

I know this is a discussed topic, but here I am, after all other solutions I've found did not solve my problem. I saved multiple images in Firebase Storage and now I want to get one of them and put it into an ImageView on an AlertDialog (or another Activity).
I've read about Glide solution, but it doesn't work for me. Gilde:
Glide.with(ViewScenesSG.this) //ViewScenesSG is the Activity
.load(reference) //the storage reference
.into(imageView); //my imageView
Dependencies for Glide (I've tried with multiple versions and 4.8.0 is the only one that doesn't give me Build error):
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
annotationProcessor 'androidx.annotation:annotation:1.1.0'
I've also read about the .using(new FirebaseImageLoader()) method, I've implemented the FirebaseImageLoader(), but the using() method is not found => build error. I believe it's been removed.
The second version I've tried is this one (found in another question here):
final long ONE_MEGABYTE = 1024 * 1024;
reference.getBytes(ONE_MEGABYTE)
.addOnSuccessListener(new OnSuccessListener<byte[]>() {
#Override
public void onSuccess(byte[] bytes) {
Bitmap bm = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
imageView.setMinimumHeight(dm.heightPixels);
imageView.setMinimumWidth(dm.widthPixels);
imageView.setImageBitmap(bm);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
Toast.makeText(ViewScenesSG.this, "Couldn't retrieve image.", Toast.LENGTH_SHORT).show();
}
});
But every time it goes on the Failure listener. Therefore, my imageView always remains empty.
In my logcat I observed this error:
E/StorageException: Could not open resulting stream.
java.io.IOException: Could not open resulting stream.
at com.google.firebase.storage.StreamDownloadTask.createDownloadStream(com.google.firebase:firebase-storage##19.1.1:145)
at com.google.firebase.storage.StreamDownloadTask.access$000(com.google.firebase:firebase-storage##19.1.1:36)
at com.google.firebase.storage.StreamDownloadTask$1.call(com.google.firebase:firebase-storage##19.1.1:167)
at com.google.firebase.storage.StreamDownloadTask$1.call(com.google.firebase:firebase-storage##19.1.1:164)
at com.google.firebase.storage.StreamDownloadTask$StreamProgressWrapper.ensureStream(com.google.firebase:firebase-storage##19.1.1:325)
at com.google.firebase.storage.StreamDownloadTask$StreamProgressWrapper.access$100(com.google.firebase:firebase-storage##19.1.1:262)
at com.google.firebase.storage.StreamDownloadTask.run(com.google.firebase:firebase-storage##19.1.1:175)
at com.google.firebase.storage.StorageTask.lambda$getRunnable$7(com.google.firebase:firebase-storage##19.1.1:1072)
at com.google.firebase.storage.StorageTask$$Lambda$12.run(Unknown Source:2)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
E/StorageException: StorageException has occurred.
Object does not exist at location.
Code: -13010 HttpResult: 404
But the image is there, in the Storage, and the reference points directly to it:
storageRef = storage.getReference("photos").child(title); //for all images in the current folder named with the 'title' attribute
StorageReference reference = storageRef.child(imageName); //for the image I want to retrieve
What am I missing?
EDIT: Using the suggestion in the coments, I tried with:
reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Glide.with(ViewScenesSG.this)
.load(uri.toString())
.into(imageView);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(ViewScenesSG.this, "Retrieving image failed",
Toast.LENGTH_SHORT).show();
}
});
but this time I get the error:
E/StorageException: { "error": { "code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT" }}
java.io.IOException: { "error": { "code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT" }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(com.google.firebase:firebase-storage##19.1.1:433)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(com.google.firebase:firebase-storage##19.1.1:450)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(com.google.firebase:firebase-storage##19.1.1:441)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##19.1.1:272)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##19.1.1:286)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##19.1.1:70)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##19.1.1:62)
at com.google.firebase.storage.GetDownloadUrlTask.run(com.google.firebase:firebase-storage##19.1.1:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

I found the following solution (as suggested in the comments before):
Using the Firebase UI plugin with Gilde, I added the following dependency:
implementation 'com.firebaseui:firebase-ui-storage:6.2.0'
Now, having the StorageReference reference pointing to the image, and the ImageView in which the content must be uploaded, the following code retrieves the image and puts it in the ImageView:
Glide.with(ViewScenesSG.this) //this is the current Activity
.load(reference)
.into(imageView);
To be mentioned that the ImageView must have the dimensions set to a specific value, not using wrap_content or match_parent (at least for height in my case), otherwise it will appear as a small icon. This can also depend on how the image was saved before in the Storage.
Hope this will help someone else as well!

I'm not sure what's going wrong in your second snippet, but in the first snippet you seem to be passing a StorageReference to Glide. Since Glide doesn't know anything about Firebase Storage, that won't work.
Instead, you should get a download URL from Firebase Storage, which is a regular HTTPS URL that provides public access to the data, and pass that to Glide to render in the view.
Something like:
reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
// Got the download URL for 'users/me/profile.png'
Glide.with(ViewScenesSG.this)
.load(uri.toString())
.into(imageView);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});

Related

Can't get image from firebase storage using glide library

i'm trying to get profile picture for every user from firebase storage within a firestore recycler adapter. i'm using the glide library to load the picture on the imageview. But i'm getting a StorageException. I always used the same code before to get picture from Firebase Storage but now i don't know what does changed.
Here's my code:
#Override
protected void onBindViewHolder(#NonNull UsersViewHolder usersViewHolder, int i, #NonNull User user) {
FirestoreUsage.getUserPictureReference(user.getMail(), user.getGender()).child("profile_picture.jpg").getDownloadUrl()
.addOnSuccessListener(uri -> Glide.with(context).load(uri)
.into(usersViewHolder.image));
usersViewHolder.name.setText(user.getName());
usersViewHolder.city.setText(user.getCity());
}
// ONE USER STORAGE REFERENCE
public static StorageReference getUserPictureReference(String userMail, String gender) {
return getAllUsersStorageRef().child(gender).child(userMail).child("PROFILE PICTURE");
}
And here is the exception:
E/StorageException: StorageException has occurred.
Object does not exist at location.
Code: -13010 HttpResult: 404
E/StorageException: { "error": { "code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT" }}
java.io.IOException: { "error": { "code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT" }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:434)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:451)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:442)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:286)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:70)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:62)
at com.google.firebase.storage.GetDownloadUrlTask.run(GetDownloadUrlTask.java:76)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Please help me
I have found a solution for my problem. It was about path.
Earlier, when i was registrating the profil picture of the user in firebase storage, i also saved the path of the picture in firestore.
StorageReference userProfilePicture = FirestoreUsage.getUserPictureReference(Prevalent.currentUserOnline.getMail(), gender).child("profile_picture.jpg");
userProfilePicture.putFile(uriImageSelected).addOnSuccessListener(this, taskSnapshot -> {
String pathImageSavedInFirebaseStorage = Objects.requireNonNull(taskSnapshot.getMetadata()).getPath();
choiceMap.put("profile_picture", pathImageSavedInFirebaseStorage);
Prevalent.currentUserOnline.setProfile_picture(pathImageSavedInFirebaseStorage);
Then in my adapter, i created a Storage Reference with that path and dowloaded the pic
StorageReference storageReference = FirebaseStorage.getInstance().getReference(user.getProfile_picture());
storageReference.getDownloadUrl().addOnSuccessListener(uri -> Glide.with(context).load(uri)
.into(usersViewHolder.image));

How to get file name from download link in firebase storage?

I have image view which loads image using Glide using download link. Code is given below :
How can I get the file name stored in fire base storage from the download url ?
Glide.with(ct)
.load(downloadurllink)
.centerCrop();
placeholder(R.drawable.common_icon_dark)
.into(holder.image);
I had the same problem and I used a Regular Expression to extract the file name from the download URL
%2..*%2F(.*?)\?alt
Eg: If your download URL is https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffdGQ7QPLIMp7N11vSOYorUM2%2FCapture.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3 , by using %2..*%2F(.*?)\?alt you can extract "Capture.JPG"
You can get filename easily using the name property.
Example:
val httpsReference = FirebaseStorage.getInstance().getReferenceFromUrl("https://firebasestorage.googleapis.com/v0/b/art-
track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?
alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3")
Log.d(TAG, "filename: ${httpsReference.name}")
Android Example:
StorageReference storageReference = FirebaseStorage.getInstance().getReferenceFromUrl(urlImg);
String link = storageReference.getName();
Toast.makeText(EditAQuestionP1.this, link, Toast.LENGTH_SHORT).show();
If the URL is in this pattern:
https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3
then this will work to split the URL into the pattern from 2F till 2F and it will remove the extension (.jpg or .png)
String url="https://firebasestorage.googleapis.com/v0/b/art-
track.appspot.com/o/images%2Fu1nffhbfdjsa%2FN11vSOYorUM2%2FImageName.JPG?
alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3";
print(url.split(RegExp(r'(%2F)..*(%2F)'))[1].split(".")[0]);
There are many options. Two of the most used ones are:
1. You can use File Metadata in Firebase Storage to get the file name from URL. Basically, you create a Firebase Data Reference and then add a file metadata listener, like this:
// Create a storage reference from our app
StorageReference storageRef = storage.getReference();
// Get reference to the file
StorageReference fileRef = storageRef.child("images/forest.jpg");
fileRef.getMetadata().addOnSuccessListener(new OnSuccessListener<StorageMetadata>() {
#Override
public void onSuccess(StorageMetadata storageMetadata) {
String filename = storageMetadata.getName();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Uh-oh, an error occurred!
}
});
This code was taken from the documentation which I advice you to check out: File Metadata
2. Another option is to store your URL with the name in Firebase Database. This has the advantage of avoiding unnecessary listeners. That means that you can get the name with a single value event listener without having to load all of the file metadata.
database.child("files").child("url")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = dataSnapShot.getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}
It depends on your implementation on how you want to do it. Hope it helps :)
The easiest way is to use the reference method:
let storage = Storage.storage()
let yourFirestoreURL = "https://firebasestorage.googleapis.com/v0/b/art-track.appspot.com/o/images%2Fu1nffdGQ7QPLIMp7N11vSOYorUM2%2FCapture.JPG?alt=media&token=86081f67-9065-4a13-aa0b-14fab7d44bf3"
let storageRef = storage.reference(forURL: yourFirestoreURL)
print(storageRef.name)
For further details, see the google guide here: https://firebase.google.com/docs/storage/ios/create-reference
var storageReference =
firebase_storage.FirebaseStorage.instance.refFromURL(url);
String imgName = storageReference.name;
print(imgName);
If you want to delete a file having the url, you can do this:
final httpsReference = FirebaseStorage.instance.refFromURL(url);
await FirebaseStorageService.deleteFile(httpsReference.fullPath);
Solution for iOS!
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"%2F(.*?)\\?alt" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *matches = [regex matchesInString:photo_url options:0 range:NSMakeRange(0, [photo_url length])];
if (matches && matches.count > 0) {
NSString *substringForFirstMatch = [photo_url substringWithRange:[matches[0] rangeAtIndex:1]];
}

Get Image Download url by Passing Firebase Storage Reference [duplicate]

This question already has answers here:
How to get URL from Firebase Storage getDownloadURL
(13 answers)
Closed 3 years ago.
Is it Possible to get Download uri by using Firebase Storage Reference ?
This is question not similar to this question
Above question problem was get image url by uploading image.
I want to try something get Image Download URI by providing Image Ref from Storage.
I tried something :
storageReference.child("images/download.jpg").downloadUrl.addOnSuccessListener { uri ->
if (uri != null){
Log.e("url", uri.toString())
}
}
Image :
It shows Error (i know something like that does not exist) :
E/StorageException: { "error": { "code": 404, "message": "Not
Found. Could not get object", "status": "GET_OBJECT" }}
java.io.IOException: { "error": { "code": 404, "message": "Not Found. Could not get object", "status": "GET_OBJECT" }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(com.google.firebase:firebase-storage##17.0.0:455)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(com.google.firebase:firebase-storage##17.0.0:435)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(com.google.firebase:firebase-storage##17.0.0:426)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##17.0.0:280)
at com.google.firebase.storage.network.NetworkRequest.performRequest(com.google.firebase:firebase-storage##17.0.0:294)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##17.0.0:70)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(com.google.firebase:firebase-storage##17.0.0:62)
at com.google.firebase.storage.GetDownloadUrlTask.run(com.google.firebase:firebase-storage##17.0.0:74)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
I am just looking for show image without using glide library. so i am looking for image uri to show image.
Try this:
StorageReference storageReference = FirebaseStorage.getInstance().getReferenceFromUrl("storage ref url in string");
storageReference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
//do your stuff- uri.toString() will give you download URL\\
}
});
or directly use StorageReference if you already initialized it.

How to download images with specific size from firebase storage

I am using firebase storage in my android app to store images uploaded by users. all images uploaded are square in shape.
I discovered that downloading this images consumes a lot of user bandwidth and i would like to reduce this consumption by reducing the size of image downloaded into a square imageview
I am using Glide to download this images and i have tried to download images of custom size but the image is not appearing on the imageview.
interface
public interface MyDataModel {
public String buildUrl(int width, int height);
}
my class which extends BaseGlideUrlLoader
public class MyUrlLoader extends BaseGlideUrlLoader<MyDataModel> {
public MyUrlLoader(Context context) {
super(context);
}
#Override
protected String getUrl(MyDataModel model, int width, int height) {
// Construct the url for the correct size here.
return model.buildUrl(width, height);
}
}
class which implements MyDataModel interface
public class CustomImageSize implements MyDataModel {
private String uri;
public CustomImageSize(String uri){
this.uri = uri;
}
#Override
public String buildUrl(int width, int height) {
return uri + "?w=" + width + "&h=" + height;
}
}
Finally
CustomImageSize size = new CustomImageSize(uri);
Glide.with(context)
.using(new MyUrlLoader(context))
.load(size)
.centerCrop()
.priority(Priority.HIGH)
.into(imageView);
RESULTS OF SOLUTION ABOVE
Image is not appearing in my square imageview
SOLUTION 2: use firebase image loader
// Reference to an image file in Firebase Storage
StorageReference storageReference = ...;
ImageView imageView = ...;
// Load the image using Glide
Glide.with(this /* context */)
.using(new FirebaseImageLoader())
.load(storageReference)
.into(imageView);
RESULT OF SOLUTION 2 ABOVE
working! image is appearing BUT it's like entire image is been downloaded which consume a lot of bandwidth. I just want a custom size image e.g 200px by 200px to be downloaded.
How can I do or change in my solution 1 above to download images of custom size from firebase storage?
EDIT
I have tried to access one of my images https://firebasestorage.googleapis.com/....m.png from the browser and it was loaded successfully to the webpage. but when i try to put to size specific parameters to my image url link https://firebasestorage.googleapis.com/....m.png?w=100&h=100 an error appeared on the webpage
{
"error": {
"code": 403,
"message": "Permission denied. Could not perform this operation"
}
}
I was finally able to download images from firebase storage using MyUrlLoader class
You see, firebase storage urls look like this
firebasestorage.googleapis.com/XXXX.appspot.com/Folder%2Image.png?&alt=media&token=XXX
As you can see above, the link already have this special question mark character ? which stands for the start of querying string so when i use CustomImageSize class, another ? was being added so the link was ending up with two ? which made downloading to fail
firebasestorage.googleapis.com/XXXX.appspot.com/Folder%2Image.png?&alt=media&token=XXX?w=200&h=200
Solution was to remove the ? in my CustomImageSize class. so it ended up like this
public class CustomImageSize implements MyDataModel {
private String uri;
public CustomImageSize(String uri){
this.uri = uri;
}
#Override
public String buildUrl(int width, int height) {
return uri + "w=" + width + "&h=" + height;
}
}
Although it downloaded, am not sure whether entire image was being downloaded or just the custom size one. This is because, i tried to access the image in my browser after correcting the error that was making viewing to fail, but still i was receiving an entire image. not a resized image (w=200&h=200)
Try downloading your image using the following commands:-
StorageReference islandRef = storageRef.child("yourImage.jpg");
// defines the specific size of your image
final long ONE_MEGABYTE = 1024 * 1024;
islandRef.getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
#Override
public void onSuccess(byte[] bytes) {
// Data for "yourImage.jpg" is returns, use this as needed
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});

Manage image with Firebase

I am developing an android app that using firebase. My app looks like
App shows card that contains image.
I don't know how to manage image when app works in offline mode.
Could you give me suggestion to resolve it ?
First, use offline capabilities of Firebase by using .setPersistenceEnabled(true);
Use a Image Managing Cloud Server like Cloudinary to store all your images.
In your Firebase database, save the Url to the image as a String.
Use a Image Library like Picasso to get your image from the url.
This worked for me, hope it helps you.
Use Picasso or similar library for load image, show it and save in memory.
Use Firebase only for upload image to cloud and get link.
Example upload image:
StorageReference storageReference = FirebaseStorage.getInstance().getReference(app.packageName + ".webp");
UploadTask uploadTask = storageReference.putFile(Uri.fromFile(new File(app.icon)));
uploadTask.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
success = false;
countDown.countDown();
Log.e(TAG, "", e);
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Log.i(TAG, "onSuccess");
app.setPublicIconPath(taskSnapshot.getDownloadUrl().toString());
ref.child(app.getFirebaseKey()).child("icon").setValue(app.getFirebaseValueDataPart1().getIcon());
}
});

Categories

Resources