在Android中擦除旋转的图像不会显示擦除正确的路径

我们正在构建一个涉及图像编辑的Android应用程序。 一些function包括旋转图像和擦除图像的一部分。

我们使用以下库: https : //github.com/nimengbo/StickerView

我们已经成功创建了一个旋转和擦除图像的function。 但是,当我们尝试执行以下操作时:

  1. 在一定程度上旋转图像。
  2. 然后,删除图像。

我们发现了以下错误:

  1. 当我们尝试擦除旋转的图像时,擦除的路径不会反映我们的手指在屏幕上跟踪的路径。

在此处输入图像描述

从上图中,黄线是手指的实际移动(在贴纸上垂直向下)。 但是,发现擦除的路径是对角的。

此问题仅在旋转图像时存在。 图像未旋转时不存在。

经过进一步的调试,我们从上述问题中得出一些假设:

  1. 由于旋转图像,x和y绝对位置改变。 因此,路径不会通过触摸路线反映正确的路径。

我们怎样才能确保路径仍在参考正确的路径,即使在旋转后手指触摸的是什么?

以下是我们在StickerView.java类中扩展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(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 p : paths) { mFillCanvas.drawPath(p.first,p.second); } } mBitmap = mFillCache; } canvas.drawBitmap(mBitmap, matrix, bitmapPaint); canvas.restore(); } } 

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

您需要在坐标上应用旋转matrics。 这里θ是图像旋转的角度。 您需要应用矩阵旋转

图像源维基百科

在代码中它将是这样的

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

您正在onDraw方法中旋转整个视图。 这不仅影响性能(每次都重复相同的转换),它会影响结果,因为它会旋转视图中的所有内容,包括路径。

如果由于某种原因你必须这样做(不推荐),那么你需要以相反的方向旋转相反方向的路径。 我强烈建议你不要这样做。 尝试找一种绕着onDraw旋转背景的方法。 例如,无论何时旋转背景,您都可以创建新背景(在onDraw方法之外)并在onDraw方法中使用该背景。