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()
Related
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);
}
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);
I am using MapCustomClustering to show images on the map. The Cluster Icon also shows the number of items in the cluster but it doesn't show in mine. I am loading data from Parse cloud. The example one renders cluster.getSize() but in mine it doesn't work.
#Override
protected void onBeforeClusterRendered(final Cluster<MapPosts> cluster, final MarkerOptions markerOptions) {
// Draw multiple people.
// Note: this method runs on the UI thread. Don't spend too much time in here (like in this example).
final List<Drawable> profilePhotos = new ArrayList<>(Math.min(4, cluster.getSize()));
final int width = mDimension;
final int height = mDimension;
int i = 0;
for (MapPosts p : cluster.getItems()) {
// Draw 4 at most.
i++;
Picasso.with(getApplicationContext())
.load(String.valueOf(p.profilePhoto))
.into(new Target() {
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
Drawable drawable = new BitmapDrawable(getResources(), bitmap);
drawable.setBounds(0, 0, width, height);
profilePhotos.add(drawable);
MultiDrawable multiDrawable = new MultiDrawable(profilePhotos);
multiDrawable.setBounds(0, 0, width, height);
mClusterImageView.setImageDrawable(multiDrawable);
Bitmap icon = mClusterIconGenerator.makeIcon(String.valueOf(cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
if (profilePhotos.size() == 4) break;
}
}
I found the answear :-) -> Make sure you have some TextView like this in your icon style! The IMPORTANT POINT is you name it "text" !!!
<TextView
**android:id="#id/text"**
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/holo_green_dark"
android:paddingLeft="#dimen/custom_profile_padding"
android:paddingRight="#dimen/custom_profile_padding"
android:layout_gravity="center"
android:alpha=".8"/>
I am using recycler view and in the recycler view I have networkImage. I am trying to load image from gallery as follows, but it does not load it, it still uses the default image. I have tested and validated url is valid. I wonder what I am missing. Initially, I have an image is loaded, and now I am trying to update it.
ItemData Class
public class ItemData {
private String url;
public ItemData(String url){
this.url = url;
}
String getUrl(){return url;}
void setUrl(String t){url = t;}
}
In the Activity
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1 && resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
Uri filePath = data.getData();
Update(getRealPathFromURI(filePath));
}
}
private void Update(String path)
{
// update the existing view
listImages.set(0, new ItemData(path));
mAdapter.notifyDataSetChanged();
}
Adapter
public void onBindViewHolder(ViewHolder viewHolder, int pos) {
int position = pos;
ImageUtil.setPic(viewHolder.imgViewIcon, itemsData.get(position).getUrl());
}
ImageUtil Class
public static void setPic(NetworkImageView imageView, String picturePath) {
// Get the dimensions of the View
int targetW = imageView.getWidth();
int targetH = imageView.getHeight();
if(targetW != 0 || targetH != 0)
{
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(picturePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW / targetW, photoH / targetH); // zero division olasiligi...
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
//bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(picturePath, bmOptions);
Matrix matrix = new Matrix();
matrix.postRotate(getImageOrientation(picturePath));
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
imageView.setImageBitmap(rotatedBitmap);
}
}
Here is the bitmap screenshot, as seen below, it is not null.
Here on GitHub I put code with the entire flow implemented.
Main problem is the usage of NetworkImageView for rendering local images.
You can extend NetworkImageView as follows and use method setLocalImageBitmap in case you need to load local images into your view.
public class MyImageView extends NetworkImageView {
private Bitmap mLocalBitmap;
private boolean mShowLocal;
public MyImageView(Context context) {
this(context, null);
}
public MyImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setLocalImageBitmap(Bitmap bitmap) {
if (bitmap != null) {
mShowLocal = true;
}
this.mLocalBitmap = bitmap;
requestLayout();
}
#Override
public void setImageUrl(String url, ImageLoader imageLoader) {
mShowLocal = false;
super.setImageUrl(url, imageLoader);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mShowLocal) {
setImageBitmap(mLocalBitmap);
}
}
}
You should set the new ArrayList in the adapter.
Make a method in BaseAdapter
In Activity,
listImages.add(new ItemData(path));
adapter.setNewList(your arraylist);
adapter.notifyDataSetChanged();
And In Adapter,
public void setNewList(Arraylist<String> newlist)
{
this.list=newlist.
}
It will do your all work.
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!