4

I'm trying to draw some points on an ImageView which also features DRAG and ZOOM capabilities.

My implementation works fine if the image is not modified ( zoomed or dragged ), but if I apply these types of transformations, it won't draw correctly anymore. Instead it will hold the initial frame as reference and will draw the dots as if it weren't modified.

This is what the image looks like right after choosing it from the gallery and drawing a green dot by tapping on it.

unaltered image

This is what the image looks like after zooming it in and dragging it to the side. As you can see, if I tap inside the initial frame, it will draw the dot inside the image as if it were unscaled.

altered image

Bellow is the code (select image from gallery, onTouch method and the actual drawing).

public void onClick(View v) {

    if (v.getId()==R.id.putPoint){
        drawPath=true;
    }
    else
    if (v == choosePicture) {
        Intent choosePictureIntent = new Intent(
                Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(choosePictureIntent, 0);
    }
}

protected void onActivityResult(int requestCode, int resultCode,
                                Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    if (resultCode == RESULT_OK) {
        Uri imageFileUri = intent.getData();
        try {
            BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
            bmpFactoryOptions.inJustDecodeBounds = true;
            bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
                    imageFileUri), null, bmpFactoryOptions);

            bmpFactoryOptions.inJustDecodeBounds = false;
            bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(
                    imageFileUri), null, bmpFactoryOptions);


            alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp
                    .getHeight(), bmp.getConfig());

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

            choosenImageView.setImageBitmap(alteredBitmap);
            choosenImageView.setOnTouchListener(this);
        } catch (Exception e) {
            Log.v("ERROR", e.toString());
        }
    }
}
public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction();
    ImageView view = (ImageView) v;
    if(drawPath) {
    //I use this flag to enable drawing mode

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downx = event.getX();
                downy = event.getY();
                canvas.drawCircle(downx, downy, radius,paint);
                choosenImageView.invalidate();
                drawPath=false;
                break;

        }
        return true;
    }
    else{
        //if the drawing mode is not enable I can zoom and drag the image
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                savedMatrix.set(matrix);
                start.set(event.getX(), event.getY());
                mode = DRAG;
                lastEvent = null;
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                oldDist = spacing(event);
                if (oldDist > 10f) {
                    savedMatrix.set(matrix);
                    midPoint(mid, event);
                    mode = ZOOM;
                }
                lastEvent = new float[4];
                lastEvent[0] = event.getX(0);
                lastEvent[1] = event.getX(1);
                lastEvent[2] = event.getY(0);
                lastEvent[3] = event.getY(1);
                d = rotation(event);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_POINTER_UP:
                mode = NONE;
                lastEvent = null;

                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == DRAG) {
                    matrix.set(savedMatrix);
                    float dx = event.getX() - start.x;
                    float dy = event.getY() - start.y;
                    matrix.postTranslate(dx, dy);

                } else if (mode == ZOOM) {
                    float newDist = spacing(event);
                    if (newDist > 10f) {
                        matrix.set(savedMatrix);
                        float scale = (newDist / oldDist);
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                }
                break;
        }

        view.setImageMatrix(matrix);
        return true;

    }
}

}

My goal is to be able to tap on the image(zommed or dragged) and see the points drawn correctly.

Community
  • 1
  • 1

1 Answers1

0

See: How do I get touch coordinates with respect to canvas after scaling and translating?

The easiest and most consistent way to do this is to apply the inverse matrix you used to modify the view modify the MotionEvent. There's two commands you need to know:

event.transform(invertMatrix);

and:

invertMatrix = new Matrix(viewMatrix);
invertMatrix.invert(invertMatrix);

Basically you do the opposite of what you did to the view to the touches. So the touches go to the scene space.

Tatarize
  • 9,577
  • 4
  • 56
  • 59