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; }
4 Answers
Answers 1
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
Answers 2
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 }
Answers 3
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 } });
Answers 4
This is what I would do.
As you are using glide, place your loaded image to an Image view.
From code, set:
imageView = (ImageView) view.findViewById(R.id.image_view); imageViewProfile.setDrawingCacheEnabled(true); imageViewProfile.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
then to get the bitmap from that image view you can use
imageView.getDrawingCache() //This returns a Bitmap
The only thing you should worry about is to verify if Glide finished loading your image or not -I am not sure how to accomplish this-, but give a try and give a vote if this works for you.
0 comments:
Post a Comment