Draw on Picture in android

17,666

You can avoid counting coordinates of other UI items in your sample by creation your own ImageView. Try this code for Activity:

public class DrawOnBitmapActivity extends Activity implements OnClickListener
    {

DrawableImageView choosenImageView;
Button choosePicture;
Button savePicture;

Bitmap bmp;
Bitmap alteredBitmap;

@Override
public void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    choosenImageView = (DrawableImageView) this.findViewById(R.id.ChoosenImageView);
    choosePicture = (Button) this.findViewById(R.id.ChoosePictureButton);
    savePicture = (Button) this.findViewById(R.id.SavePictureButton);

    savePicture.setOnClickListener(this);
    choosePicture.setOnClickListener(this);
}

public void onClick(View v) 
{
    if (v == choosePicture) 
    {
        Intent choosePictureIntent = new Intent(
                Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(choosePictureIntent, 0);
    } 
    else if (v == savePicture) 
    {
        if (alteredBitmap != null) 
        {
            ContentValues contentValues = new ContentValues(3);
            contentValues.put(Media.DISPLAY_NAME, "Draw On Me");

            Uri imageFileUri = getContentResolver().insert(
                    Media.EXTERNAL_CONTENT_URI, contentValues);
            try {
                OutputStream imageFileOS = getContentResolver()
                        .openOutputStream(imageFileUri);
                alteredBitmap
                        .compress(CompressFormat.JPEG, 90, imageFileOS);
                Toast t = Toast
                        .makeText(this, "Saved!", Toast.LENGTH_SHORT);
                t.show();

            } catch (Exception e) {
                Log.v("EXCEPTION", e.getMessage());
            }
        }
    }
}

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());

            choosenImageView.setNewImage(alteredBitmap, bmp);
        } 
        catch (Exception e) {
            Log.v("ERROR", e.toString());
        }
    }
}
}

You have to change activity_main layout slightly:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Choose Picture" android:id="@+id/ChoosePictureButton"/>
    <ru.pristalovpavel.drawonimage.DrawableImageView android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:id="@+id/ChoosenImageView">
    </ru.pristalovpavel.drawonimage.DrawableImageView>
     <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Save Picture" android:id="@+id/SavePictureButton"/>
</LinearLayout>

and your custom ImageView:

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;
    }
}

All source code of the project in eclipse: link

UPDATE:

new source code for DrawableImageView!

More information is in my blog.

Share:
17,666
user782104
Author by

user782104

php

Updated on June 12, 2022

Comments

  • user782104
    user782104 over 1 year

    I was working on a custom imageview that can draw line on it, the problem is that the drawing area size is not exactly with the bitmap size.

    For example, in the other app, it looks like:

    enter image description here

    However, in my app, it looks like

    enter image description here

    Here is my program, which seems the bitmap is not fit with the canvas. Thanks for helping

       public class DrawingView extends View {
    
        //drawing path
        private Path drawPath;
        //drawing and canvas paint
        private Paint drawPaint, canvasPaint;
        //initial color
        private int paintColor = 0xFF660000;
        //canvas
        private Canvas drawCanvas;
        //canvas bitmap
        private Bitmap canvasBitmap;
    
    
        public DrawingView(Context context, AttributeSet attrs){
            super(context, attrs);
            setupDrawing();
        }
    
        //setup drawing
        private void setupDrawing(){
    
            //prepare for drawing and setup paint stroke properties
            drawPath = new Path();
            drawPaint = new Paint();
            drawPaint.setColor(paintColor);
            drawPaint.setAntiAlias(true);
            drawPaint.setStrokeWidth(15.0f);
            drawPaint.setStyle(Paint.Style.STROKE);
            drawPaint.setStrokeJoin(Paint.Join.ROUND);
            drawPaint.setStrokeCap(Paint.Cap.ROUND);
            canvasPaint = new Paint(Paint.DITHER_FLAG);
        }
    
        //size assigned to view
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            drawCanvas = new Canvas(canvasBitmap);
        }
    
        //draw the view - will be called after touch event
        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), 0, 0, canvasPaint);
            canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
            canvas.drawPath(drawPath, drawPaint);
        }
    
        //register user touches as drawing action
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            float touchX = event.getX();
            float touchY = event.getY();
            //respond to down, move and up events
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                drawPath.moveTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_MOVE:
                drawPath.lineTo(touchX, touchY);
                break;
            case MotionEvent.ACTION_UP:
                drawPath.lineTo(touchX, touchY);
                drawCanvas.drawPath(drawPath, drawPaint);
                drawPath.reset();
                break;
            default:
                return false;
            }
            //redraw
            invalidate();
            return true;
    
        }
    
        //update color
        public void setColor(String newColor){
            invalidate();
            paintColor = Color.parseColor(newColor);
            drawPaint.setColor(paintColor);
        }
    
        //start new drawing
        public void startNew(){
            drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
            invalidate();
        }
    }
    

    And I found the similar tutorial code, the problem is that the touch event has bug, it count in the action bar and the rest UI element so the touching is weird. Recommend to have a look

    http://www.java2s.com/Code/Android/2D-Graphics/DrawonPictureandsave.htm

    So, the goal of this topic , is the solution of

    1) draw-able image

    2) zoom-able and pan-able(can use library) (when active zoom , zoom, when inactive zoom , draw)

    can reference the screenshot 1 for the idea

    Thanks a lot for helping