How to load image from aws with picasso with private access - android

I'm trying to load image stored on aws S3 into my android app using Picasso but I am getting a blank image with no errors in my logcat and nothing to me from general debugging around the relevant lines of code.
We are having private access on images so image url can't work on browser.
i need to display image into my android app using Picasso. but it doesn't work.
My code snippet below
new Picasso.Builder(getApplicationContext()).downloader(new S3Downloader(getApplicationContext(), s3Client, bucket))
.build()
.load("https://s3-ea-east-8.amazonaws.com/music/MusicApp_3.jpg")
.placeholder(R.drawable.img_placeholder)
.memoryPolicy(MemoryPolicy.NO_CACHE)
.networkPolicy(NetworkPolicy.NO_CACHE)
.into(imageView);
By using above code image is displaying only very first time after installing app. next time its only showing placeholder image
I am using this library for displaying image.
The problem isn't with Picasso, it's with loading an image from a "private" url.
please suggest solutions

You need to generate a presigned Url from S3 client and you can pass that url to picasso.
That url will be public and will have an expriy date.

You can use the below set of code , which is a aynctask which will use glide to attach private images from s3 by generating presignedurl.
public class sets3imageasync extends AsyncTask<Object, Void, String> {
// The list of objects we find in the S3 bucket
static final String s3bucket=bucket_name;
Context scontext;
ImageView image;
#Override
protected String doInBackground(Object... objects) {
// Queries files in the bucket from S3.
Calendar cal = Calendar.getInstance();
Log.d(TAG, "doInBackground: in progress");
cal.setTime(new Date());
cal.add(Calendar.HOUR, +1);
Date oneHourLater = cal.getTime();
AmazonS3Client s3 = (AmazonS3Client) objects[0];
scontext= (Context) objects[1];
image=(ImageView) objects[2];
String imagekey=(String) objects[3];
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(s3bucket, imagekey)
.withMethod(HttpMethod.GET)
.withExpiration(oneHourLater);
URL url = s3.generatePresignedUrl(generatePresignedUrlRequest);
Log.e("url was", url.toString());
return url.toString();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Log.d(TAG, "onPostExecute: completed "+s);
Glide.with(scontext).load(s)
.apply(new RequestOptions()
.centerCrop())
.placeholder(scontext.getResources().getDrawable(R.drawable.progress_animation))
.into((image));
}
this can be called as below
new sets3imageasync().execute(s3Client,context,Image_view);

Simply use this:
Picasso.with(getApplicationContext()).load(your_url).noFade().into(imageView);

write below code to load image in Picasso.
variables:-
String file_path -->> this is your image file path
Imageview mViewHolder.img_post_photo -->> this is your imageview to load image.
Picasso.with(context)
.load(file_path)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.into(mViewHolder.img_post_photo, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
Picasso.with(context)
.load(file_path)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.into(mViewHolder.img_post_photo);
}
});
Set dependencies in your app build.gradle file:-
compile 'com.squareup.picasso:picasso:2.5.2'
hope this code helps you.

Related

Retrofit 2: Async download many images and store in Android folder

I need to download 20 images from remote server and store in Android folder.
Here my code:
Interface:
#GET
Call<ResponseBody> downloadFile(#Url String url);
In fragment:
private void downloadImagesList(List<Image> imagesList) {
for (Image image : imagesList) {
final String imageSourceUrl = imageSource.getUrl();
Call<ResponseBody> call = RestClientFactory.getRestClient().downloadFile(imageSourceUrl);
call.enqueue(new DefaultRestClientCallback<ResponseBody>() {
#Override
public void onSuccess(Response<ResponseBody> response) {
Toast.makeText(context, "Success download from url: " + imageSourceUrl, Toast.LENGTH_LONG).show();
// code to write downloaded image to Android's local folder
}
});
}
}
As you can see I iterate loop and call call.enqueue() for every image.
Is it good solution? Is this can perform my android app?
You can use dependencies like Glide , Pissaco etc for downloading images from remote server. Because these provide better caching and error handling. Have a look at the code below. It is using Pissaco to load the image
First add the Pissaco dependency in your build.gradle
compile 'com.squareup.picasso:picasso:2.5.2'
Picasso.with(context)
.load(url)
.resize(50, 50)
.centerCrop()
.into(imageView)

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

Generate pre-signed url of private Image and load to a image view - S3 Client android

I am trying to load image from my S3 Bucket in my android application. My images are private so I won't be having any specific link for each image.
I'm using link generator,
s3Client.generatePresignedUrl(Constants.S3_BUCKET_NAME, key, expiration);
It generates a URL with let's say 1 hour or 2 min expiration.
Now I have problem in loading the url. I tried loading it by using picasso ,
Picasso.with(context).load(url.toString()).resize(30,38).into(holder.photo);
but it's not quite seems to be working. When I tried that link on browser I got following error
<Code>NoSuchKey</Code>
<Message>The specified key does not exist.</Message>
Try to attach error listener to Picasso and see what's going on. Also read logcat. Print URL which you pass to Picasso, does it correct?
Picasso.Builder builder = new Picasso.Builder(getApplicationContext());
builder.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso arg0, String err) {
Log.e("Picasso Error", "Errored " + err);
}
});
builder.loggingEnabled(true);
Picasso pic = builder.build();
pic.load("image.jpg").into(iv);

