1

In my ImageView's onDraw I am struggling to convert a Drawable object to a Bitmap (respecting scaling). I'm loading an SVG file as a PictureDrawable. Then I'm trying to apply rounded corners to the image with a BitmapShader. In order to do that I have to convert the Drawable to Bitmap. It basically works, but I'm not getting my head around the scaling procedure.

Bitmap bitmap = Bitmap.createBitmap(
    picture.getIntrinsicWidth(),
    picture.getIntrinsicHeight(),
    Bitmap.Config.ARGB_8888
)

Canvas canvas = new Canvas( bitmap )
// Scaling the Canvas appears to work ...
canvas.concat( getImageMatrix() )
canvas.drawPicture(
    picture.getPicture,
    // ... however this will not fill the viewport, as the getWidth and getHeight
    // values do not reflect the scaling
    new RectF( 0, 0, canvas.getWidth(), canvas.getHeight() )
)

paint.setShader( new BitmapShader( bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP ) )
canvas.drawRoundRect(
    new RectF( 0, 0, bitmap.getWidth(), bitmap.getHeight() ),
    radius,
    radius,
    paint
)

Erroneous rendering example for centerCrop scaling: screenshot

Besides the problem described in the code comments above I am wondering whether it might be possible to mask the the Picture/SVG file with drawing operations such as clipPath instead of this heavy Bitmap conversion. But it'd have to be anti-aliased, of course.

The code was originally written in Scala and loosely translated to Java for SO, so please ignore any Syntax errors

Taig
  • 6,718
  • 4
  • 44
  • 65
  • switch off hwd acc and use clipPath – pskink Oct 24 '14 at 17:29
  • 1
    or use Canvas.saveLayer with SRC_IN porter duff mode – pskink Oct 24 '14 at 18:10
  • I found your answer (http://stackoverflow.com/questions/22200614/make-image-view-rounded-not-the-image) and your code is working for me right away. After hours of hassle. Post it as an answer and I'll gladly accept it! – Taig Oct 24 '14 at 18:47
  • exactly.. i completely forgot about that answer... ;) – pskink Oct 24 '14 at 18:54

1 Answers1

1

With pskink's answer (Make Image view rounded (not the image)) to a similar question I came to the following solution, based on the saveLayer approach (with some minor modifications).

@Override
public void onDraw( Canvas canvas )
{
    Paint paint1 = new Paint( Paint.ANTI_ALIAS_FLAG )
    Paint paint2 = new Paint()
    paint2.setXfermode( new PorterDuffXfermode( Mode.SRC_IN ) )

    Drawable drawable = getDrawable()
    RectF rectangle = new RectF()
    rectangle.set( drawable.getBounds() )

    getImageMatrix.mapRect( rectangle )
    rectangle.offset( getPaddingLeft(), getPaddingTop() )

    // Prevent radius being drawn out of canvas bounds
    rectangle.intersect( new RectF( 0, 0, canvas.getWidth(), canvas.getHeight() ) )

    int restore = canvas.saveLayer( rectangle, null, Canvas.ALL_SAVE_FLAG )
    canvas.drawRoundRect( rectangle, radius.getValue(), radius.getValue(), paint1 )
    canvas.saveLayer( rectangle, paint2, Canvas.ALL_SAVE_FLAG )
    super.onDraw( canvas )
    canvas.restoreToCount( restore )
}

The above code ignores object caching in class level and ignores NPE from getDrawable().

Community
  • 1
  • 1
Taig
  • 6,718
  • 4
  • 44
  • 65