Converting image url to bitmap quickly
Asked Answered
F

3

5

I need to display the list of images from api in the list page. For that i used two approaches.

First Approach:
By converting the url to byte array and then converting it into bitmap.Please find the below code..

URL imageUrl = new URL(url);
URLConnection ucon = imageUrl.openConnection();

InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);

ByteArrayBuffer baf = new ByteArrayBuffer(500);
int current = 0;
while ((current = bis.read()) != -1) {
     /* This approach slowdown the process*/
     baf.append((byte) current);
}

byte[] img_ary= baf.toByteArray();

Converting byte array to bitmap:

ByteArrayInputStream imageStream = new ByteArrayInputStream(
                    imgUrl);
Bitmap theImage = BitmapFactory.decodeStream(imageStream);

Second Approach:
Image scaling based on height and width

private static final String TAG_iamge = "Image";
private static final int IO_BUFFER_SIZE = 4 * 1024;

public static Bitmap loadBitmap(String url) {
    Bitmap bitmap = null;
    InputStream in = null;
    BufferedOutputStream out = null;

    try {
        in = new BufferedInputStream(new URL(url).openStream(),
                IO_BUFFER_SIZE);

        final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
        out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
        copy(in, out);
        out.flush();

        final byte[] data = dataStream.toByteArray();
        BitmapFactory.Options options = new BitmapFactory.Options();

        options.inJustDecodeBounds = true;
        options.inDither = false;
        options.inPurgeable = true;
        options.inInputShareable = true;

        bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,
                options);

        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        int reqHeight = 500;
        int reqWidth = 500;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2
            // and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        int scale = inSampleSize;

        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        o2.inDither = false;
        o2.inPurgeable = true;
        o2.inInputShareable = true;
        return BitmapFactory.decodeByteArray(data, 0, data.length, o2);
    } catch (Exception e) {
        Log.e(TAG_iamge, "Could not load Bitmap from: " + url);
    } finally {
        closeStream(in);
        closeStream(out);
    }

    return bitmap;
}

private static void copy(InputStream in, OutputStream out)
        throws IOException {
    byte[] b = new byte[IO_BUFFER_SIZE];
    int read;
    while ((read = in.read(b)) != -1) {
        out.write(b, 0, read);
    }
}

private static void closeStream(Closeable stream) {
    if (stream != null) {
        try {
            stream.close();
        } catch (IOException e) {
            android.util.Log.e("", "Could not close stream", e);
        }
    }
}

Both approaches making the APP very slow. So here is my questions..

  1. How can i quickly convert the url into bitmap without making the app slow?

  2. How the other apps(like flipcart) displaying the 1000>s of images, without any slow or hang?

    Please guide to get the answer.

Fry answered 15/5, 2015 at 9:32 Comment(5)
You forgot to describe what you do in the second aproach. Why?Libertine
converting the url to byte array. ?? One does not do such things. Please describe better what happens instead.Libertine
and then converting it into bitmap. You are not doing that in the first aproach.Libertine
They use layloading. For that you can use third party library.Tosh
please review my edited codeFry
F
9

There is a library named Picasso. which can efficiently load images from url. it can also load image from the File. all you wanted to do , write a line of code.

example

Picasso.with(context) //Context
    .load("http://i.imgur.com/DvpvklR.png") //URL/FILE
    .into(imageView)//an ImageView Object to show the loaded image; 

It can also cache your image, so the loaded image could be able to load faster on the next time without wasting the data.

There are many more options available in Picasso. Here is the documentation

If you need rounded cornered bitmap

Picasso.with(mContext)
    .load("your-image-url-or-file-or-drawable")
    .transform(new RoundedTransformation(200, 0))
    .fit()
    .into(imageView);

RoundedTransformation.java

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;

// enables hardware accelerated rounded corners
// original idea here : http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
public class RoundedTransformation implements com.squareup.picasso.Transformation {
    private final int radius;
    private final int margin;  // dp

    // radius is corner radii in dp
    // margin is the board in dp
    public RoundedTransformation(final int radius, final int margin) {
        this.radius = radius;
        this.margin = margin;
    }

    @Override
    public Bitmap transform(final Bitmap source) {
        final Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        Bitmap output = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Config.ARGB_8888);
        Canvas canvas = new Canvas(output);
        canvas.drawRoundRect(new RectF(margin, margin, source.getWidth() - margin, source.getHeight() - margin), radius, radius, paint);

        if (source != output) {
            source.recycle();
        }

        return output;
    }

    @Override
    public String key() {
        return "rounded";
    }
}
Foregone answered 15/5, 2015 at 9:36 Comment(7)
Hi, here i need one more clarification.. I want to display the image as rounded image. Initially i converted the url into bitmap and then converted that bitmap into rounded bitmap.. How can i accomplish this task using this library?Fry
This can be easily done with Picasso. wait a second, i'll get you the code.Foregone
Hi i am going to implement this library in my app. Is this library is more advance compared with universal-image-loader?. Is this a best approach? Because i am going to give the baseline for our project.. If it is okay, I will move on it.. Kindly guide me.Fry
Everything has their own specialties, Check this answers #29363821 , #19995507 . I never used any imageHelper library other than Picasso, so i can't tell about them. Picasso always suits to me.Foregone
Finally i am going to picasso for my project. Thank you for your support and your great time.Fry
It's ok. and happy coding.Foregone
Thank you for providing the documentation link. Truly useful and it worked for me! Saved my dayStriation
C
1

There are open-source libraries which focus on loading image into an ImageView. Take for example of universal-image-loader, it is very easy to use, like:

// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view 
//  which implements ImageAware interface)
imageLoader.displayImage(imageUri, imageView);

or:

// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        // Do whatever you want with Bitmap
    }
});

or:

// Load image, decode it to Bitmap and return Bitmap synchronously
Bitmap bmp = imageLoader.loadImageSync(imageUri);

Take example of Volley, you can use it like this:

public void displayImg(View view){
    ImageView imageView = (ImageView)this.findViewById(R.id.image_view);
    RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext()); 

    ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());

    ImageListener listener = ImageLoader.getImageListener(imageView,R.drawable.default_image, R.drawable.default_image);
    imageLoader.get("http://developer.android.com/images/home/aw_dac.png", listener);
    //指定图片允许的最大宽度和高度
    //imageLoader.get("http://developer.android.com/images/home/aw_dac.png",listener, 200, 200);
}

These libraries are used broadly, and more importantly, they are open-sourced. No need to implement functions like this repeatedly.

Cappello answered 15/5, 2015 at 9:51 Comment(0)
G
1

Try this

Hope this should help you.
Gerber answered 16/5, 2015 at 7:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.