I'm using the following to transform an image into a circle. (The purpose is to have a rounded circle image to use as a button in an Android application.)
I'm trying to add a shade of shadow but I can't get it to work. Can anyone help?
public static class CircleTransform extends BitmapTransformation {
public CircleTransform(Context context) {
super(context);
}
#Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return circleCrop(pool, toTransform);
}
private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
if (source == null) return null;
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, paint);
return result;
}
#Override
public String getId() {
return getClass().getName();
}
}
Related
I have the following code:
public class LetterGenerator {
private static final int NUM_OF_TILE_COLORS = 8;
private final TextPaint mPaint = new TextPaint();
private final Rect mBounds = new Rect();
private final Canvas mCanvas = new Canvas();
private final char[] mFirstChar = new char[1];
private final TypedArray mColors;
private final int mTileLetterFontSize;
private final Bitmap mDefaultBitmap;
private final int mWidth;
private final int mHeight;
public LetterGenerator(Context context) {
final Resources res = context.getResources();
mPaint.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
mPaint.setColor(Color.WHITE);
mPaint.setTextAlign(Paint.Align.CENTER);
mPaint.setAntiAlias(true);
mColors = res.obtainTypedArray(R.array.avatar_colors);
mTileLetterFontSize = res.getDimensionPixelSize(R.dimen.tile_letter_font_size);
mDefaultBitmap = drawableToBitmap(ContextCompat.getDrawable(context, R.drawable.ic_person_white_24dp));
mWidth = res.getDimensionPixelSize(R.dimen.letter_tile_size);
mHeight = res.getDimensionPixelSize(R.dimen.letter_tile_size);
}
public Bitmap getCircularLetterTile(String displayName) {
final Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
final Canvas c = mCanvas;
c.setBitmap(bitmap);
c.drawColor(pickColor(displayName));
if (displayName.trim().length() == 0) {
c.drawBitmap(mDefaultBitmap, dpToPx(4) ,dpToPx(4), null);
} else {
final char firstChar = displayName.trim().charAt(0);
mFirstChar[0] = Character.toUpperCase(firstChar);
mPaint.setTextSize(mTileLetterFontSize);
mPaint.getTextBounds(mFirstChar, 0, 1, mBounds);
c.drawText(mFirstChar, 0, 1, mWidth / 2, mHeight / 2 + (mBounds.bottom - mBounds.top) / 2, mPaint);
}
return getCircularBitmap(bitmap);
}
private Bitmap getCircularBitmap(Bitmap bitmap) {
Bitmap output;
if (bitmap.getWidth() > bitmap.getHeight()) {
output = Bitmap.createBitmap(bitmap.getHeight(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
} else {
output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
float radius = 0;
if (bitmap.getWidth() > bitmap.getHeight()) {
radius = bitmap.getHeight() / 2;
} else {
radius = bitmap.getWidth() / 2;
}
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawCircle(radius, radius, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
private static Bitmap drawableToBitmap(Drawable drawable) {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getBitmap() != null) {
return bitmapDrawable.getBitmap();
}
}
if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
It creates an avatar letter. As default it sets an XML vector icon. But the icon is a bit of. I can't seem to figure out which arguments I need to pass on line c.drawBitmap(mDefaultBitmap, dpToPx(4) ,dpToPx(4), null). The dpToPx method is:
private int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
What I get:
How can I center the icon?
Change the line
c.drawBitmap(mDefaultBitmap, dpToPx(4) ,dpToPx(4), null);
To:
c.drawBitmap(mDefaultBitmap, mWidth / 2 - mDefaultBitmap.getWidth() / 2, mHeight / 2 - mDefaultBitmap.getHeight() / 2)
The reason that I'm using Picasso is because I need a rounded image and I could achieve this with Picasso using Transformation:
public class CircleTransform implements Transformation {
#Override
public Bitmap transform(Bitmap source) {
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 (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);
squaredBitmap.recycle();
return bitmap;
}
#Override
public String key() {
return "circle";
}
}
And then :
Picasso.with(this).load(R.drawable.image)
.transform(new CircleTransform()).into(photo);
But I'm taking a Bitmap from a Camera and I need to put the image inside of ImageView, rounded! I was trying to use Bitmap to File but it doesnt' work!
I have an app whit an imageView, which is set by the user, either using his/her camera or file system. When the image is set I use this class to round the corners of the image:
public class DrawRoundImage extends Drawable {
private static final boolean USE_VIGNETTE = true;
private final float mCornerRadius;
private final RectF mRect = new RectF();
private final BitmapShader mBitmapShader;
private final Paint mPaint;
private final int mMargin;
public DrawRoundImage(Bitmap bitmap, float cornerRadius, int margin) {
mCornerRadius = cornerRadius;
mBitmapShader = new BitmapShader(bitmap,
Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setShader(mBitmapShader);
mMargin = margin;
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(mMargin, mMargin, bounds.width() - mMargin, bounds.height() - mMargin);
if (USE_VIGNETTE) {
RadialGradient vignette = new RadialGradient(
mRect.centerX(), mRect.centerY() * 1.0f / 0.7f, mRect.centerX() * 1.3f,
new int[] { 0, 0, 0x7f000000 }, new float[] { 0.0f, 0.7f, 1.0f },
Shader.TileMode.CLAMP);
Matrix oval = new Matrix();
oval.setScale(1.0f, 0.7f);
vignette.setLocalMatrix(oval);
mPaint.setShader(
new ComposeShader(mBitmapShader, vignette, PorterDuff.Mode.SRC_OVER));
}
}
#Override
public void draw(Canvas canvas) {
canvas.drawRoundRect(mRect, mCornerRadius, mCornerRadius, mPaint);
}
#Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
#Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
mPaint.setColorFilter(cf);
}
}
Now I need to upload the image to my server, but since it is a drawable I can't quite figure how to turn it back to a Bitmap, which I convert like this:
Bitmap bitmap = bMap;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
I try to convert the drawable to a Bitmap like this:
Drawable drawable = imageButton1.getDrawable();
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
But it throws this error:
java.lang.ClassCastException: com.adrissa.klea.model.DrawRoundImage
cannot be cast to android.graphics.drawable.BitmapDrawable
How can i properly convert a drawable to a bitmap? When i google all i find is questions about drawable resources to bitmap.
Here is how you can convert drawable to bitmap:
Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.example);
#Kæmpe Klunker, look at this solution:
https://stackoverflow.com/a/10600736/4137318
Probably you have to override following methods in your DrawRoundImage class, to make this solution working:
#Override
public int getIntrinsicHeight() {
return (int) mRect.height();
}
#Override
public int getIntrinsicWidth() {
return (int) mRect.width();
}
I`m tring to to load an image from an URL into a Bitmap using the Picasso library , but most of the examples i found refer to loading a Bitmap to a ImageView or something similar.
The code should be something like this , according to the documentation.
public void loadImage() {
Picasso.with(getBaseContext()).load("image url").into(new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
}
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom arg1) {
Bitmap bitImage = Bitmap(getApplicationContext(),bitmap);
}
#Override
public void onBitmapFailed(Drawable arg0) {
}
});
}
But Bitmap bitImage = Bitmap(getApplicationContext(),bitmap); doesn't seem to be correct, since i`m getting a Method call expected error.
It looks like you are not creating the Bitmap properly, but if I was in your position I would create a scaled bitmap like so:
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(
bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
}
Then set it to an imageView like so:
mImg.setImageBitmap(img);
Overall it would look like this:
public void loadImage() {
Picasso.with(getBaseContext()).load("image url").into(new Target() {
// ....
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom arg1) {
// Pick arbitrary values for width and height
Bitmap resizedBitmap = getResizedBitmap(bitmap, newWidth, newHeight);
mImageView.setBitmap(resizedBitmap);
}
// ....
});
}
}
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(
bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
}
But I question you using Target altogether, usually that is for a very specialized case. You should be calling the singleton of Picasso in the same class you will be displaying images. Usually this is in an Adapter (RecyclerView Adapter maybe) like so:
Picasso.with(mContext)
.load("image url")
.into(mImageView);
I am using the following code with the help of 'Android Universal image loader' library, but the quality of the image is very poor and I get too many skipped frames in my logcat,
here is my code, please look and help how can I improve it?
private class DownloadImageTask extends AsyncTask<String, Void,
Bitmap> {
ImageView bmImage;
public DownloadImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
// Bitmap mIcon11 = null;
ImageLoader imageLoader = ImageLoader.getInstance();
Bitmap bitmap = imageLoader.loadImageSync(urldisplay);
Bitmap circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
Paint paint = new Paint();
paint.setShader(shader);
Canvas c = new Canvas(circleBitmap);
c.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2, bitmap.getWidth() / 2, paint);
//img1.setImageBitmap(circleBitmap);
//bmImage.setImageBitmap(circleBitmap);
return circleBitmap;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
Picasso and Volley are very good for images, I use Volley and I made a class that extends NetworkImageView and there I crop the image and make it round.
public class RoundedNetworkImageView extends NetworkImageView {
private Bitmap frame;
public RoundedNetworkImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public RoundedNetworkImageView(Context context, AttributeSet attrs) {
super(context, attrs);
// frame = BitmapFactory.decodeResource(context.getResources(), R.drawable.chat_list_profile_frame);
}
public RoundedNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// frame = BitmapFactory.decodeResource(context.getResources(), R.drawable.chat_list_profile_frame);
}
#Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
if (b != null) {
Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
int w = getWidth(), h = getHeight();
Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
canvas.drawBitmap(roundBitmap, 0, 0, null);
// canvas.drawBitmap(frame, 0, 0, null);
}
}
public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
Bitmap sbmp;
if (bmp.getWidth() != radius || bmp.getHeight() != radius)
sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
else
sbmp = bmp;
Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xffa19774;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(Color.parseColor("#FFFFFF"));
canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f, sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(sbmp, rect, rect, paint);
return output;
}
}
//--------- and when I am using it public
// declaration
public RoundedNetworkImageView user_status_pic;
// getting the image from the url in an list adapter
viewHolder.user_status_pic.setImageUrl(image_url, imageLoader);
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.squareup.picasso.Transformation;
public class CircleTransform implements Transformation {
#Override
public Bitmap transform(Bitmap source) {
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 (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);
squaredBitmap.recycle();
return bitmap;
}
#Override
public String key() {
return "circle";
}
}
try like this:
Picasso.with(context).load("url").transform(new CircleTransform()).into(target);