Glide BitmapTransformation is not called - android

I'm trying to rotate my image in Glide.
I've created BitmapTransformation as it's said in the documentation.
Problem is that overrided method transform is not called so image is not rotated at all. I'm using Glide 3.7.0
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Uri imageUri = this.imageUri;
Glide.with(getContext())
.load(imageUri)
.transform(new RotateTransformation(getContext(), 90))
.fitCenter()
.into(imageView);
}
public class RotateTransformation extends BitmapTransformation {
private float rotateRotationAngle = 0f;
public RotateTransformation(Context context, float rotateRotationAngle) {
super(context);
this.rotateRotationAngle = rotateRotationAngle;
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Matrix matrix = new Matrix();
matrix.postRotate(rotateRotationAngle);
return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true);
}
#Override
public String getId() {
return "rotate" + rotateRotationAngle;
}
}

update
Glide.with(getContext())
.load(imageUri)
.transform(new RotateTransformation(getContext(), 90))
.fitCenter()
.into(imageView);
to
Glide.with(getContext())
.load(imageUri)
.fitCenter()
.transform(new RotateTransformation(getContext(), 90))
.into(imageView);

Related

Crash OutOfMemory Canvas: trying to use a recycled bitmap when using Glide 4 to show image with transition crossFade

I am using GlideApp for loading images in a slide images, this problem is when I load a lot of images, transition is changed continuity and it gives to me one crash Canvas: trying to use a recycled bitmap android.graphics.Bitmap#71167b3
I try to find a way to fix it but hopeless.
I believe that crash occur because of placeholder(imageView.getDrawable())
and AS my expected is transition cross from old image to new image so I have to use placeholder(imageView.getDrawable())
Could you guys have anyway to fix them? Thanks so much!
public void loadImageWithFade(final ImageView imageView, final String url) {
if (imageView == null) {
return;
}
GlideApp.with(imageView.getContext())
.load(url)
.transition(new DrawableTransitionOptions().crossFade(FADE_DURATION_MS))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(imageView.getDrawable())
.into(imageView);
}
For change image old one to new one smoothly, use withCrossFade
DrawableCrossFadeFactory factory =
new DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build();
GlideApp.with(context)
.load(url)
.transition(withCrossFade(factory))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(R.color.placeholder)
.into(imageView);
After time to looking for. I found one solution and it's working to me
public static final int FULLY_VISIBLE = 1;
private static final int FADE_DURATION_MS = 500;
public static final float ALMOST_TRANSPARENT = 0.2f;
private static Handler handler = new Handler();
private static Runnable runnable;
public static void loadImageWithFade(final ImageView imageView, final String url) {
if (imageView == null) {
return;
}
// Using new feature and upgrade glide to 4
GlideApp.with(imageView.getContext())
.asBitmap()
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.placeholder(imageView.getDrawable())
.into(new CustomTarget<Bitmap>() {
#Override
public void onResourceReady(#NonNull Bitmap resource, #Nullable Transition<? super Bitmap> transition) {
if (!resource.isRecycled()) {
animateView(imageView, FULLY_VISIBLE, ALMOST_TRANSPARENT);
if (runnable != null) {
handler.removeCallbacks(runnable);
}
runnable = () -> {
imageView.setImageBitmap(resource);
animateView(imageView, ALMOST_TRANSPARENT, FULLY_VISIBLE);
};
handler.postDelayed(runnable, FADE_DURATION_MS);
}
}
#Override
public void onLoadCleared(#Nullable Drawable placeholder) {
}
});
}
private static void animateView(ImageView imageView, float fromAlpha, float toAlpha) {
Animation animation = new AlphaAnimation(fromAlpha, toAlpha);
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(FADE_DURATION_MS);
imageView.startAnimation(animation);
}

Glide loader is not loading image properly

I am using Glide loader to load my images. My code is working but it changes images continuously. Here is my code:
Glide.with(ctx).load(image).asBitmap()
.dontTransform()
.placeholder(R.drawable.cart)
.into(new SimpleTarget < Bitmap > () {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
photoImageView.setImageBitmap(resource);
Glide.with(ctx).load(image).into(post_image);
post_image.setImageBitmap(resource);
}
Hey You can use glide utill class for better understanding
public class GlideUtil {
public static void loadImage(String url, ImageView imageView) {
Context context = imageView.getContext();
if(context!=null || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)) {
assert context != null;
ColorDrawable cd = new ColorDrawable(ContextCompat.getColor(context, R.color.blue_grey_500));
Glide.with(context)
.load(url)
.placeholder(cd)
.crossFade()
.centerCrop()
.into(imageView);
}
}
public static void loadProfileIcon(String url, ImageView imageView) {
Context context = imageView.getContext();
if(context!=null || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)) {
Glide.with(context)
.load(url)
.placeholder(R.drawable.ic_person_outline_black)
.dontAnimate()
.fitCenter()
.into(imageView);
}
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public static void loadImage(String url, ImageView mPhotoView, final ProgressBar mProgress) {
Context context = mPhotoView.getContext();
if(context!=null || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)) {
assert context != null;
ColorDrawable cd = new ColorDrawable(ContextCompat.getColor(context, R.color.blue_grey_500));
mProgress.setEnabled(true);
Glide.with(context)
.load(url)
.listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
mProgress.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
mProgress.setVisibility(View.GONE);
return false;
}
})
.placeholder(cd)
.crossFade()
.centerCrop()
.into(mPhotoView);
}
}
}
Image changing occurs because of lazy loading of images in the glide. When the glide is downloading the new image previous image will be already loaded since you are reusing the view. To prevent this,.Before loading images clear the previous image before loading image.
Glide.clear(post_image);
EDIT:
Also before fetching the image from glide clear the old image of the imageView.
post_image.setImageDrawable(null);
Then load the new image from glide
Glide.with(ctx)
.load(image)
.asBitmap()
.dontTransform()
.placeholder(R.drawable.cart)
.into(new SimpleTarget<Bitmap>() {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
post_image.setImageBitmap(resource);
}
}

Fading animation not working when an image is loaded with .asBitmap()

