Android: Cómo implementar el dibujo en la parte superior de la imagen

El objetivo es poder escribir / dibujar / dibujar algo encima de la imagen tomada y también borrar sin destruir la imagen haciendo que la imagen permanezca intacta, y al guardar la imagen el dibujo y la imagen en el fondo estarían incluidos en la imagen Salida final

He construido una aplicación que toma una foto y luego la envía a una nueva actividad para la vista previa y la edición donde debería ser capaz de dibujar sobre la imagen como un círculo o algunas líneas. Pude hacer esto creando el mapa de bits y pasándolo a través del nuevo constructor de Canvas ().

El problema con esto es que podría escribir en la imagen, pero cuando uso el modo de borrado la imagen también se borra, me gustaría implementar algo que me dejaría borrar sin destruir la imagen de fondo, y al mismo tiempo la imagen en El fondo todavía se incluiría cuando ahorre la imagen finalmente.

El código para mi vista está abajo.

import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Shader; import android.util.AttributeSet; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; public class DrawingView extends View { //drawing path private Path drawPath; //drawing and canvas paint private Paint drawPaint, canvasPaint; //initial color private int paintColor = 0xFF660000, paintAlpha = 255; //canvas private Canvas drawCanvas; //canvas bitmap private Bitmap canvasBitmap; //brush sizes private float brushSize, lastBrushSize; //erase flag private boolean erase=false; Bitmap bg; 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); Resources res = getResources(); Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.background); bg = bitmap.copy(Bitmap.Config.ARGB_8888, true); } //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(bg); } //draw the view - will be called after touch event @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(bg, 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(); //check whether color value or pattern name if(newColor.startsWith("#")){ paintColor = Color.parseColor(newColor); drawPaint.setColor(paintColor); drawPaint.setShader(null); } else{ //pattern int patternID = getResources().getIdentifier( newColor, "drawable", "com.example.drawingfun"); //decode Bitmap patternBMP = BitmapFactory.decodeResource(getResources(), patternID); //create shader BitmapShader patternBMPshader = new BitmapShader(patternBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); //color and shader drawPaint.setColor(0xFFFFFFFF); drawPaint.setShader(patternBMPshader); } } //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; drawPaint.setColor(Color.parseColor("#FFFFFF")); if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); else drawPaint.setXfermode(null); drawPaint.setColor(paintColor); } //start new drawing public void startNew(){ drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR); invalidate(); } //return current alpha public int getPaintAlpha(){ return Math.round((float)paintAlpha/255*100); } //set alpha public void setPaintAlpha(int newAlpha){ paintAlpha=Math.round((float)newAlpha/100*255); drawPaint.setColor(paintColor); drawPaint.setAlpha(paintAlpha); } } 

MainActivity.java es este

 import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.provider.MediaStore; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import android.widget.Toast; import java.util.UUID; public class MainActivity extends Activity implements OnClickListener { //custom drawing view private DrawingView drawView; //buttons private ImageButton currPaint, drawBtn, eraseBtn, newBtn, saveBtn, opacityBtn; //sizes private float smallBrush, mediumBrush, largeBrush; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //get drawing view drawView = (DrawingView)findViewById(R.id.drawing); // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // drawView.setBackground(getResources().getDrawable(R.drawable.background, null)); // } // else // drawView.setBackground(getResources().getDrawable(R.drawable.background)); //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(smallBrush); //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); //opacity opacityBtn = (ImageButton)findViewById(R.id.opacity_btn); opacityBtn.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. // getMenuInflater().inflate(R.menu.main, menu); return true; } //user clicked paint public void paintClicked(View view){ //use chosen color //set erase false drawView.setErase(false); drawView.setPaintAlpha(100); 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(); } else if(view.getId()==R.id.opacity_btn){ //launch opacity chooser final Dialog seekDialog = new Dialog(this); seekDialog.setTitle("Opacity level:"); seekDialog.setContentView(R.layout.opacity_chooser); //get ui elements final TextView seekTxt = (TextView)seekDialog.findViewById(R.id.opq_txt); final SeekBar seekOpq = (SeekBar)seekDialog.findViewById(R.id.opacity_seek); //set max seekOpq.setMax(100); //show current level int currLevel = drawView.getPaintAlpha(); seekTxt.setText(currLevel+"%"); seekOpq.setProgress(currLevel); //update as user interacts seekOpq.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { seekTxt.setText(Integer.toString(progress)+"%"); } @Override public void onStartTrackingTouch(SeekBar seekBar) {} @Override public void onStopTrackingTouch(SeekBar seekBar) {} }); //listen for clicks on ok Button opqBtn = (Button)seekDialog.findViewById(R.id.opq_ok); opqBtn.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { drawView.setPaintAlpha(seekOpq.getProgress()); seekDialog.dismiss(); } }); //show dialog seekDialog.show(); } } } 

Usted ha implementado todas las cosas de la manera correcta, pero sólo quiero sugerirle que pruebe el siguiente código, puede ser que le ayudaría.

 public void clearCanvas() { drawPath.reset(); invalidate(); } 

Intente este método en lugar de setErase (), El método anterior se utiliza para borrar la ruta que ha creado mediante el toque. Puede restablecer todos los valores a valores predeterminados en este método.

Lo que resolvió mi problema fue sólo para configurar la imagen como el fondo de la vista de la superficie a través de setBackgroundDrawable. Luego, al guardarlo sólo tenía que obtener la caché de dibujo del lienzo que luego incluye la imagen de fondo.

  • Camera2 api convertir yuv420 a rgb verde hacia fuera
  • La carga de Android se puede dibujar mediante programación y cambiar su tamaño
  • Recuperando sólo imágenes de la galería al disparar la intención del selector de imágenes de Android
  • ¿Cómo descargar la imagen más rápido en android Volley / Picasso / Glide cualquier otro?
  • Cómo almacenar (imagen de mapa de bits) y recuperar la imagen de la base de datos sqlite en android?
  • Combinar dos imágenes en android java
  • Imagen de fondo - cómo repetir la imagen como fondo en lugar de estirar
  • Aplicación lenta con imagen de fondo
  • Cómo hacer una imagen de la partición de Android a su PC
  • Android: ¿Realiza una parte de una imagen repetible en android?
  • Reaccione imágenes locales nativas con URI en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.