Loading images from URL partially, just like what is implemented in WhatsApp
Asked Answered
S

4

8

WhatsApp developers recently improved the image loading in which immediately loading some portion of the image (getting its dimension and some pixels of the images) and then after loading the entire image, replace the placeholder with the full image:

enter image description here

My question is, how did they implement it? Do they read the dimension of the image by reading its header (meta-data)? How about the image content? Or do they have two versions of the image at the server-side, a smaller one with low-quality which is loaded first and a bigger one which is the full image? Note that if it's the second approach then they still need to extract the smaller version of the image at the server side once receiving the image from the sender. Any other approaches?

Syllogize answered 9/11, 2013 at 19:28 Comment(2)
This may be worth a watch: youtube.com/watch?v=Yx1l9Y7GIk8&feature=share&t=22m45s they discuss this effect, and how it it may have been implemented.Licit
Have you figured out what they did?Tortoiseshell
S
1

After several experiments, I got the dimensions without downloading the entire image:

String address = "image_url";
URL url = new URL(address);
URLConnection urlC = url.openConnection();
urlC.connect();
InputStream is = urlC.getInputStream();
for(int i = 0; i < 92; i++) is.read();

nt byte1 = is.read();
int byte2 = is.read();

int width = (byte1 << 8) + byte2;

for(int i = 0; i < 10; i++) is.read();

byte1 = is.read();
byte2 = is.read();

int height = (byte1 << 8) + byte2;

System.out.println("width = " + width + " | height = " + height);

is.close();
Syllogize answered 22/11, 2013 at 11:26 Comment(0)
C
2

There is another alternative to the colored placeholder solution, which is to show a thumbnail image (may be only a 100 X 100 px) as the placeholder until loading the real image, which is away more cooler than having only a colored placeholder :) .

I did it in Zingoo and made a blog post about it. Using Picasso, you can do it like this:

Transformation blurTransformation = new Transformation() {
    @Override
    public Bitmap transform(Bitmap source) {
        Bitmap blurred = Blur.fastblur(LiveImageView.this.context, source, 10);
        source.recycle();
        return blurred;
    }

    @Override
    public String key() {
        return "blur()";
    }
};

Picasso.with(context)
    .load(thumbUrl) // thumbnail url goes here
    .placeholder(R.drawable.placeholder)
    .resize(imageViewWidth, imageViewHeight)
    .transform(blurTransformation)
    .into(imageView, new Callback() {
        @Override
        public void onSuccess() {
            Picasso.with(context)
                    .load(url) // image url goes here
                    .resize(imageViewWidth, imageViewHeight)
                    .placeholder(imageView.getDrawable())
                    .into(imageView);
        }

        @Override
        public void onError() {
        }
    });

more details in the post itself including the Blur class.

Cantwell answered 15/2, 2015 at 13:14 Comment(2)
Hi AbdelHady i tried to use your method. But it gives me error in the following code Bitmap blurred = Blur.fastblur(LiveImageView.this.context, source, 10); It seems that the class "Blur" and "fastblur" should be your own codes, great if you would clarify whether we would find "Blur" or "fastblur" in picassoMersey
Oh, my bad :), I totally forgot about it. Anyway, I updated my blog post with this class which you can find also here github.com/MichaelEvans/EtsyBlurExample/blob/master/app/src/…Cantwell
T
2

Yet another up-to-date answer for an older post. You could try the progressive JPEG streaming feature of the Fresco library to achieve that effect.

Basically all you'd need to do is calling .setProgressiveRenderingEnabled(true) while creating an ImageRequest. I have included a complete example for Fresco's progressive JPEG streaming into my demo application mentioned in this answer, you might want to try it out to see how it works.

For the lazy ones: when working with Fresco, create a DraweeController as following:

 ImageRequest imgReq = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                    .setProgressiveRenderingEnabled(true)
                    .build();
 DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setImageRequest(imgReq)
                    .setOldController(yourDrawee.getController())
                    .build();
 yourDrawee.setController(controller);

Note: this approach has some restrictions as explained in the docs.

Thyroiditis answered 26/6, 2016 at 14:25 Comment(0)
S
1

After several experiments, I got the dimensions without downloading the entire image:

String address = "image_url";
URL url = new URL(address);
URLConnection urlC = url.openConnection();
urlC.connect();
InputStream is = urlC.getInputStream();
for(int i = 0; i < 92; i++) is.read();

nt byte1 = is.read();
int byte2 = is.read();

int width = (byte1 << 8) + byte2;

for(int i = 0; i < 10; i++) is.read();

byte1 = is.read();
byte2 = is.read();

int height = (byte1 << 8) + byte2;

System.out.println("width = " + width + " | height = " + height);

is.close();
Syllogize answered 22/11, 2013 at 11:26 Comment(0)
W
0

Using Glide lib:

Glide.with(context)
  .load(url)
  .diskCacheStrategy(DiskCacheStrategy.ALL)
  .into(imageView);
Workmanlike answered 15/10, 2018 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.