I have this code
Glide
.with(this)
.load(mUrl)
.asBitmap()
.thumbnail(Glide
.with(this)
.load(mPreviewUrl)
.asBitmap()
.animate(R.anim.fade_in))
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
mProgressBar.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
mProgressBar.setVisibility(View.GONE);
return false;
}
})
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
mWallpaperImageView.setImageBitmap(resource);
createPaletteAsync(resource);
}
});
This downloads an image and returns a Bitmap object, which then I use to generate a palette of colour with the Palette library. I also want to load the bitmap in an ImageView, and I do that with mWallpaperImageView.setImageBitmap(resource) which loads the image without any fading or animation to smooth out the loading.
If I use glide like this:
Glide.with(this)
.load(mUrl)
.crossFade(500)
.into(mImageView)
then the image appears with fading but then I don't have a Bitmap object.
According to this answer,
Unfortunately, there isn't a built in way to cross fade Bitmaps. You
can however, use a custom BitmapImageViewTarget, and use a
TransitionDrawable in onResourceReady() to cross fade.
Fortunately, there's a trick to enable fading effect with bitmap in Glide.
For this you will need two classes,
FadingDrawable
final public class FadingDrawable extends BitmapDrawable {
// Only accessed from main thread.
private static final float FADE_DURATION = 200; //ms
private final float density;
Drawable placeholder;
long startTimeMillis;
boolean animating;
int alpha = 0xFF;
FadingDrawable(Context context, Bitmap bitmap, Drawable placeholder) {
super(context.getResources(), bitmap);
this.density = context.getResources().getDisplayMetrics().density;
this.placeholder = placeholder;
animating = true;
startTimeMillis = SystemClock.uptimeMillis();
}
/**
* Create or update the drawable on the target {#link android.widget.ImageView} to display the supplied bitmap
* image.
*/
static public void setBitmap(ImageView target, Context context, Bitmap bitmap) {
if (bitmap != null && !bitmap.isRecycled()) {
Drawable placeholder = target.getDrawable();
if (placeholder instanceof AnimationDrawable) {
((AnimationDrawable) placeholder).stop();
}
FadingDrawable drawable = new FadingDrawable(context, bitmap, placeholder);
//this will avoid OverDraw
//target.setBackgroundDrawable(null);
//target.setBackgroundColor(0);
target.setImageDrawable(drawable);
}
}
/**
* Create or update the drawable on the target {#link android.widget.ImageView} to display the supplied
* placeholder image.
*/
static void setPlaceholder(ImageView target, Drawable placeholderDrawable) {
target.setImageDrawable(placeholderDrawable);
if (target.getDrawable() instanceof AnimationDrawable) {
((AnimationDrawable) target.getDrawable()).start();
}
}
#Override
public void draw(Canvas canvas) {
if (!animating) {
super.draw(canvas);
} else {
float normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION;
if (normalized >= 1f) {
animating = false;
placeholder = null;
super.draw(canvas);
} else {
if (placeholder != null) {
placeholder.draw(canvas);
}
int partialAlpha = (int) (alpha * normalized);
super.setAlpha(partialAlpha);
super.draw(canvas);
super.setAlpha(alpha);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
invalidateSelf();
}
}
}
}
#Override
public void setAlpha(int alpha) {
this.alpha = alpha;
if (placeholder != null) {
placeholder.setAlpha(alpha);
}
super.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
if (placeholder != null) {
placeholder.setColorFilter(cf);
}
super.setColorFilter(cf);
}
#Override
protected void onBoundsChange(Rect bounds) {
if (placeholder != null) {
placeholder.setBounds(bounds);
}
super.onBoundsChange(bounds);
}
}
and GlideImageView
public class GlideImageView extends AppCompatImageView {
public GlideImageView(Context context) {
this(context, null);
}
public GlideImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GlideImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Drawable placeholder = getDrawable();
if (placeholder instanceof AnimationDrawable) {
((AnimationDrawable) placeholder).stop();
Glide.clear(this);
}
}
#Override
public void setImageBitmap(Bitmap bitmap) {
if (bitmap != null) FadingDrawable.setBitmap(this, getContext(), bitmap);
}
public void setImageBitmapWithoutAnimation(Bitmap bitmap) {
super.setImageBitmap(bitmap);
}
}
Now change your mWallpaperImageView from ImageView to
<com.yourpackage.GlideImageView
android:id="#+id/mWallpaperImageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
And finally remove all external animation effect from Glide configuration,
Glide
.with(this)
.load(mUrl)
.asBitmap()
.thumbnail(Glide
.with(this)
.load(mPreviewUrl)
.asBitmap()
.listener(new RequestListener<String, Bitmap>() {
#Override
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
mProgressBar.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
mProgressBar.setVisibility(View.GONE);
return false;
}
})
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
#Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {
mWallpaperImageView.setImageBitmap(resource);
createPaletteAsync(resource);
}
});
Tested and working properly!
You can use the value of the alpha of an image to create a fade in or fade out effect:
In Java
yourimage.animate().setAlpha(0f).setDuration(2000);
given that the image's alpha starts with alpha =1 (not transparent).
so the image will disappear (transparent) during 2 seconds

How to rotate image using glide library? (Like in picasso)

