0

I am trying to implement an application to get an image from the device and add it to the canvas then start drawing on it using brush and eraser (like snapchat idea) I used Drawing app as a base

http://code.tutsplus.com/series/create-a-drawing-app-on-android--cms-704

My problem for now is that when I draw on the bitmap it start drawing but when I finished and touch up the drawing disappear.

this is a video for the problem

https://vid.me/rgnF (try to mute the sound there is some noise :) )

‏any help would be appreciated. Thank you

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 public Bitmap canvasBitmap; //brush sizes private float brushSize, lastBrushSize; //erase flag private boolean erase=false; public DrawingView(Context context, AttributeSet attrs){ super(context, attrs); setupDrawing(); } //setup drawing private void setupDrawing(){ //prepare for drawing and setup paint stroke properties brushSize = getResources().getInteger(R.integer.medium_size); lastBrushSize = brushSize; drawPath = new Path(); drawPaint = new Paint(); drawPaint.setColor(paintColor); drawPaint.setAntiAlias(true); drawPaint.setStrokeWidth(brushSize); 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) { super.onDraw(canvas); canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); canvas.drawPath(drawPath, drawPaint); } @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); } //set brush size public void setBrushSize(float newSize){ float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, newSize, getResources().getDisplayMetrics()); brushSize=pixelAmount; drawPaint.setStrokeWidth(brushSize); } //get and set last brush size public void setLastBrushSize(float lastSize){ lastBrushSize=lastSize; } public float getLastBrushSize(){ return lastBrushSize; } //set erase true or false public void setErase(boolean isErase){ erase=isErase; if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); else drawPaint.setXfermode(null); } //start new drawing public void startNew(){ drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR); invalidate(); } 

}

