Tag Archives: draw on picture

Drawing on image in Android

The task of drawing by fingers on already existing image meets quite often: if you need to select complex image fragment, sometimes – to emphasize or cross out something, to add the hand-written text or a smilie.

All your app needs to do is to intercept all user touch events and draw lines between two adjacent positions. But the details matter. If your source bitmap size is less, than your device screen size, everything is normal. You can just use the code below:

public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    switch (action) {
    case MotionEvent.ACTION_DOWN:
      downx = event.getX();
      downy = event.getY();
      break;
    case MotionEvent.ACTION_MOVE:
      upx = event.getX();
      upy = event.getY();
      canvas.drawLine(downx, downy, upx, upy, paint);
      choosenImageView.invalidate();
      downx = upx;
      downy = upy;
      break;
    case MotionEvent.ACTION_UP:
      upx = event.getX();
      upy = event.getY();
      canvas.drawLine(downx, downy, upx, upy, paint);
      choosenImageView.invalidate();
      break;
    case MotionEvent.ACTION_CANCEL:
      break;
    default:
      break;
    }
    return true;
  }
}

Source

But if you want to edit a huge image, than scales to your view port, you can get such result:

A complete description of this case is available on StackOverFlow

The only one solution is Matrix, that holds a 3×3 matrix for transforming coordinates from the original bitmap to your view port. Let’s create custom ImageView with proper drawing on scaled pictures:

public class DrawableImageView extends ImageView implements OnTouchListener
{
    float downx = 0;
    float downy = 0;
    float upx = 0;
    float upy = 0;
    
    Canvas canvas;
    Paint paint;
    Matrix matrix;
    
    public DrawableImageView(Context context)
    {
        super(context);
        setOnTouchListener(this);
    }
    
    public DrawableImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        setOnTouchListener(this);
    }

    public DrawableImageView(Context context, AttributeSet attrs,
            int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        setOnTouchListener(this);
    }

    public void setNewImage(Bitmap alteredBitmap, Bitmap bmp)
    {
        canvas = new Canvas(alteredBitmap );
        paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(5);
        matrix = new Matrix();
        canvas.drawBitmap(bmp, matrix, paint);

        setImageBitmap(alteredBitmap);
    }
    
    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        int action = event.getAction();
        
        switch (action)
        {
        case MotionEvent.ACTION_DOWN:
            downx = getPointerCoords(event)[0];//event.getX();
            downy = getPointerCoords(event)[1];//event.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            upx = getPointerCoords(event)[0];//event.getX();
            upy = getPointerCoords(event)[1];//event.getY();
            canvas.drawLine(downx, downy, upx, upy, paint);
            invalidate();
            downx = upx;
            downy = upy;
            break;
        case MotionEvent.ACTION_UP:
            upx = getPointerCoords(event)[0];//event.getX();
            upy = getPointerCoords(event)[1];//event.getY();
            canvas.drawLine(downx, downy, upx, upy, paint);
            invalidate();
            break;
        case MotionEvent.ACTION_CANCEL:
            break;
        default:
            break;
        }
        return true;
    }

    final float[] getPointerCoords(MotionEvent e)
    {
        final int index = e.getActionIndex();
        final float[] coords = new float[] { e.getX(index), e.getY(index) };
        Matrix matrix = new Matrix();
        getImageMatrix().invert(matrix);
        matrix.postTranslate(getScrollX(), getScrollY());
        matrix.mapPoints(coords);
        return coords;
    }
}

Every time when we need a proper coordinates of touch item, we ask the current transformation matrix about them in getPointerCoords method. And it works very well 🙂

More information and sample project see here.