I am trying to rotate the image using glide library. Previously, was able to do with Picasso (due to an issue, I moved to glide). Now I am missing rotate functionality in glide. I tried using transformations but didn't work.
// Code used
public class MyTransformation extends BitmapTransformation {
private float rotate = 0f;
public MyTransformation(Context context, float rotate) {
super(context);
this.rotate = rotate;
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform,
int outWidth, int outHeight) {
return rotateBitmap(toTransform, rotate);
}
#Override
public String getId() {
return "com.example.helpers.MyTransformation";
}
public static Bitmap rotateBitmap(Bitmap source, float angle)
{
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
}
// glide
Glide.with(context)
.load(link)
.asBitmap()
.transform(new MyTransformation(context, 90))
.into(imageView);
Thanks in advance.
Maybe you found a solution already by yourself, if not, maybe this could help you. I use this snippet for rotate images which I get from the camera.
public MyTransformation(Context context, int orientation) {
super(context);
mOrientation = orientation;
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
int exifOrientationDegrees = getExifOrientationDegrees(mOrientation);
return TransformationUtils.rotateImageExif(toTransform, pool, exifOrientationDegrees);
}
private int getExifOrientationDegrees(int orientation) {
int exifInt;
switch (orientation) {
case 90:
exifInt = ExifInterface.ORIENTATION_ROTATE_90;
break;
// other cases
default:
exifInt = ExifInterface.ORIENTATION_NORMAL;
break;
}
return exifInt;
}
and how to use it:
Glide.with(mContext)
.load(//your url)
.asBitmap()
.centerCrop()
.transform(new MyTransformation(mContext, 90))
.diskCacheStrategy(DiskCacheStrategy.RESULT)
.into(//your view);
for more cases or exif int values, check the public constants in android.media.ExifInterface
One way I found was this.
Glide.with(mCtx)
.load(uploadImage.getImageUrl())
.into(holder.imageView);
holder.imageView.setRotation(uploadImage.getmRotation());
I hope you understand.
Just take the file that you put inside the .into(x) method
and then write x.setRotaion()

Android Glide library not working with shared element transitions

I'm looking to adopt the Glide library in place of Universal Image Loader but I'm running into a problem with regards to shared element transitions.
In my simple Sandbox I've created the following transition using UIL: https://dl.dropboxusercontent.com/u/97787025/device-2015-06-18-113333.mp4
Pretty simple, and it works fine. But when I used Glide, it doesn't look so nice: https://dl.dropboxusercontent.com/u/97787025/device-2015-06-18-114508.mp4
Here is the code I'm using
The first activity:
public class MainActivity extends BaseActivity {
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
final ImageView iv = (ImageView) findViewById(R.id.main_image);
displayImageGlide(BaseActivity.IMAGE_URL, iv, true);
Button button = (Button) findViewById(R.id.main_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), DifferentActivity.class);
startActivity(intent, iv);
}
});
}
}
And the second:
public class DifferentActivity extends BaseActivity {
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.different);
ImageView imageView = (ImageView) findViewById(R.id.diff_image);
displayImageGlide(BaseActivity.IMAGE_URL, imageView, false);
}
}
BaseActivity just contains displayImageGlide
public void displayImageGlide(String url, ImageView imageView) {
Glide.with(this).load(url)
.asBitmap().transform(new CustomTransformation(this))
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}
private static class CustomTransformation extends BitmapTransformation {
public CustomTransformation(Context context) {
super(context);
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return bitmapChanger(toTransform, outWidth, outHeight);
}
#Override
public String getId() {
return "some_id_1";
}
}
private static Bitmap bitmapChanger(Bitmap bitmap, int desiredWidth, int desiredHeight) {
float originalWidth = bitmap.getWidth();
float originalHeight = bitmap.getHeight();
float scaleX = desiredWidth / originalWidth;
float scaleY = desiredHeight / originalHeight;
//Use the larger of the two scales to maintain aspect ratio
float scale = Math.max(scaleX, scaleY);
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
//If the scaleY is greater, we need to center the image
if(scaleX < scaleY) {
float tx = (scale * originalWidth - desiredWidth) / 2f;
matrix.postTranslate(-tx, 0f);
}
Bitmap result = Bitmap.createBitmap(desiredWidth, desiredHeight, bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
canvas.drawBitmap(bitmap, matrix, new Paint());
return result;
}
I've tried removing the cache lines from the Glide builder (used to prevent it from caching what I'm trying to tweak) but that didn't help. Would love to adopt Glide, but it's kind of a deal breaker if this won't work. If anyone has some input I'd appreciate it, thanks!
I tried your code and got the same result, then I tried another implementation following this: https://github.com/codepath/android_guides/wiki/Shared-Element-Activity-Transition
And made some changes, which I think are the key here:
The centerCrop should be set on the ImageView, if we set it with Glide it causes the same bug.
activity_main.xml
<ImageView
android:id="#+id/ImageView"
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_centerInParent="true"
android:transitionName="detail_image"
android:scaleType="centerCrop"
/>
BaseActivity.java
On the MainActivity dontTransform should be true and on DifferentActivity false.
public void displayImageGlide(String url, ImageView imageView, Boolean dontTransform) {
if (dontTransform) {
Glide.with(this).load(url)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.dontTransform()
.into(imageView);
return;
}
Glide.with(this).load(url)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}
Edit, see how it looks: https://www.dropbox.com/s/30s5l8awxogltls/device-2015-06-23-153153.mp4?dl=0
For those of you that are struggling with the SharedElementTransition using Glide I think I got a workaround that works, or at least it worked for me. In your second activity or fragment use this code:
postponeEnterTransition();
GlideApp.with(this)
.load(imageToLoad)
.listener(new RequestListener<Drawable>() {
#Override
public boolean onLoadFailed(#Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
return false;
}
#Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
startPostponedEnterTransition();
return false;
}
})
.into(imageView);
If you are targeting API<21 use:
supportPostponeEnterTransition();
supportStartPostponedEnterTransition();
Hope that helps!

Categories

Resources