Tratando de crear una pintura de borrador para lienzo
Estoy creando una aplicación de dibujo que utiliza la clase DrawingSurfaceView a continuación. En esa clase tengo una Paint Called eraserPaint que el usuario puede activar y desactivar .. Cuando en esa pintura se supone que borrar lo que nunca está en su camino. Pero en su lugar sólo está dibujando una línea negra ..
Cuando guardo el lienzo como un png transparente el borrador es correcto pero en la pantalla aparece negro ..
- Android: ¿es Paint.breakText (...) impreciso?
- Lona de Android - Dibuja un agujero
- Cómo dibujar una cadena Spanned con Canvas.drawText en Android
- Cambiar la intensidad de clarear / oscurecer en mapas de bits mediante PorterDuffXfermode en la clase Paint de Android
- Cambiar el color en Paint and Canvas en Android
Captura de pantalla desde el teléfono de EraserPaint utilizado para escribir "Erik" en blob
Guardado PNG de lienzo
EraserPaint se ve así:
eraserPaint = new Paint(); eraserPaint.setAlpha(0); eraserPaint.setColor(Color.TRANSPARENT); eraserPaint.setStrokeWidth(60); eraserPaint.setStyle(Style.STROKE); eraserPaint.setMaskFilter(null); eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); eraserPaint.setAntiAlias(true);
toda la clase
public KNDrawingSurfaceView(Context c, float width, float height, KNSketchBookActivity parent) { super(c); myWidth = width; myHeight = height; mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); _parent = parent; mEmboss = new EmbossMaskFilter(new float[] { 1, 1, 1 }, 0.4f, 6, 3.5f); tile = new Paint(); tileImage = BitmapFactory.decodeResource(getResources(), R.drawable.checkerpattern); shader = new BitmapShader(tileImage, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); tile.setShader(shader); mPath = new Path(); eraserPaint = new Paint(); eraserPaint.setAlpha(0x00); eraserPaint.setColor(Color.TRANSPARENT); eraserPaint.setStrokeWidth(60); eraserPaint.setStyle(Style.STROKE); //eraserPaint.setMaskFilter(null); eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); eraserPaint.setAntiAlias(true); mBitmapPaint = new Paint(Paint.DITHER_FLAG); mCanvas.drawRect(0, 0, myWidth, myHeight, tile); mCanvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { if (!_parent.isDrawerOpen()&&mPaint!=null) { Log.v("onDraw:", "curent paths size:" + paths.size()); //mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //canvas.drawPath(mPath, mPaint); for (int i=0;i< paths.size();i++) { tempPaint = paints.get(i); eraserPaint.setStrokeWidth(tempPaint.getStrokeWidth()); if(fills.get(i)){ tempPaint.setStyle(Style.FILL_AND_STROKE); eraserPaint.setStyle(Style.FILL_AND_STROKE); }else{ tempPaint.setStyle(Style.STROKE); eraserPaint.setStyle(Style.STROKE); } if(erasers.get(i)){ //tempPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPath(paths.get(i), eraserPaint); }else{ //tempPaint.setXfermode(null); canvas.drawPath(paths.get(i), tempPaint); } //canvas.drawPath(paths.get(i), tempPaint); } if(_parent.toggleFill.isChecked()){ mPaint.setStyle(Style.FILL_AND_STROKE); eraserPaint.setStyle(Style.FILL_AND_STROKE); }else{ mPaint.setStyle(Style.STROKE); eraserPaint.setStyle(Style.STROKE); } if(_parent.toggleErase.isChecked()){ //mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawPath(mPath, eraserPaint); }else{ //mPaint.setXfermode(null); canvas.drawPath(mPath, mPaint); } //canvas.drawPath(mPath, mPaint); } } public void onClickUndo() { if (paths.size() > 0) { undonePaths.add(paths.remove(paths.size() - 1)); undonePaints.add(paints.remove(paints.size() - 1)); undoneFills.add(fills.remove(fills.size() - 1)); undoneErasers.add(erasers.remove(erasers.size() - 1)); clearCanvasCache(); invalidate(); } else { } _parent.checkButtonStates(); } public void onClickRedo() { if (undonePaths.size() > 0) { paths.add(undonePaths.remove(undonePaths.size() - 1)); paints.add(undonePaints.remove(undonePaints.size() - 1)); fills.add(undoneFills.remove(undoneFills.size() - 1)); erasers.add(undoneErasers.remove(undoneErasers.size() - 1)); clearCanvasCache(); invalidate(); } else { } _parent.checkButtonStates(); } public void onClickClear() { paths.clear(); paints.clear(); fills.clear(); erasers.clear(); undoneFills.clear(); undonePaths.clear(); undonePaints.clear(); undoneErasers.clear(); clearCanvasCache(); invalidate(); _parent.checkButtonStates(); } public void saveDrawing() { FileOutputStream outStream = null; String fileName = "tempTag"; try { outStream = new FileOutputStream("/sdcard/" + fileName + ".png"); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream); outStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { } } private float mX, mY; private static final float TOUCH_TOLERANCE = 4; private void touch_start(float x, float y) { undonePaths.clear(); undonePaints.clear(); undoneFills.clear(); mPath.reset(); mPath.moveTo(x, y); mX = x; mY = y; } private void touch_move(float x, float y) { float dx = Math.abs(x - mX); float dy = Math.abs(y - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2); mX = x; mY = y; } } private void touch_up() { mPath.lineTo(mX, mY); // commit the path to our offscreen if(_parent.toggleErase.isChecked()){ mCanvas.drawPath(mPath, eraserPaint); erasers.add(true); paints.add(eraserPaint); }else{ mCanvas.drawPath(mPath, mPaint); erasers.add(false); paints.add(mPaint); } // kill this so we don't double draw paths.add(mPath); if(_parent.toggleFill.isChecked()){ fills.add(true); }else{ fills.add(false); } if(_parent.toggleErase.isChecked()){ erasers.add(true); }else{ erasers.add(false); } _parent.checkButtonStates(); mPath = new Path(); } @Override public boolean onTouchEvent(MotionEvent event) { if(mPaint==null &&!_parent._showingAlert){ _parent.showNoPaintAlert(); } if (!_parent.isDrawerOpen()&&mPaint!=null) { float x = event.getX(); float y = event.getY(); if (x > myWidth) { x = myWidth; } if (y > myHeight) { y = myHeight; } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touch_start(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: touch_move(x, y); invalidate(); break; case MotionEvent.ACTION_UP: touch_up(); invalidate(); break; } return true; } else { return true; } } public void clearCanvasCache() { mBitmap = Bitmap.createBitmap((int) myWidth, (int) myHeight, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); } }
Debo agregar que estoy agregando esta vista personalizada a un diseño relativo que tiene ese patrón a cuadros como la imagen de fondo.
POR FAVOR POR FAVOR, POR FAVOR ayuda .. necesito que la imagen de vista previa para no mostrar negro después de una pintura de borrador se utilizó .. lo necesito para mostrar el patrón a cuadros detrás .. Sé que el borrador está trabajando como las marcas de borrador negro salvo como transparente.
NUEVA NOTA
Yo estaba jugando y descubierto algo más que curioso. Experimentando, traté de cambiar de dibujo a la canvas
como pasó al método onDraw
y directamente a la tela que se estableció en el constructor llamado mCanvas
y noté que no dibujar en la medida de lo que podía ver .. por lo que agregó un registro a la onDraw
como así:
protected void onDraw(Canvas canvas) { Log.v("DRAWING SURFACE", "canvas:"+canvas+" mCanvas:"+mCanvas);
Que escupe
06-21 11:10:43.994: V/DRAWING SURFACE(4532): canvas:android.view.Surface$CompatibleCanvas@42a8c030 mCanvas:android.graphics.Canvas@431df180
- superposición de texto de pintura de Android
- Significado de algunas constantes de Paint en Android
- Nueva línea al pintar un texto en una imagen
- Dibujar la línea en la pintura de los dedos quitar la imagen dibujada previamente
- Problema con la pintura de Android en diferentes API
- Android: measureText () Retorno de píxeles basados en píxeles escalados
- ¿Cómo configurar un filtro de color para XWalkView? (Resuelto)
Tuve este mismo problema con mi aplicación. Incluso probé el código de ejemplo de "pintura con dedos" y todavía tenía el mismo problema. Nunca pude tener el borrador de trabajo como un camino, pero pude encontrar una solución. En lugar de dibujar un camino cuando borro, dibujo un círculo (podría ser de cualquier forma) cuando el usuario pone su dedo hacia abajo o hay un evento "mover":
case MotionEvent.ACTION_DOWN: mPaint.setStrokeWidth(25); mPaint.setXfermode(new PorterDuffXfermode( PorterDuff.Mode.CLEAR)); mCanvas.drawCircle(x, y, 10, mPaint); isErase = true; invalidate(); } touch_start(x, y); invalidate(); break; case MotionEvent.ACTION_MOVE: if(isErase) { mCanvas.drawCircle(x, y, 20, mPaint); } else{ touch_move(x, y); }invalidate(); break;
Tomará un cierto tiempo incorporar esto en su código, pero le garantizo que tomará menos tiempo que la cantidad de tiempo que usted ha pasado el intentar solucionar este problema. Puedo enviarte más de mi PaintView si crees que sería útil.
El mismo problema encontrado, probado todas las otras soluciones encontradas, no hay suerte.
Pero tengo una solución. Puede agregar un mapa de bits para almacenar los trazos.
public void init(int width, int height) { Log.i(TAG,"init with "+width+"x"+height); foreground = Bitmap.createBitmap(width, height, Config.ARGB_8888); cacheCanvas = new Canvas(); cacheCanvas.setBitmap(foreground); }
Siempre que haya algún toque, registre la carrera con la pintura actual y el ancho de carrera actual. (La pintura podría ser cualquier color, incluyendo la pintura del borrador)
Y luego anular el método onDraw (Canvas). Como el mapa de bits admite el borrador mientras el lienzo no, podemos dibujar primero la imagen resultante en el mapa de bits primero y, a continuación, dibujar el mapa de bits en el lienzo.
@Override protected void onDraw(Canvas canvas) { // Log.i(TAG,"onDraw called"); synchronized (strokes) { if (strokes.size() > 0) { for (Stroke s : strokes) { cacheCanvas.drawPath(s.path, s.color); } canvas.drawBitmap(foreground, 0, 0, null); strokes.clear(); } } }
FYI, si el mapa de bits en primer plano es muy grande, el rendimiento será bajo. Para resolver esto, deberíamos invalidar sólo el área que el último dedo toca alterado.
Esto es sólo una suposición: podría estar relacionado con la aceleración de hardware. Intente desactivar la aceleración de hardware. Si eso ayuda, puede crear un mapa de bits del tamaño de la vista, dibujar todas sus cosas a ese mapa de bits y, a continuación, dibujar el mapa de bits en el lienzo de la vista.
Para que el lienzo se borre e invalide, debe establecer el setXfermode de su lienzo como null. Compruebe la última línea del código.
if(view.getId()==R.id.erase_btn) { erase_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onDraw.setErase(true); } } } public void setErase(boolean isErase){ erase=isErase; if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); else drawPaint.setXfermode(null); }
Puede usar una variable booleana mientras elige borrador (es decir, isEraser = true
) y en onDraw()
, puede dibujar ruta si no es borrador.
@Override protected void onDraw(Canvas canvas) { if(!isEraser ){ canvas.drawPath(mPath, mPaint); } }