public class MainActivity extends Activity implements OnClickListener { //custom drawing view private DrawingView drawView; //buttons private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn; //sizes private float smallBrush, mediumBrush, largeBrush; Button mBtnPick; int mWidth; int mHeight; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWidth = mHeight = 0; //get drawing view drawView = (DrawingView)findViewById(R.id.drawing); //get the palette and first color button LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors); currPaint = (ImageButton)paintLayout.getChildAt(0); currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); //sizes from dimensions smallBrush = getResources().getInteger(R.integer.small_size); mediumBrush = getResources().getInteger(R.integer.medium_size); largeBrush = getResources().getInteger(R.integer.large_size); //draw button drawBtn = (ImageButton)findViewById(R.id.draw_btn); drawBtn.setOnClickListener(this); //set initial size drawView.setBrushSize(mediumBrush); //erase button eraseBtn = (ImageButton)findViewById(R.id.erase_btn); eraseBtn.setOnClickListener(this); //new button newBtn = (ImageButton)findViewById(R.id.new_btn); newBtn.setOnClickListener(this); //save button saveBtn = (ImageButton)findViewById(R.id.save_btn); saveBtn.setOnClickListener(this); // Getting reference to Button "Pick an Image" mBtnPick = (Button) findViewById(R.id.button); // Setting OnClickListener for the button mBtnPick.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent i = new Intent(); i.setType("image/*"); i.setAction(Intent.ACTION_GET_CONTENT); Intent customChooserIntent = Intent.createChooser(i, "Pick an image"); startActivityForResult(customChooserIntent, 10); } }); if(savedInstanceState!=null){ mWidth = savedInstanceState.getInt("width"); mHeight = savedInstanceState.getInt("height"); Bitmap bitmap = savedInstanceState.getParcelable("bitmap"); if(bitmap!=null){ drawView.canvasBitmap=bitmap; } } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } //user clicked paint public void paintClicked(View view){ //use chosen color //set erase false drawView.setErase(false); drawView.setBrushSize(drawView.getLastBrushSize()); if(view!=currPaint){ ImageButton imgView = (ImageButton)view; String color = view.getTag().toString(); drawView.setColor(color); //update ui imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed)); currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint)); currPaint=(ImageButton)view; } } @Override public void onClick(View view){ if(view.getId()==R.id.draw_btn){ //draw button clicked final Dialog brushDialog = new Dialog(this); brushDialog.setTitle("Brush size:"); brushDialog.setContentView(R.layout.brush_chooser); //listen for clicks on size buttons ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush); smallBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(false); drawView.setBrushSize(smallBrush); drawView.setLastBrushSize(smallBrush); brushDialog.dismiss(); } }); ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush); mediumBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(false); drawView.setBrushSize(mediumBrush); drawView.setLastBrushSize(mediumBrush); brushDialog.dismiss(); } }); ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush); largeBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(false); drawView.setBrushSize(largeBrush); drawView.setLastBrushSize(largeBrush); brushDialog.dismiss(); } }); //show and wait for user interaction brushDialog.show(); } else if(view.getId()==R.id.erase_btn){ //switch to erase - choose size final Dialog brushDialog = new Dialog(this); brushDialog.setTitle("Eraser size:"); brushDialog.setContentView(R.layout.brush_chooser); //size buttons ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush); smallBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(true); drawView.setBrushSize(smallBrush); brushDialog.dismiss(); } }); ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush); mediumBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(true); drawView.setBrushSize(mediumBrush); brushDialog.dismiss(); } }); ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush); largeBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setErase(true); drawView.setBrushSize(largeBrush); brushDialog.dismiss(); } }); brushDialog.show(); } else if(view.getId()==R.id.new_btn){ //new button AlertDialog.Builder newDialog = new AlertDialog.Builder(this); newDialog.setTitle("New drawing"); newDialog.setMessage("Start new drawing (you will lose the current drawing)?"); newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which){ drawView.startNew(); dialog.dismiss(); } }); newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which){ dialog.cancel(); } }); newDialog.show(); } else if(view.getId()==R.id.save_btn){ //save drawing AlertDialog.Builder saveDialog = new AlertDialog.Builder(this); saveDialog.setTitle("Save drawing"); saveDialog.setMessage("Save drawing to device Gallery?"); saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which){ //save drawing drawView.setDrawingCacheEnabled(true); //attempt to save String imgSaved = MediaStore.Images.Media.insertImage( getContentResolver(), drawView.getDrawingCache(), UUID.randomUUID().toString()+".png", "drawing"); //feedback if(imgSaved!=null){ Toast savedToast = Toast.makeText(getApplicationContext(), "Drawing saved to Gallery!", Toast.LENGTH_SHORT); savedToast.show(); } else{ Toast unsavedToast = Toast.makeText(getApplicationContext(), "Oops! Image could not be saved.", Toast.LENGTH_SHORT); unsavedToast.show(); } drawView.destroyDrawingCache(); } }); saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){ public void onClick(DialogInterface dialog, int which){ dialog.cancel(); } }); saveDialog.show(); } } // Courtesy : developer.android.com/training/displaying-bitmaps/load-bitmap.html public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // Calculate ratios of height and width to requested height and width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will guarantee // a final image with both dimensions larger than or equal to the // requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; } return inSampleSize; } private Bitmap getBitmapFromUri(Uri data){ Bitmap bitmap = null; // Starting fetch image from file InputStream is=null; try { is = getContentResolver().openInputStream(data); // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // BitmapFactory.decodeFile(path, options); BitmapFactory.decodeStream(is, null, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, mWidth, mHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; is = getContentResolver().openInputStream(data); bitmap = BitmapFactory.decodeStream(is,null,options); if(bitmap==null){ Toast.makeText(getBaseContext(), "Image is not Loaded",Toast.LENGTH_SHORT).show(); return null; } is.close(); }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch(NullPointerException e){ e.printStackTrace(); } return bitmap; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { // TODO Auto-generated method stub super.onActivityResult(requestCode, resultCode, intent); if (requestCode == 10 && resultCode == RESULT_OK && null != intent) { Uri data = intent.getData(); Bitmap bitmap = getBitmapFromUri(data); if(bitmap!=null){ drawView.canvasBitmap=bitmap; } } } @Override public void onWindowFocusChanged(boolean hasFocus) { // TODO Auto-generated method stub super.onWindowFocusChanged(hasFocus); mWidth = drawView.getWidth(); mHeight = drawView.getHeight(); } @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt("width", mWidth); outState.putInt("height", mHeight); if(drawView.canvasBitmap!=null){ outState.putParcelable("bitmap", drawView.canvasBitmap); } super.onSaveInstanceState(outState); } 

}

2 Answers 2

1

What you are doing is getting canvas of image via drawCanvas object and drawing it on canvas and then drawing path on it.

Try another way, get canvas of image via drawCanvas object and draw path on it and then draw resultant image on canvas. See following code

// draw path on canvasBitmap drawCanvas.drawPath(drawPath, drawPaint); //Now draw canvasBitmap on canvas canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint); //canvas.drawPath(drawPath, drawPaint); // No need for this line 

What actually happening is that you draw path on canvas on ACTION_UP and reset path object, see following code of yours

 case MotionEvent.ACTION_UP: drawPath.lineTo(touchX, touchY); drawCanvas.drawPath(drawPath, drawPaint); drawPath.reset(); 

According to Android what reset() do is as follows:

Clear any lines and curves from the path, making it empty.

After above code you call invalidate(); which clears canvas and redraw it with empty path object because you already have called drawPath.reset(). This is the main reason why lines are disappearing.

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your reply but unfortunately this doesn't work it draws nothing on the image
0

Finally I solved the problem by adding the following method to the DrawingView class

public void setPicture (Bitmap bitmap) { setBackgroundDrawable(new BitmapDrawable(bitmap)); } 

then I replaced every line contain drawView.canvasBitmap=bitmap; by drawView.setPicture(bitmap);

and every thing works fine :)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.