content: package com.github.akashandroid90.imageletter.drawable;
  
  import android.content.res.ColorStateList;
  import android.graphics.Bitmap;
  import android.graphics.Bitmap.Config;
  import android.graphics.BitmapShader;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.ColorFilter;
  import android.graphics.Matrix;
  import android.graphics.Paint;
  import android.graphics.PixelFormat;
  import android.graphics.Rect;
  import android.graphics.RectF;
  import android.graphics.Shader;
  import android.graphics.drawable.BitmapDrawable;
  import android.graphics.drawable.ColorDrawable;
  import android.graphics.drawable.Drawable;
  import android.graphics.drawable.LayerDrawable;
  import android.widget.ImageView.ScaleType;
  
  public class RoundedDrawable extends Drawable {
      public static final int DEFAULT_BORDER_COLOR = Color.BLACK;
      private final RectF mBounds = new RectF();
      private final RectF mDrawableRect = new RectF();
      private final RectF mBitmapRect = new RectF();
      private final BitmapShader mBitmapShader;
      private final Paint mBitmapPaint;
      private final int mBitmapWidth;
      private final int mBitmapHeight;
      private final RectF mBorderRect = new RectF();
      private final Paint mBorderPaint;
      private final Matrix mShaderMatrix = new Matrix();
      private ColorStateList mBorderColor = ColorStateList.valueOf(DEFAULT_BORDER_COLOR);
      private float mCornerRadius = 0;
      private boolean mOval = false;
      private float mBorderWidth = 0;
      private ScaleType mScaleType = ScaleType.FIT_XY;
  
      public RoundedDrawable(Bitmap bitmap) {
          mBitmapWidth = bitmap.getWidth();
          mBitmapHeight = bitmap.getHeight();
          mBitmapRect.set(0, 0, mBitmapWidth, mBitmapHeight);
          mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
          mBitmapShader.setLocalMatrix(mShaderMatrix);
          mBitmapPaint = new Paint();
          mBitmapPaint.setStyle(Paint.Style.FILL);
          mBitmapPaint.setAntiAlias(true);
          mBitmapPaint.setShader(mBitmapShader);
          mBorderPaint = new Paint();
          mBorderPaint.setStyle(Paint.Style.STROKE);
          if(mBorderColor!=null){
              if (mBorderColor.isStateful())
                  mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
              else mBorderPaint.setColor(mBorderColor.getDefaultColor());
          } else mBorderPaint.setColor(DEFAULT_BORDER_COLOR);
          mBorderPaint.setStrokeWidth(mBorderWidth);
      }
  
      public static Drawable fromBitmap(Bitmap bitmap) {
          if (bitmap != null) {
              return new RoundedDrawable(bitmap);
          } else {
              return null;
          }
      }
  
      public static Drawable fromDrawable(Drawable drawable) {
          if (drawable != null) {
              if (drawable instanceof RoundedDrawable) {
                  // just return if it's already a RoundedDrawable
                  return drawable;
              } else if (drawable instanceof ColorDrawable) {
                  // FIXME we don't support ColorDrawables yet
                  return drawable;
              } else if (drawable instanceof LayerDrawable) {
                  LayerDrawable ld = (LayerDrawable) drawable;
                  int num = ld.getNumberOfLayers();
                  // loop through layers to and change to RoundedDrawables if possible
                  for (int i = 0; i < num; i++) {
                      Drawable d = ld.getDrawable(i);
                      ld.setDrawableByLayerId(ld.getId(i), fromDrawable(d));
                  }
                  return ld;
              }
              // try to get a bitmap from the drawable and
              Bitmap bm = drawableToBitmap(drawable);
              if (bm != null) {
                  return new RoundedDrawable(bm);
              }
          }
          return drawable;
      }
  
      public static Bitmap drawableToBitmap(Drawable drawable) {
          if (drawable instanceof BitmapDrawable) {
              return ((BitmapDrawable) drawable).getBitmap();
          }
          Bitmap bitmap;
          int width = drawable.getIntrinsicWidth();
          int height = drawable.getIntrinsicHeight();
          if (width > 0 && height > 0) {
              bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
              Canvas canvas = new Canvas(bitmap);
              drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
              drawable.draw(canvas);
          } else {
              bitmap = null;
          }
          return bitmap;
      }
  
      @Override
      public boolean isStateful() {
          return mBorderColor.isStateful();
      }
  
      @Override
      protected boolean onStateChange(int[] state) {
          int newColor = mBorderColor.getColorForState(state, 0);
          if (mBorderPaint.getColor() != newColor) {
              mBorderPaint.setColor(newColor);
              return true;
          } else {
              return super.onStateChange(state);
          }
      }
  
      private void updateShaderMatrix() {
          mBorderRect.set(mBounds);
          mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
          float scale;
          float dx;
          float dy;
          switch (mScaleType) {
              case CENTER:
                  mBorderRect.set(mBounds);
                  mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
                  mShaderMatrix.set(null);
                  mShaderMatrix.setTranslate((int) ((mDrawableRect.width() - mBitmapWidth) * 0.5f + 0.5f), (int) ((mDrawableRect.height() - mBitmapHeight) * 0.5f + 0.5f));
                  break;
              case CENTER_CROP:
                  mBorderRect.set(mBounds);
                  mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
                  mShaderMatrix.set(null);
                  dx = 0;
                  dy = 0;
                  if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
                      scale = mDrawableRect.height() / (float) mBitmapHeight;
                      dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
                  } else {
                      scale = mDrawableRect.width() / (float) mBitmapWidth;
                      dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
                  }
                  mShaderMatrix.setScale(scale, scale);
                  mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, (int) (dy + 0.5f) + mBorderWidth);
                  break;
              case CENTER_INSIDE:
                  mShaderMatrix.set(null);
                  if (mBitmapWidth <= mBounds.width() && mBitmapHeight <= mBounds.height()) {
                      scale = 1.0f;
                  } else {
                      scale = Math.min(mBounds.width() / (float) mBitmapWidth,
                              mBounds.height() / (float) mBitmapHeight);
                  }
                  dx = (int) ((mBounds.width() - mBitmapWidth * scale) * 0.5f + 0.5f);
                  dy = (int) ((mBounds.height() - mBitmapHeight * scale) * 0.5f + 0.5f);
                  mShaderMatrix.setScale(scale, scale);
                  mShaderMatrix.postTranslate(dx, dy);
                  mBorderRect.set(mBitmapRect);
                  mShaderMatrix.mapRect(mBorderRect);
                  mDrawableRect.set(mBorderRect.left + mBorderWidth, mBorderRect.top + mBorderWidth, mBorderRect.right - mBorderWidth, mBorderRect.bottom - mBorderWidth);
                  mShaderMatrix.setRectToRect(mBitmapRect, mDrawableRect, Matrix.ScaleToFit.FILL);
                  break;
              case FIT_CENTER:
                  mBorderRect.set(mBitmapRect);
                  mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.CENTER);
                  mShaderMatrix.mapRect(mBorderRect);
                  mDrawableRect.set(mBorderRect.left + mBorderWidth, mBorderRect.top + mBorderWidth, mBorderRect.right - mBorderWidth, mBorderRect.bottom - mBorderWidth);
                  mShaderMatrix.setRectToRect(mBitmapRect, mDrawableRect, Matrix.ScaleToFit.FILL);
                  break;
              case FIT_END:
                  mBorderRect.set(mBitmapRect);
                  mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.END);
                  mShaderMatrix.mapRect(mBorderRect);
                  mDrawableRect.set(mBorderRect.left + mBorderWidth, mBorderRect.top + mBorderWidth, mBorderRect.right - mBorderWidth, mBorderRect.bottom - mBorderWidth);
                  mShaderMatrix.setRectToRect(mBitmapRect, mDrawableRect, Matrix.ScaleToFit.FILL);
                  break;
              case FIT_START:
                  mBorderRect.set(mBitmapRect);
                  mShaderMatrix.setRectToRect(mBitmapRect, mBounds, Matrix.ScaleToFit.START);
                  mShaderMatrix.mapRect(mBorderRect);
                  mDrawableRect.set(mBorderRect.left + mBorderWidth, mBorderRect.top + mBorderWidth, mBorderRect.right - mBorderWidth, mBorderRect.bottom - mBorderWidth);
                  mShaderMatrix.setRectToRect(mBitmapRect, mDrawableRect, Matrix.ScaleToFit.FILL);
                  break;
              case FIT_XY:
              default:
                  mBorderRect.set(mBounds);
                  mDrawableRect.set(0 + mBorderWidth, 0 + mBorderWidth, mBorderRect.width() - mBorderWidth, mBorderRect.height() - mBorderWidth);
                  mShaderMatrix.set(null);
                  mShaderMatrix.setRectToRect(mBitmapRect, mDrawableRect, Matrix.ScaleToFit.FILL);
                  break;
          }
          mBorderRect.inset(mBorderWidth / 2, mBorderWidth / 2);
          mBitmapShader.setLocalMatrix(mShaderMatrix);
      }
  
      @Override
      protected void onBoundsChange(Rect bounds) {
          super.onBoundsChange(bounds);
          mBounds.set(bounds);
          updateShaderMatrix();
      }
  
      @Override
      public void draw(Canvas canvas) {
          if (mOval) {
              if (mBorderWidth > 0) {
                  canvas.drawOval(mBorderRect, mBorderPaint);
                  canvas.drawOval(mDrawableRect, mBitmapPaint);
              } else {
                  canvas.drawOval(mDrawableRect, mBitmapPaint);
              }
          } else {
              if (mBorderWidth > 0) {
                  canvas.drawRoundRect(mBorderRect, mCornerRadius, mCornerRadius, mBorderPaint);
                  canvas.drawRoundRect(mDrawableRect, Math.max(mCornerRadius - mBorderWidth, 0), Math.max(mCornerRadius - mBorderWidth, 0), mBitmapPaint);
              } else {
                  canvas.drawRoundRect(mDrawableRect, mCornerRadius, mCornerRadius, mBitmapPaint);
              }
          }
      }
  
      @Override
      public int getOpacity() {
          return PixelFormat.TRANSLUCENT;
      }
  
      @Override
      public void setAlpha(int alpha) {
          mBitmapPaint.setAlpha(alpha);
          invalidateSelf();
      }
  
      @Override
      public void setColorFilter(ColorFilter cf) {
          mBitmapPaint.setColorFilter(cf);
          invalidateSelf();
      }
  
      @Override
      public void setDither(boolean dither) {
          mBitmapPaint.setDither(dither);
          invalidateSelf();
      }
  
      @Override
      public void setFilterBitmap(boolean filter) {
          mBitmapPaint.setFilterBitmap(filter);
          invalidateSelf();
      }
  
      @Override
      public int getIntrinsicWidth() {
          return mBitmapWidth;
      }
  
      @Override
      public int getIntrinsicHeight() {
          return mBitmapHeight;
      }
  
      public float getCornerRadius() {
          return mCornerRadius;
      }
  
      public RoundedDrawable setCornerRadius(float radius) {
          mCornerRadius = radius;
          return this;
      }
  
      public float getBorderWidth() {
          return mBorderWidth;
      }
  
      public RoundedDrawable setBorderWidth(int width) {
          mBorderWidth = width*5;
          mBorderPaint.setStrokeWidth(mBorderWidth);
          return this;
      }
  
      public int getBorderColor() {
          if(mBorderColor!=null)
          return mBorderColor.getDefaultColor();
          else return DEFAULT_BORDER_COLOR;
      }
  
      public RoundedDrawable setBorderColor(int color) {
          return setBorderColors(ColorStateList.valueOf(color));
      }
  
      public ColorStateList getBorderColors() {
          return mBorderColor;
      }
  
      public RoundedDrawable setBorderColors(ColorStateList colors) {
          mBorderColor = colors != null ? colors : ColorStateList.valueOf(0);
          if (mBorderColor.isStateful())
              mBorderPaint.setColor(mBorderColor.getColorForState(getState(), DEFAULT_BORDER_COLOR));
          else mBorderPaint.setColor(mBorderColor.getDefaultColor());
          return this;
      }
  
      public boolean isOval() {
          return mOval;
      }
  
      public RoundedDrawable setOval(boolean oval) {
          mOval = oval;
          return this;
      }
  
      public ScaleType getScaleType() {
          return mScaleType;
      }
  
      public RoundedDrawable setScaleType(ScaleType scaleType) {
          if (scaleType == null) {
              scaleType = ScaleType.FIT_XY;
          }
          if (mScaleType != scaleType) {
              mScaleType = scaleType;
              updateShaderMatrix();
          }
          return this;
      }
  }