Skip to content

Instantly share code, notes, and snippets.

@ronshapiro
Last active August 29, 2015 14:05
Show Gist options
  • Save ronshapiro/efce6021ea63f786c8b1 to your computer and use it in GitHub Desktop.
Save ronshapiro/efce6021ea63f786c8b1 to your computer and use it in GitHub Desktop.
package com.venmo.views;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.DrawableRes;
import com.crashlytics.android.Crashlytics;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.squareup.picasso.Transformation;
public enum ResourceTransformation implements Transformation {
CIRCULAR_TRANSFORMATION() {
@Override
public Bitmap transform(Bitmap source, boolean recycle) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (recycle && squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP,
BitmapShader.TileMode.CLAMP);
paint.setShader(shader);
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
if (recycle) {
squaredBitmap.recycle();
}
return bitmap;
}
@Override
public String key() {
return "com.venmo.circle-transform";
}
};
public static final ResourceTransformation AVATAR_TRANSFORMATION = CIRCULAR_TRANSFORMATION;
private Cache<Integer, Drawable> mDrawableCache;
ResourceTransformation() {
mDrawableCache = CacheBuilder.newBuilder()
.maximumSize(10)
.build();
}
@Override
public final Bitmap transform(Bitmap source) {
return transform(source, true);
}
/**
* @param recycle whether or not to recycle the source image. Useful for avoiding recycling a
* transformed Bitmap from {@link Resources}, since they are cached by the framework and could
* be used in other contexts, untransformed.
* @see Transformation#transform(Bitmap)
*/
abstract Bitmap transform(Bitmap source, boolean recycle);
public Drawable transform(Context context, @DrawableRes int resId) {
Drawable cached = mDrawableCache.getIfPresent(resId);
if (cached == null) {
Resources res = context.getResources();
Drawable drawable = res.getDrawable(resId);
if (drawable instanceof BitmapDrawable) {
Bitmap original = ((BitmapDrawable) drawable).getBitmap();
Bitmap transformed = transform(original, false);
// Don't recycle `original` since those Bitmaps are cached by framework. Recycling
// it will cause any future references to that Drawable (even in XML) to be recycled.
drawable = new BitmapDrawable(res, transformed);
} else {
logNotBitmap(drawable);
}
mDrawableCache.put(resId, drawable);
return drawable;
} else {
return cached;
}
}
private void logNotBitmap(Drawable drawable) {
Crashlytics.logException(new IllegalStateException(
"Drawable expected to be BitmapDrawable but is " + drawable.getClass().getName() +
"instead!"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment