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:
- Obracanie obrazu w pewnym stopniu.
- Następnie skasowanie obrazu.
Znaleźliśmy następujące błędy:
- Kiedy staraliśmy się wymazać obróconego obrazu, skasowana ścieżka nie odzwierciedla ścieżkę którym nasz palec prześledzić na ekranie.
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:
- 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};
}
Gdzie należy zastosować matrycę obrotu? Czy jest na pozycji onTouchEvent? Lub w funkcji getAbsolutePosition? –
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. –
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 –