Borrar una imagen girada en Android no muestra borrar la ruta correcta

Estamos construyendo una aplicación de Android que implica la edición de imágenes. Algunas de las características incluyen girar una imagen y borrar parte de la imagen.

Estamos utilizando la siguiente biblioteca: https://github.com/nimengbo/StickerView

Hemos creado correctamente una función para rotar y borrar la imagen. Sin embargo, cuando intentamos realizar las siguientes acciones:

  1. Rotar una imagen en un cierto grado.
  2. A continuación, borrar la imagen.

Hemos encontrado el siguiente error:

  1. Cuando intentamos borrar la imagen girada, el camino borrado no reflejaba el camino que nuestro dedo trazaba en la pantalla.

Introduzca aquí la descripción de la imagen

A partir de la imagen anterior, la línea amarilla es el movimiento real del dedo (directamente hacia abajo vertical a través de la etiqueta). Pero, el camino borrado resultante se encontró que era diagonal.

Este problema sólo existe cuando se gira la imagen. No existe cuando la imagen no se gira.

Después de depurar más, tenemos algunos supuestos de los problemas anteriores:

  1. Debido a la imagen girada, se cambia la posición de absolución xey. Por lo tanto, la trayectoria no refleja el camino correcto por las rutas del tacto.

¿Cómo podemos asegurar que la trayectoria sigue haciendo referencia al camino correcto en lo que el dedo está tocando incluso después de ser girado?

Aquí está el código que tenemos en nuestra clase StickerView.java que amplía la clase ImageView .

OnTouchEvent

 @Override public boolean onTouchEvent(MotionEvent event) { int action = MotionEventCompat.getActionMasked(event); float[] pointXY = new float[2]; pointXY = getAbsolutePosition(event.getX(0),event.getY(0)); float xPoint = pointXY[0]; float yPoint = pointXY[1]; switch (action) { case MotionEvent.ACTION_DOWN: // first touch // if it is inside the image if (isInBitmap(event)) { // set isInSide to true isInSide = true; // if it is a scratch if(doScratch){ // start creating the scratch path mScratchPath = new Path(); mScratchPath.moveTo(xPoint, yPoint); mScratchPath.lineTo(xPoint, yPoint); paths.add(new Pair<Path, Paint>(mScratchPath, mScratchCurrentPaint)); } } break; case MotionEvent.ACTION_MOVE: // if two fingers touch and is not a scratch, // then it means we can rotate / resize / pan if (isPointerDown && !doScratch) { // reset matrix matrix.reset(); // get the center point scaledImageCenterX = (mImageWidth * mScaleFactor) / 2 ; scaledImageCenterY = (mImageHeight * mScaleFactor) / 2; // ROTATE THE IMAGE !!! matrix.postRotate(lastRotateDegree, scaledImageCenterX, scaledImageCenterY); // done to call onDraw invalidate(); } break; } if (operationListener != null) { operationListener.onEdit(this); } // if it is a scratch if(doScratch){ // then for every point, create a scratch path mScratchPath.lineTo(xPoint, yPoint); invalidate(); }else{ mScaleDetector.onTouchEvent(event); mRotateDetector.onTouchEvent(event); mMoveDetector.onTouchEvent(event); mShoveDetector.onTouchEvent(event); } return handled; } 

OnDraw

 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // if the image exists if (mBitmap != null) { // save canvas canvas.save(); // if it is a scratch if(doScratch){ // scratch the image mFillCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); // Draw our surface, nice an pristine final Drawable surface = mScratchSurface; if(surface != null) { surface.draw(mFillCanvas); } //Scratch the surface if(paths != null) { for (Pair<Path, Paint> p : paths) { mFillCanvas.drawPath(p.first,p.second); } } mBitmap = mFillCache; } canvas.drawBitmap(mBitmap, matrix, bitmapPaint); canvas.restore(); } } 

Función getAbsolutePosition

 public float[] getAbsolutePosition(float Ax, float Ay) { float[] mMatrixValues = new float[9]; matrix.getValues(mMatrixValues); float x = mImageWidth - ((mMatrixValues[Matrix.MTRANS_X] - Ax) / mMatrixValues[Matrix.MSCALE_X]) - (mImageWidth - getTranslationX()); float y = mImageHeight - ((mMatrixValues[Matrix.MTRANS_Y] - Ay) / mMatrixValues[Matrix.MSCALE_X]) - (mImageHeight - getTranslationY()); return new float[] { x, y}; } 

Necesitas aplicar los datos de rotación en tus coordenadas. Aquí theta es el ángulo por el cual se gira la imagen. Usted necesita aplicar la rotación de la matriz

Fuente de la imagen wikipedia

En código será algo como esto

 int getAbsoluteX(int x, int y, double theta) { int x_new = (int)(x*Math.cos(theta) - y*Math.sin(theta)); return x_new; } int getAbsoluteY(int x, int y, double theta) { int y_new = (int)(x*Math.sin(theta) + y*Math.cos(theta)); return y_new; } 

Está rotando toda la vista en el método onDraw. Esto no sólo afecta al rendimiento (repite la misma transformación cada vez), sino que afecta el resultado como se percibe ya que gira todo en la vista, incluyendo las rutas.

Si por alguna razón usted debe hacerlo de esta manera (no recomendado), entonces usted necesita girar los caminos en la dirección opuesta por la misma cantidad. Te sugiero que no lo hagas. Trate de encontrar una forma de girar el fondo dentro de la onDraw, en su lugar. Por ejemplo, cada vez que se gira el fondo, puede crear un nuevo fondo (fuera del método onDraw) y utilizar ese fondo en el método onDraw.

  • ¿Cómo se basan las coordenadas de un Android onTouchEvent MotionEvent?
  • Android: en el interruptor de desplazamiento entre Vistas / Actividades / Fragmentos
  • Diferentes diseños de hijos para diferentes grupos ExpandableListView
  • Android: obtener Viewgroup de la vista?
  • Creación de LinearLayout en Java - Los elementos no se muestran
  • Surface - dequeueBuffer failed (Error desconocido 2147483646)
  • Android expandablelistview, expanda la vista sólo al hacer clic en el indicador de grupo, abra una nueva actividad si hace clic en cualquier lugar, pero groupindicator
  • Ocultar barra de desplazamiento de HorizontalScrollView
  • Cómo establecer el atributo de primer plano en otra vista no FrameLayout
  • Reemplazar fragmento dentro de un ViewPager
  • Android doble lista de correo expandible oculta los elementos si la lista es demasiado grande
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.