Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Glide Image extraction

I am using glide to extract a bitmap from the cache and save it elsewhere. The relevant function below (based on this post:) fails to trigger the extraction. In fact, the log line 'Log.d(TAG, "About to start extraction");' below never gets triggered.

Any ideas on why the simple target function never gets called?

public byte[] extractImageFromCache(Context context, String pictureURL) {

    byte[] byteArray = new byte[0];
    if (context != null && pictureURL != null && !pictureURL.isEmpty()) {

        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        Glide.with(context)
            .load(pictureURL)
            .asBitmap()
            .toBytes()
            .diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
            .into(new SimpleTarget<byte[]>() {
                @Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
                    Log.d(TAG, "About to start extraction");
                    new AsyncTask<Void, Void, Void>() {
                        @Override protected Void doInBackground(Void... params) {
                            Log.d(TAG, "Start extraction");
                            try {
                                Log.d(TAG, "Image bytes len: " + resource.length);
                                byteArrayOutputStream.write(resource);
                                byteArrayOutputStream.flush();
                            } catch (IOException e) {
                                e.printStackTrace();
                                Log.i(TAG, "Unable to load image: " + pictureURL);
                                e.printStackTrace();
                            }
                            return null;
                        }
                    }.execute();

                }
            });
        Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL));
        return byteArrayOutputStream.toByteArray();
    }
    return null;
}
like image 678
Lmwangi Avatar asked Jul 18 '17 14:07

Lmwangi


People also ask

What is Glide image?

Glide is an Image Loader Library for Android developed by bumptech and is a library that is recommended by Google. It has been used in many Google open source projects including Google I/O 2014 official application. It provides animated GIF support and handles image loading/caching.

How do you download pictures from Glide?

To simply load an image to LinearLayout, we call the with() method of Glide class and pass the context, then we call the load() method, which contains the URL of the image to be downloaded and finally we call the into() method to display the downloaded image on our ImageView.

Where does glide save images?

Google creates a separate link for each image which can be copied-and-pasted into your Glide app spreadsheet. The image picker is pretty basic. Images are stored in Firebase and limited to 10mb files.

How does glide work?

Glide knows the dimension of the imageView as it takes the imageView as a parameter. Glide down-samples the image without loading the whole image into the memory. This way, the bitmap takes less memory, and the out of memory error is solved.


3 Answers

As you have mentioned, Log.d(TAG, "About to start extraction") never gets triggered, which means onResourceReady never gets called. This could happen due to some error. Try overriding error callbacks.

To identify the problem I would recommend you to override other callbacks of SimpleTarget to debug the problem.

  @Override
  public void onLoadCleared(@Nullable Drawable placeholder) {
    // load has been cleared
  }

  @Override
  public void onLoadStarted(@Nullable Drawable placeholder) {
    // load has started
  }

  @Override
  public void onLoadFailed(@Nullable Drawable errorDrawable) {
    // load failed due to some reason, notify callers here about the same
  }
like image 181
abhishesh Avatar answered Oct 02 '22 21:10

abhishesh


By using SimpleTarget object we can easily get Bitmap we are trying to extract from cache or network since by default glide look for cache hit.

Modify your Glide loading code to this :

     Glide.with(this)
            .load("https://cdn-images-1.medium.com/max/1200/1*hcfIq_37pabmAOnw3rhvGA.png")
            .asBitmap()
            .diskCacheStrategy(DiskCacheStrategy.SOURCE)
            .into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                    Log.d("Size ", "width :"+resource.getWidth() + " height :"+resource.getHeight());
                    imageView.setImageBitmap(resource);
                    storeImage(resource);
                }
            });

And Using this or any other mechanism for storing bitmap to external/internal storage.

private void storeImage(Bitmap image) {
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null) {
            Log.d(TAG,
                    "Error creating media file, check storage permissions: ");// e.getMessage());
            return;
        }
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            image.compress(Bitmap.CompressFormat.PNG, 90, fos);
            fos.close();
            Log.d(TAG, "img dir: " + pictureFile);
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }


private  File getOutputMediaFile(){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.
    File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
            + "/Android/data/"
            + getApplicationContext().getPackageName()
            + "/Files");

    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            return null;
        }
    }

    File mediaFile;
    Random generator = new Random();
    int n = 1000;
    n = generator.nextInt(n);
    String mImageName = "Image-"+ n +".jpg";

    mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
    return mediaFile;
} 

I am using Glide ver 3.7

compile "com.github.bumptech.glide:glide:3.7.0"

Here is full working example : https://github.com/nieldeokar/GlideApp

like image 29
Nilesh Deokar Avatar answered Oct 02 '22 19:10

Nilesh Deokar


First of all, your return is invalid because Glide executes the request in an asynchronous thread. So byteArrayOutputStream is never populated in time before the function returns. This means your function will always return an empty byte array. This also means your log statement Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL)); will be invalid. Knowing this, your About to start extraction will show up after Got image bytes.... You will need to reformat your code to use callbacks to notify the caller of the function that your code has retrieved the array. Something like this:

public interface GlideByteLoadCallback {
    void onBytesExtracted(byte[] bytes);
    void onFail(String message);
}

public void extractImageFromCache(Context context, String pictureURL, GlideByteLoadCallback callback) {

    if (context != null && pictureURL != null && !pictureURL.isEmpty()) {

        final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        Glide.with(context)
            .load(pictureURL)
            .asBitmap()
            .toBytes()
            .diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
            .into(new SimpleTarget<byte[]>() {
                @Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
                    Log.d(TAG, "About to start extraction");
                    new AsyncTask<Void, Void, Void>() {
                        @Override protected Void doInBackground(Void... params) {
                            Log.d(TAG, "Start extraction");
                            try {
                                Log.d(TAG, "Image bytes len: " + resource.length);
                                byteArrayOutputStream.write(resource);

                                byteArrayOutputStream.flush();
                                if (callback != null) callback.onBytesExtracted(byteArrayOutputStream.toByteArray());
                            } catch (IOException e) {
                                e.printStackTrace();
                                Log.i(TAG, "Unable to load image: " + pictureURL);
                                e.printStackTrace();
                                if (callback != null) callback.onFail("Extraction failed");
                            }
                        }
                    }.execute();
                }
            });
    }
    if (callback != null) callback.onFail("Invalid url");
}

Then call it with:

extractImageFromCache(context, picture, new GlideByteLoadCallback() {
                @Override
                public void onFail(String message) {
                    // handle failure here
                }

                @Override
                public void onBytesExtracted(byte[] bytes) {
                    // do stuff with bytes here
                }
            });
like image 24
Felix Guo Avatar answered Oct 02 '22 21:10

Felix Guo