AQuery: How to download images in non-sequential manner without any reference to imageView in the aQuery call

Question 1: Is it possible to download image file without giving the reference to ImageView?
Question 2: Can i download each file in a separage instance of aQuery or do i have to download the file sequentially? e.g, waiting for the callback of current file download and then trigger the next file download call? Below is my code
// Ad is my custom model class
// adList is my list of Ads having URL's to the ads hosted somewhere
// imageView is an invisible imageView as downloading does not start if i don't give any reference to any imageView resource
for (String adUrl : adList) {
if (adUrl.length() > 0) {
AQuery aQuery = new AQuery(DownloadAdActivity.this);
BitmapAjaxCallback callback = new BitmapAjaxCallback();
callBack.url(adUrl);
callBack.fallback(R.id.placeHolderResource);
callBack.fileCache(true);
callBack.memCache(true);
aQuery.id(imageView).image(callBack);
}
}
I need to download 20/30 images when the app starts first time, so far i am doing it by giving a hidden imageView reference and trigging the aQuery sequentially after each image has downloaded. I tried to generate 20/30 request in a loop but only the last aQuery trigger call works which cancels the previous image download call.
Please guide me:
1- How to cache images without giving any reference to the imageView
2- How to download images in parallel manner, not in sequential manner through AQuery.
1) You can use ajax call without ImageView reference to download image.
androidQuery.ajax("url", Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
}
});
2) By default you can download 4 images concurrently. But you can change as per your requirement like this
AjaxCallback.setNetworkLimit(8);
You can use Picasso
It will make all the downloads and also the caching for the images.
Anyway if the images are quite small you should prepare a "zip" file and dl all of them with an AsyncTask / Thread and unzip them. Opening and closing the connections to the server are "very expensive" operations in time consuming.
Here is method to obtain bitmap from url using AQuery
static Bitmap myBitmap = null;
public static Bitmap getBitmapFromURL(String src) {
try {
Log.i(TAG, "Image Url is : " + src);
AQuery androidQuery = new AQuery(ChatApplication.getInstance());
androidQuery.ajax(src, Bitmap.class, 0, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bitmap, AjaxStatus status) {
super.callback(url, bitmap, status);
if (bitmap != null)
myBitmap = bitmap;
}
});
} catch (Exception e) {
Log.i(TAG, "Error due to " + e);
}
return myBitmap;
}
AQuery aq = new AQuery(context);
aq.ajax(url_of_image, Bitmap.class, new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap object, AjaxStatus status) {
}
});
Im sorry for replying late,But this is best library I have ever came across.
Yes,You can download. Bitmap object will give you the image.
You can create multiple instances of Aquery if you want to download or pass the each URL after one download finishes,you can use any loop for that.

is it possible to download images from cache memory in picasso?

I was using UniversalImageDownloader for my app.in UIL we can save images from cache memory.
File cachedImage = ImageLoader.getInstance().getDiscCache().get(imageUrl);
if (cachedImage.exists())
{// code for save 2 sd
}
Is it possible in picasso?
There is a private Method in Picasso -
Bitmap quickMemoryCacheCheck(String key) {
Bitmap cached = cache.get(key);
if (cached != null) {
stats.dispatchCacheHit();
} else {
stats.dispatchCacheMiss();
}
return cached;
}
Modify the source according to your need.
You can do like this , Use OkHttp & Picasso:
public class APP extends Application{
public static OkHttpDownloader okHttpDownloader;
#Override
public void onCreate() {
super.onCreate();
Picasso.Builder b = new Picasso.Builder(this);
okHttpDownloader = new OkHttpDownloader(this);
b.downloader(okHttpDownloader);
Picasso.setSingletonInstance(b.build());
}
}
Then get the File from OkHttp local cache:
Downloader.Response res = APP.okHttpDownloader.load(Uri.parse(your image Url),0);
Log.i(TAG,"Get From DISK: " + res.isCached() );
storeImageFile(res.getInputStream());
You can get bitmap from ImangeView onSuccess() callback
Picasso.with(context).load(path).into(imageView, new Callback(){
public void onSuccess() {
Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
//save bitmap to sdcard
}
public void onError() {}
}
WARNING: Saved bitmap may be different to original bitmap.
Below code snippet will first make Picasso load image from cache, if failed then download and display image in imageView
You can debug memory performance with
Picasso.with(appContext).setIndicatorsEnabled(true);
green (memory, best performance)
blue (disk, good performance)
red (network, worst performance).
//Debugging memory performance https://futurestud.io/tutorials/picasso-cache-indicators-logging-stats
//TODO remove on deployment
Picasso.with(appContext).setIndicatorsEnabled(true);
//Try to load image from cache
Picasso.with(appContext)
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.ic_launcher)
.placeholder(R.drawable.ic_launcher)
.resize(100, 100)
.error(R.drawable.ic_drawer)
.into(markerImageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError() {
// Try online if cache failed
Picasso.with(appContext)
.load(imageUrl)
.placeholder(R.drawable.ic_launcher)
.resize(100, 100)
.error(R.drawable.ic_drawer)
.into(markerImageView);
}
});

Categories

Resources