Drawing on top of an image in Android’s ImageView

This is a topic for which I found on the Internet a lot of ideas but they were more workarounds for special situations than general solutions.

One of my apps contained an ImageView widget into which I had to load a series of pictures one after the other at runtime. The pictures were of different size, some smaller and some larger than the widget’s size, so the images would either be centered or automatically scaled down by the widget. The challenge was to mark certain areas in the picture with a coloured rectangle dynamically created at run time and adjusted using the coordinates of the original, unscaled image.

The general recommendation on the Internet was to subclass ImageView and overwrite OnDraw with a method that first calls the original OnDraw method of ImageView with the canvas that is provided as parameter to OnDraw and then draws into this canvas on top of the already drawn image.

I am meanwhile quite sure that this works only under certain circumstances, for example when you are sure, your image will not be scaled. The problem lies in the provided canvas. The original onDraw method applies a certain transformation matrix to the canvas before it draws the image into the canvas and restores the canvas in its previous state afterwards. This matrix is stored in a private member variable of ImageView and for whatever reason it is not always the same matrix as the one returned from getImageMatrix() calls. Using the debugger I have seen cases where getImageMatrix returned a non-null matrix where onDraw used a null Matrix and therefore did no do any transformation to the canvas at all. So there is no general reliable way to calculate the coordinates for anything you want to draw on top of what ImageView has drawn.

Therefore I used a different approach:

  1. Create a new image bitmap and attach a brand new canvas to it so that the bitmap and the canvas use the same coordinate system.
  2. Draw the image bitmap into the canvas.
  3. Draw everything else you want into the canvas (the rectangles in my case).
  4. Attach the canvas to the ImageView.

Here is the code snippet:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;

ImageView myImageView = ...
Bitmap myBitmap = ...
Paint myRectPaint = ...
int x1 = ...
int y1 = ...
int x2 = ...
int y2 = ...

//Create a new image bitmap and attach a brand new canvas to it
Bitmap tempBitmap = Bitmap.createBitmap(myBitmap.getWidth(), myBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);

//Draw the image bitmap into the cavas
tempCanvas.drawBitmap(myBitmap, 0, 0, null);

//Draw everything else you want into the canvas, in this example a rectangle with rounded edges
tempCanvas.drawRoundRect(new RectF(x1,y1,x2,y2), 2, 2, myPaint);

//Attach the canvas to the ImageView
myImageView.setImageDrawable(new BitmapDrawable(getResources(), tempBitmap));

5 thoughts on “Drawing on top of an image in Android’s ImageView

  1. My code snippet shows you the main “ingredients” for your activity: An ImageView, a Canvas and a Bitmap.

    Create an ImageView for your activity the usual way, there is plenty of sample code for this available on the internet.

    What you then have to do is to load the picture from the SD Card into a Bitmap (BitmapFactory.decodeFile does this for you) and then use my code snippet to create a new Canvas, draw the Bitmap and your circles into the Canvas and attach the canvas to your ImageView.

    Think of the canvas as a piece of paper on which you can make a drawing by painting bitmaps, lines, circles etc. on it. As soon as you have attached the Canvas to the ImageView the drawing of the paper appears within the ImageView.

    I hope this helps a bit.

    Jörg

  2. sir i am working on a project in which i am drawing diff. shapes like rect,oval
    in canvas for which i have a class which extends view.
    problem is that i want to draw over an image but dont know how to merge image in the class which extends view..
    please help me

  3. You actually attach tempBitmap and not tempCanvas to the ImageView. Your comments however say, that you attach the canvas to the ImageView.

  4. thanks for your code , i worked on project to draw points over image just i want to know what i put in myBitmap declare ?
    i assign it to null and code not working

  5. Great , very helping.
    I just want to know if I am drawing a number of the rectangle on my image view. How do I get click events on those rectangles?

Leave a Reply

Your email address will not be published. Required fields are marked *