2016-05-30 11 views
8

Budujemy aplikację dla systemu Android, która wymaga edycji obrazu. Kilka funkcji obejmuje obracanie obrazu i kasowanie części obrazu.Kasowanie obróconego obrazu w systemie Android nie powoduje usunięcia prawidłowej ścieżki.

Używamy następujące biblioteki: https://github.com/nimengbo/StickerView

powodzeniem stworzyła funkcję obracania i usunąć obraz. Jednak gdy próbowaliśmy wykonać następujące czynności:

  1. Obracanie obrazu w pewnym stopniu.
  2. Następnie skasowanie obrazu.

Znaleźliśmy następujące błędy:

  1. Kiedy staraliśmy się wymazać obróconego obrazu, skasowana ścieżka nie odzwierciedla ścieżkę którym nasz palec prześledzić na ekranie.

enter image description here

Z powyższego obrazu, żółta linia jest rzeczywisty ruch palca (prosto w dół pionowo w poprzek naklejki). Ale wynikowa skasowana ścieżka okazała się przekątna.

Ten problem występuje tylko po obróceniu obrazu. Nie istnieje, gdy obraz nie jest obracany.

Po dalszych debugowania, mamy kilka założeń z powyższych problemów:

  1. z powodu obróconego obrazu, X i Y pozycja rozgrzeszenie ulega zmianie. W ten sposób ścieżka nie odzwierciedla prawidłowej ścieżki przez trasy dotykowe.

W jaki sposób możemy zapewnić, że ścieżka nadal wskazuje prawidłową ścieżkę na palcu, który dotyka nawet po obróceniu?

Oto kod, który mamy w naszej klasie StickerView.java, która rozszerza klasę 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(); 
    } 
} 

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

Odpowiedz

4

Ty ne ed, aby zastosować matryce obrotu na twoich współrzędnych. Tutaj theta to kąt, o który obraz jest obracany. You Need to Apply Matrix rotation

źródło obrazu wikipedia

W kodzie to będzie coś takiego

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

Gdzie należy zastosować matrycę obrotu? Czy jest na pozycji onTouchEvent? Lub w funkcji getAbsolutePosition? –

+0

Załóżmy, że theta to kąt, o który obraz został obrócony. Następnie musimy obrócić pozycję usuwania (lub pozycję dotykową) o (-theta), czyli ujemną z theta. Aby to zrobić, zastosuj transformację w miejscu, w którym użytkownik dotyka ekranu za pomocą (-theta), a następnie usuń współrzędne uzyskane w wyniku działania imageView. –

+0

Możesz obliczyć całą ścieżkę usuwania, po pierwsze, bez stosowania żadnych transformacji. Następnie po obliczeniu całej ścieżki można zastosować transformację na całej ścieżce i uzyskać wynikową ścieżkę. Następnie usuń transformowaną ścieżkę z obrazu –

2

Jesteś obracającego całą widoku w metodzie OnDraw. Nie tylko to wpływa na wydajność (za każdym razem powtarzasz tę samą transformację), wpływa na wynik, jak zauważyłeś, ponieważ obraca wszystko w widoku, w tym ścieżki.

Jeśli z jakiegoś powodu musisz zrobić to w ten sposób (niezalecane), musisz obrócić ścieżki w przeciwnym kierunku o tę samą wartość. Zdecydowanie sugeruję, żeby tego nie robić. Spróbuj zamiast tego znaleźć sposób na obrócenie tła wewnątrz onDraw. Na przykład, gdy tło jest obracane, możesz utworzyć nowe tło (poza metodą onDraw) i użyć tego tła w metodzie onDraw.

Powiązane problemy