I am trying to use the support lib v4's RoundedBitmapDrawable in order to display Rounded bitmaps loaded asynchronously in ImageViews, either circled or rounded rectangles.
However, it looks like RoundedBitmapDrawable does not mesh very well with LayerDrawable :
If I try something like :
if (previousDrawable != null) {
final Drawable[] layers = new Drawable[2];
layers[0] = previousDrawable;
layers[1] = roundedDrawable;
TransitionDrawable drawable = new TransitionDrawable(layers);
view.setImageDrawable(drawable);
drawable.startTransition(3000);
} else {
view.setImageDrawable(roundedDrawable);
}
The TransitionDrawable launches but it does not respect the RoundedBitmapDrawable is not correctly displayed : its dimensions seems to shift somehow, if I set it to be a circle with :
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory
.create(getResources(), bitmap);
roundedDrawable.setCornerRadius(bitmap.getHeight() / 2);
roundedDrawable.setAntiAlias(true);
It is displayed correctly if I use ImageView.setImageDrawable(), but it results in a rounded rectangle if a TransitionDrawable displays it.
Does anybody has any idea why this display problem happen ?
Set
roundedDrawable.setCircular(true);
then it works fine
Use Universal Image loader to fix your issue
https://github.com/nostra13/Android-Universal-Image-Loader
This is my solution to create a rounded image:
package com.campusapp;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
public class CircularImageView extends ImageView {
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CircularImageView(final Context context) {
this(context, null);
}
public CircularImageView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.circularImageViewStyle);
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
// load the styled attributes and set their properties
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
if(attributes.getBoolean(R.styleable.CircularImageView_border, true))
{
int defaultBorderSize = (int) (4 * getContext().getResources().getDisplayMetrics().density + 0.5f);
setBorderWidth(attributes.getDimensionPixelOffset(R.styleable.CircularImageView_border_width, defaultBorderSize));
setBorderColor(attributes.getColor(R.styleable.CircularImageView_border_color, Color.WHITE));
}
if(attributes.getBoolean(R.styleable.CircularImageView_shadow, false))
addShadow();
}
public void setBorderWidth(int borderWidth)
{
this.borderWidth = borderWidth;
this.requestLayout();
this.invalidate();
}
public void setBorderColor(int borderColor)
{
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
public void addShadow()
{
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
#Override
public void onDraw(Canvas canvas)
{
// load the bitmap
image = drawableToBitmap(getDrawable());
// init shader
if (image != null)
{
canvasSize = canvas.getWidth();
if(canvas.getHeight()<canvasSize)
canvasSize = canvas.getHeight();
BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY)
{
// The parent has determined an exact size for the child.
result = specSize;
}
else if (specMode == MeasureSpec.AT_MOST)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight)
{
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY)
{
// We were told how big to be
result = specSize;
}
else if (specMode == MeasureSpec.AT_MOST)
{
// The child can be as large as it wants up to the specified size.
result = specSize;
}
else
{
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2);
}
public Bitmap drawableToBitmap(Drawable drawable)
{
if (drawable == null)
{
return null;
}
else if (drawable instanceof BitmapDrawable)
{
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap 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;
}
}
After creating the class, replace your ImageView with the code below:
<com.yourpkg.CircularImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/your_image"
app:border_color="#EEEEEE"
app:border_width="4dp"
app:shadow="true" />
public static Bitmap getRoundedCornerBitmap(Context context, Bitmap input, int pixels , int w , int h , boolean squareTL, boolean squareTR, boolean squareBL, boolean squareBR ) {
Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final float densityMultiplier = context.getResources().getDisplayMetrics().density;
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
//make sure that our rounded corner is scaled appropriately
final float roundPx = pixels*densityMultiplier;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
//draw rectangles over the corners we want to be square
if (squareTL ){
canvas.drawRect(0, 0, w/2, h/2, paint);
}
if (squareTR ){
canvas.drawRect(w/2, 0, w, h/2, paint);
}
if (squareBL ){
canvas.drawRect(0, h/2, w/2, h, paint);
}
if (squareBR ){
canvas.drawRect(w/2, h/2, w, h, paint);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0,0, paint);
return output;
}
or you can see this also
Related
I'm writing a custom Circular ImageView in Android. I need to set a Drawable overlay on top of it, so I chose to write a custom CircularImageView that holds the picture itself + the drawable.
Actually I have 2 problems:
The image is drawn top-left, I need it to be drawn on the center of the View
I need my crown to be bigger (drawable) but I don't know how to resize it.
Some imgs to clarify:
What I'd like to achieve:
What I have now:(please, disconsider the black frame border, it's just to clarify the wrong image "gravity")
My view code:
public class CrownCircularImageView extends ImageView {
private Drawable crown;
private int canvasSize;
private int crownWidth;
private int crownHeight;
// Object used to draw
private Bitmap image;
private Drawable drawable;
private Paint paint;
private Paint crownPaint;
public CrownCircularImageView(Context context) {
this(context, null, 0);
}
public CrownCircularImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CrownCircularImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
crownPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
this.crown = ContextCompat.getDrawable(context, R.drawable.ic_crown);
}
private void loadBitmap() {
if (this.drawable == getDrawable())
return;
this.drawable = getDrawable();
this.image = drawableToBitmap(this.drawable);
updateShader();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
canvasSize = w - crownWidth;
if (h < canvasSize)
canvasSize = h - crownHeight;
if (image != null)
updateShader();
}
private void updateShader() {
if (image == null)
return;
// Crop Center Image
image = cropBitmap(image);
// Create Shader
BitmapShader shader = new BitmapShader(image, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
// Center Image in Shader
Matrix matrix = new Matrix();
matrix.setScale((float) canvasSize / (float) image.getWidth(), (float) canvasSize / (float) image.getHeight());
shader.setLocalMatrix(matrix);
// Set Shader in Paint
paint.setShader(shader);
}
private Bitmap cropBitmap(Bitmap bitmap) {
Bitmap bmp;
if (bitmap.getWidth() >= bitmap.getHeight()) {
bmp = Bitmap.createBitmap(
bitmap,
bitmap.getWidth() / 2 - bitmap.getHeight() / 2,
0,
bitmap.getHeight(),
bitmap.getHeight());
} else {
bmp = Bitmap.createBitmap(
bitmap,
0,
bitmap.getHeight() / 2 - bitmap.getWidth() / 2,
bitmap.getWidth(),
bitmap.getWidth());
}
return bmp;
}
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
} else if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
int intrinsicWidth = drawable.getIntrinsicWidth();
int intrinsicHeight = drawable.getIntrinsicHeight();
if (!(intrinsicWidth > 0 && intrinsicHeight > 0))
return null;
try {
// Create Bitmap object out of the drawable
Bitmap bitmap = Bitmap.createBitmap(intrinsicWidth, intrinsicHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
// Simply return null of failed bitmap creations
Log.e(getClass().toString(), "Encountered OutOfMemoryError while generating bitmap!");
return null;
}
}
#Override
public void onDraw(Canvas canvas) {
// Load the bitmap
loadBitmap();
// Check if image isn't null
if (image == null)
return;
if (!isInEditMode()) {
canvasSize = canvas.getWidth();
if (canvas.getHeight() < canvasSize) {
canvasSize = canvas.getHeight();
}
}
int circleCenter = (canvasSize - crownHeight) / 2;
int cx = (canvasSize - crownWidth) / 2;
int cy = (canvasSize - crownHeight) / 2;
Bitmap crownBmp = drawableToBitmap(crown);
int crownX = cx;
int crownY = cy;
canvas.drawCircle(cx, cy, circleCenter, paint);
canvas.drawBitmap(crownBmp, crownX, crownY, crownPaint);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
crownWidth = crown.getIntrinsicWidth();
crownHeight = crown.getIntrinsicHeight();
setMeasuredDimension(width, height);
}
#Override
public ScaleType getScaleType() {
return ScaleType.CENTER_CROP;
}
private int measureWidth(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// The parent has determined an exact size for the child.
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result + crown.getIntrinsicWidth();
}
private int measureHeight(int measureSpecHeight) {
int result;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2 + crown.getIntrinsicHeight());
}
}
You can create a new bitmap to draw the old one on a transparent background with a circle mask, and then draw the crown on it. This example also allows to add a padding around the image.
You will want to tweak the values of CIRCLE_PADDING and RESIZE_CROWN_FACTOR to fulfill your needs.
public class CrownImageView extends ImageView {
private static final int CIRCLE_PADDING = 25;
private static final float RESIZE_CROWN_FACTOR = 1.5f;
private Bitmap rounded;
private Bitmap resizedCrown;
public CrownImageView(final Context context) {
super(context);
}
public CrownImageView(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
public CrownImageView(final Context context, final AttributeSet attrs, final int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null || getWidth() == 0 || getHeight() == 0) {
return;
}
if (resizedCrown == null) {
loadCrown();
}
loadImage(drawable);
canvas.drawBitmap(rounded, 0, 0, null);
canvas.drawBitmap(resizedCrown, canvas.getWidth() - resizedCrown.getWidth(), 0, null);
}
private void loadImage(Drawable drawable) {
Bitmap bmp = bitmapFromDrawable(drawable);
final Rect rect = new Rect(0, 0, bmp.getWidth(), bmp.getHeight());
final Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
rounded = Bitmap.createBitmap(bmp.getWidth(),
bmp.getHeight(), Bitmap.Config.ARGB_8888);
Canvas newCanvas = new Canvas(rounded);
newCanvas.drawARGB(0, 0, 0, 0);
float centerX = getWidth() / 2;
float centerY = getHeight() / 2;
float radius = Math.min(getWidth(), getHeight()) / 2 - CIRCLE_PADDING;
newCanvas.drawCircle(centerX, centerY, radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
newCanvas.drawBitmap(bmp, rect, rect, paint);
}
private void loadCrown() {
Bitmap crown = BitmapFactory.decodeResource(getResources(), R.drawable.crown);
resizedCrown = Bitmap.createScaledBitmap(crown,
(int) (crown.getWidth() * RESIZE_CROWN_FACTOR),
(int) (crown.getHeight() * RESIZE_CROWN_FACTOR),
true);
}
private Bitmap bitmapFromDrawable(Drawable drawable) {
Bitmap bmp;
if (drawable instanceof BitmapDrawable) {
bmp = ((BitmapDrawable) drawable).getBitmap();
} else {
bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas bmpCanvas = new Canvas(bmp);
drawable.setBounds(0, 0, bmpCanvas.getWidth(), bmpCanvas.getHeight());
drawable.draw(bmpCanvas);
}
return bmp;
}
}
Update: You can use it with Glide like this
final CrownImageView imageView = (CrownImageView) findViewById(R.id.fragment_kids_row_img_kids);
Glide.with(this).load(yourimageurl).into(imageView);
The image is drawn top-left, I need it to be drawn on the center of the View
Yes, that is because of parameters to .drawCircle
canvas.drawCircle(cx, cy, circleCenter, paint);
You are not calculating them for your image. This should be something like
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
float bitmapRadius = Math.min(image.getWidth(), image.getHeight()) / 2f;
canvas.drawCircle(centerX, centerY, bitmapRadius, paint);
But I think it is better to save this values and recalculate them when size changes.
I need my crown to be bigger (drawable) but I don't know how to resize it.
You specify size of bitmap yourself - make it a bit bigger by specifying another size.
Bitmap bitmap = Bitmap.createBitmap(
intrinsicWidth + scale,
intrinsicHeight + scale,
Bitmap.Config.ARGB_8888);
I've modified your code: http://pastebin.com/0h02Tqh1
I made this Custom Drawable that should clip any Drawable in circle. But with my implementation, the drawable passed is being the output in the original form not in the circular form.
public class CircularDrawable extends Drawable {
Paint mPaint,xfermodePaint;
Drawable mDrawable;
int[] vinylCenter = new int[2];
int radius;
Bitmap src;
PorterDuffXfermode xfermode;
Rect rect;
Canvas testCanvas;
public CircularDrawable(Drawable drawable) {
mDrawable = drawable;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(0xffffffff);
mPaint.setStyle(Paint.Style.FILL);
xfermodePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
xfermodePaint.setXfermode(xfermode);
testCanvas=new Canvas();
}
#Override
public void setBounds(Rect bounds) {
super.setBounds(bounds);
mDrawable.setBounds(bounds);
}
#Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
mDrawable.setBounds(left, top, right, bottom);
}
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
vinylCenter[0] = bounds.width() / 2;
vinylCenter[1] = bounds.height() / 2;
radius = (bounds.right - bounds.left) / 2;
src = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888);
testCanvas.setBitmap(src);
}
#Override
public void draw(Canvas canvas) {
canvas.save();
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint);
mDrawable.draw(testCanvas);
canvas.drawBitmap(src,0f,0f,xfermodePaint);
}
#Override
public void setAlpha(int alpha) {/*ignored*/}
#Override
public void setColorFilter(ColorFilter colorFilter) {/*ignored*/}
#Override
public int getOpacity() {
/*ignored*/
return 0;
}
}
What is my mistake?
Also I am using a SquareImageview to display this drawable that just makes the view square in onMeasure.
This question is not meant for Circular imageview.
You already have optimized implementation for circular drawable in Support library v4:
Google reference
/**
* A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a
* RoundedBitmapDrawable from a file path, an input stream, or from a
* {#link android.graphics.Bitmap} object.
* <p>
* Also see the {#link android.graphics.Bitmap} class, which handles the management and
* transformation of raw bitmap graphics, and should be used when drawing to a
* {#link android.graphics.Canvas}.
* </p>
*/
public abstract class RoundedBitmapDrawable extends Drawable ....
The canvas doesnt have alpha channel on by default when using Porter/Duff xfermode mode (As per my experience with my this in android). That is the reason the whole image(src) is being the output. Porter/Duff xfermode acts based on Alpha Channel.
In many implementation of Circular Drawable 2 Canvas are taken, out of which one is given RGB image bitmap and other is given only alpha channel bitmap with circular mask. Porter/Duff xfermodeis applied and the result is drawn on the main canvas.
My mistake is that I am not specifying the draw function's canvas that alpha channel is to be considered on using the layer on the canvas for xfermode.
The draw function will become
#Override
public void draw(Canvas canvas) {
int sc = canvas.saveLayer(null, null,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
);
canvas.drawCircle(vinylCenter[0],vinylCenter[1],radius,mPaint);
mDrawable.draw(testCanvas);
canvas.drawBitmap(src,0f,0f,xfermodePaint);
canvas.restoreToCount(sc);
}
Saving the Layer to indicate alpha channel with the flag and then using the xfermode. Finally restoring it to its save count.
So basically I use this method to get rounded corner images
public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), 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());
final RectF rectF = new RectF(rect);
final float roundPx = pixels;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
but like you pointed out sometimes it does not work, well it does work, but what happens most of the time is your imageview might have its scaletype set to centerCrop and other types, what I do is I first compress my image height to the same height and width as my imageview so that the entire image will fit in the imageview and no scaling will take place or I just calculate how much of the corner height to make rounded using this function based on the height
private int calculatePercentage(int percentage, int target)
{
int k = (int)(target*(percentage/100.0f));
return k;
}
so I use my code like: new Bitmap(getRoundedCornerBitmap(bmp, calculatePercentage(5, bmp.getHeight()))); where 5 is 5 of the image height this gives me same curves for all images be it some images are bigger than others
`
For rounded imageview you can use this code
public class RoundedImageView extends ImageView {
public RoundedImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public RoundedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap b = ((BitmapDrawable) drawable).getBitmap();
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);
}
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("#BAB399"));
paint.setColor(Color.parseColor("#FF0000"));
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;
}
}
For circular imageview use the below code
public class RoundedImageView extends ImageView {
public RoundedImageView(Context context) {
super(context);
}
public RoundedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onDraw(Canvas canvas) {
BitmapDrawable drawable = (BitmapDrawable) getDrawable();
if (drawable == null) {
return;
}
if (getWidth() == 0 || getHeight() == 0) {
return;
}
Bitmap fullSizeBitmap = drawable.getBitmap();
int scaledWidth = getMeasuredWidth();
int scaledHeight = getMeasuredHeight();
/*
* scaledWidth = scaledWidth/2; scaledHeight = scaledHeight/2;
*/
Bitmap mScaledBitmap;
if (scaledWidth == fullSizeBitmap.getWidth()
&& scaledHeight == fullSizeBitmap.getHeight()) {
mScaledBitmap = fullSizeBitmap;
} else {
mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap,
scaledWidth, scaledHeight, true /* filter */);
}
// Bitmap roundBitmap = getRoundedCornerBitmap(mScaledBitmap);
// Bitmap roundBitmap = getRoundedCornerBitmap(getContext(),
// mScaledBitmap, 10, scaledWidth, scaledHeight, false, false,
// false, false);
// canvas.drawBitmap(roundBitmap, 0, 0, null);
Bitmap circleBitmap = getCircledBitmap(mScaledBitmap);
canvas.drawBitmap(circleBitmap, 0, 0, null);
}
public Bitmap getRoundedCornerBitmap(Context context, Bitmap input,
int pixels, int w, int h, boolean squareTL, boolean squareTR,
boolean squareBL, boolean squareBR) {
Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final float densityMultiplier = context.getResources()
.getDisplayMetrics().density;
final int color = 0xff424242;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, w, h);
final RectF rectF = new RectF(rect);
// make sure that our rounded corner is scaled appropriately
final float roundPx = pixels * densityMultiplier;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
// draw rectangles over the corners we want to be square
if (squareTL) {
canvas.drawRect(0, 0, w / 2, h / 2, paint);
}
if (squareTR) {
canvas.drawRect(w / 2, 0, w, h / 2, paint);
}
if (squareBL) {
canvas.drawRect(0, h / 2, w / 2, h, paint);
}
if (squareBR) {
canvas.drawRect(w / 2, h / 2, w, h, paint);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(input, 0, 0, paint);
return output;
}
Bitmap getCircledBitmap(Bitmap bitmap) {
Bitmap result = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
int color = Color.BLUE;
Paint paint = new Paint();
Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
// canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
bitmap.getHeight() / 2, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return result;
}
}
Try disabling hardware acceleration if you are using PorterDuffXfermode:
In manifest for whole activity:
<activity android:hardwareAccelerated="false" />
Or on a specific view on which you are using xfermode:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
I need to get circle images from rectangular/square images taken from network. In my application I get images with Volley's NetworkImageView. I found that fantastic library https://github.com/hdodenhof/CircleImageView but I don't understand how I can use it with NetworkImageView.
Can someone help me?
Check this Class
public class CirculaireNetworkImageView extends NetworkImageView {
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CirculaireNetworkImageView(final Context context) {
this(context, null);
}
public CirculaireNetworkImageView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.actionButtonStyle);
}
public CirculaireNetworkImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.requestLayout();
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
public void addShadow() {
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
image = drawableToBitmap(getDrawable());
// init shader
if (image != null) {
canvasSize = canvas.getWidth();
if(canvas.getHeight()<canvasSize)
canvasSize = canvas.getHeight();
BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// The parent has determined an exact size for the child.
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = canvasSize;
}
return (result + 2);
}
public Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
} else if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap 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;
}
}
Check the source code of the NetworkImageView here. Modify it to extend your "CircleImageView" instead of the normal ImageView and you are done.
I am using circularimageView to display the picture of a person. Here's the class.
public class CircularImageView extends ImageView {
private int borderWidth = 4;
private int viewWidth;
private int viewHeight;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
private BitmapShader shader;
public CircularImageView(Context context) {
super(context);
setup();
}
public CircularImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setup();
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setup();
}
private void setup() {
// init paint
paint = new Paint();
paintBorder = new Paint();
paint.setAntiAlias(true);
setBorderColor(Color.WHITE);
paintBorder.setAntiAlias(true);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
this.setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
}
else
{
}
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.invalidate();
}
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
private void loadBitmap() {
BitmapDrawable bitmapDrawable = (BitmapDrawable) this.getDrawable();
if (bitmapDrawable != null)
image = bitmapDrawable.getBitmap();
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
loadBitmap();
// init shader
if (image != null) {
shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvas.getWidth(), canvas.getHeight(), false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
int circleCenter = viewWidth / 2;
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, circleCenter - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec, widthMeasureSpec);
viewWidth = width - (borderWidth * 2);
viewHeight = height - (borderWidth * 2);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = viewWidth;
}
return result;
}
private int measureHeight(int measureSpecHeight, int measureSpecWidth) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text (beware: ascent is a negative number)
result = viewHeight;
}
return (result + 2);
}
}
It works fine in anything > API 10 but in other cases the image gets stretched out and only the top left part of the image is visible and is pixelated. I tried Resizing the bitmap of the picture but it did not help.
Here is the bitmap initialization
PackageManager m = getActivity().getPackageManager();
String s = getActivity().getPackageName();
PackageInfo p = null;
try {
p = m.getPackageInfo(s, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
s = p.applicationInfo.dataDir;
//String root = Environment.getExternalStorageDirectory().toString();
s += "/player_photos/" + player.getPlayerId() + ".png";
Bitmap bMap = BitmapFactory.decodeFile(s);
Resources res = getResources();
BitmapDrawable icon = new BitmapDrawable(res, bMap);
playerDP.setImageDrawable(icon);
}
I want to know an Image inside a Circle Mask as follows.
The user usually selected the image from the gallery or shoots one using the camera. Considering that the image is either Landscape or Portrait and not square. is there a way to display a center cropped image after choosing the image?
<com.mikhaellopez.circularimageview.CircularImageView
android:id="#+id/ivCreateCompanyImage"
android:layout_width="#dimen/big_logo_width_height"
android:layout_height="#dimen/big_logo_width_height"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="#dimen/ten_dp"
android:layout_marginTop="#dimen/thirty_dp"
android:src="#drawable/add_image"
android:scaleType="centerCrop"
android:background="#drawable/logo_button_selector"
app:border_color="#color/transparent"
app:border_width="5"
app:shadow="false" />
Java code
public void onActivityResult(int requestCode, int resultCode,
Intent data)
{
if(resultCode != RESULT_OK)
return;
else if (requestCode == SELECT_FILE)
{
// this gives the Uri of the selected image
Uri selectedImageUri = data.getData();
try {
InputStream stream = getActivity().getContentResolver().openInputStream(selectedImageUri);
byte[] bytes = getBytes(stream);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
int height_width = (int) getResources().getDimension(R.dimen.big_logo_width_height);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap,height_width,height_width,true);
ivCreateCompanyImage.setImageBitmap(scaledBitmap);
}
catch(Exception ex)
{
}
//ivCreateCompanyImage.setImageURI(selectedImageUri);
}
else if( requestCode == CAPTURE_FROM_CAMERA)
{
File f = new File(Environment.getExternalStorageDirectory().toString());
for (File temp : f.listFiles())
{
if (temp.getName().equals("temp.jpg"))
{
f = temp;
ivCreateCompanyImage.setImageURI(Uri.fromFile(f));
break;
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}
You can do this very simply (I've done this exact thing and its live on millions of devices right now) using Picasso and a Circular Image Transformation.
Here's a gist of the exact code I use in production.
This code is working for me
<com.abc.commons.helper.CircularImageView
android:id="#+id/capture_pic"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:background="#drawable/payer_profile_image"
android:scaleType="centerCrop"
app:shadow="true" />
Create seperate java class name as CircularImageView.java and paste the entire below code
and just give the reference of this class in your xml imgevoew tag and after that it will take care everything automatically
package com.xyz.commons.helper;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* This class is used to set style of image
* means this class will help to set the image in circular form
* #author santoshk
*
*/
#SuppressLint("DrawAllocation")
public class CircularImageView extends ImageView {
private int borderWidth;
private int canvasSize;
private Bitmap image;
private Paint paint;
private Paint paintBorder;
public CircularImageView(final Context context) {
this(context, null);
}
public CircularImageView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.circularImageViewStyle);
}
#SuppressLint("Recycle")
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// init paint
paint = new Paint();
paint.setAntiAlias(true);
paintBorder = new Paint();
paintBorder.setAntiAlias(true);
// load the styled attributes and set their properties
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
if(attributes.getBoolean(R.styleable.CircularImageView_border, true)) {
int defaultBorderSize = (int) (4 * getContext().getResources().getDisplayMetrics().density + 0.5f);
setBorderWidth(attributes.getDimensionPixelOffset(R.styleable.CircularImageView_border_width, defaultBorderSize));
setBorderColor(attributes.getColor(R.styleable.CircularImageView_border_color, Color.WHITE));
}
if(attributes.getBoolean(R.styleable.CircularImageView_shadow, false))
addShadow();
}
/**
* This method is used to set the width of border
* #param borderWidth
*/
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
this.requestLayout();
this.invalidate();
}
/**
* This method is used to set the color of border
* #param borderColor
*/
public void setBorderColor(int borderColor) {
if (paintBorder != null)
paintBorder.setColor(borderColor);
this.invalidate();
}
/**
* This method is used to set the shadow
*/
public void addShadow() {
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
paintBorder.setShadowLayer(4.0f, 0.0f, 2.0f, Color.BLACK);
}
#SuppressLint("DrawAllocation")
#Override
public void onDraw(Canvas canvas) {
// load the bitmap
image = drawableToBitmap(getDrawable());
// init shader
if (image != null) {
canvasSize = canvas.getWidth();
if(canvas.getHeight()<canvasSize)
canvasSize = canvas.getHeight();
BitmapShader shader = new BitmapShader(Bitmap.createScaledBitmap(image, canvasSize, canvasSize, false), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(shader);
// circleCenter is the x or y of the view's center
// radius is the radius in pixels of the cirle to be drawn
// paint contains the shader that will texture the shape
int circleCenter = (canvasSize - (borderWidth * 2)) / 2;
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) + borderWidth - 4.0f, paintBorder);
canvas.drawCircle(circleCenter + borderWidth, circleCenter + borderWidth, ((canvasSize - (borderWidth * 2)) / 2) - 4.0f, paint);
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
// The parent has determined an exact size for the child.
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
// The child can be as large as it wants up to the specified size.
result = specSize;
} else {
// The parent has not imposed any constraint on the child.
result = canvasSize;
}
return result;
}
private int measureHeight(int measureSpecHeight) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
result = specSize;
} else {
result = canvasSize;
}
return (result + 2);
}
public Bitmap drawableToBitmap(Drawable drawable) {
if (drawable == null) {
return null;
} else if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
Bitmap 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;
}
}