building a custom crop image activity

46 Views Asked by At

i have been encoutering errors in getting acurate values of the area that needs to be cropped.the cropped image is usually too much to the left and bottom. .It even shows negative width and height if you zoom too much.

example of when if(left \>= 0 && top \>= 0 && width \> 0 && height \> 0) is false:

left = 2303.7014  
top = 1823.5114  
right = 1080.0 
 bottom = 1080.0  
width = -1223 
 height = -743
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.squareup.picasso.Picasso;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Objects;

public class CropImageActivity extends AppCompatActivity {

    private ImageView imageView;
    private ScaleGestureDetector scaleGestureDetector;
    private Matrix matrix = new Matrix();
    private TextView saveButton;
    private float scaleFactor = 1.0f;
    
    private Uri imageUri;
    private float lastX, lastY;
    private String TAG ="CropImage Activity";
    private ActivityResultLauncher<Intent> selectImageLauncher;
    private TextView backButton;
    @SuppressLint("ClickableViewAccessibility")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_crop_image);
        imageView = findViewById(R.id.crop_image_image_view);
        saveButton = findViewById(R.id.crop_image_save_button);
        backButton = findViewById(R.id.crop_image_select_button);
        scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
        imageView.setScaleType(ImageView.ScaleType.MATRIX);
        selectImageLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result ->{
    
            try {
                assert result.getData() != null;
                Log.d(TAG, result.toString());
                imageUri = result.getData().getData();
                Picasso.get().load(imageUri).into(imageView);
            }catch (Exception e){
    
                Log.d(TAG, Objects.requireNonNull(e.getMessage()));
    
            }
    
        });
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        selectImageLauncher.launch(intent);
    
        backButton.setOnClickListener(view->{
    
            Intent intentAgaim = new Intent(Intent.ACTION_GET_CONTENT);
            intentAgaim.setType("image/*");
            selectImageLauncher.launch(intentAgaim);
    
        });
    
        imageView.setOnTouchListener((v, event) -> {
            scaleGestureDetector.onTouchEvent(event);
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastX = event.getX();
                    lastY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float deltaX = event.getX() - lastX;
                    float deltaY = event.getY() - lastY;
    
                    // Get the current matrix of the ImageView
                    matrix.set(imageView.getImageMatrix());
    
                    // Translate the matrix by the change in X and Y
                    Log.d(TAG, "deltX = "+deltaX+" deltaY = "+deltaY);
                    matrix.postTranslate(deltaX, deltaY);
    
                    // Apply the new matrix to the ImageView
                    imageView.setImageMatrix(matrix);
                    imageView.invalidate();
    
                    // Update the last touch coordinates
                    lastX = event.getX();
                    lastY = event.getY();
                    break;
            }
    
            return true;
        });
    
        saveButton.setOnClickListener(view ->{
    
            if (cropImage() == null){
    
                Toast.makeText(this, "cropping failed", Toast.LENGTH_SHORT).show();
    
            }else {
    
                Intent resultIntent = new Intent();
                resultIntent.putExtra("cropped_image", cropImage());
                setResult(RESULT_OK, resultIntent);
                finish();
    
            }
    
        });
    
    
    }
    
    private Uri cropImage() {
        RectF visibleRect = new RectF();
        Matrix imageMatrix = imageView.getImageMatrix();
        imageMatrix.mapRect(visibleRect);
        Bitmap croppedBitmap;
        Drawable drawable = imageView.getDrawable();
        if (drawable != null) {
            int imageWidth = drawable.getIntrinsicWidth();
            int imageHeight = drawable.getIntrinsicHeight();
    
            float[] matrixValues = new float[9];
            imageMatrix.getValues(matrixValues);
            float imageX = matrixValues[Matrix.MTRANS_X];
            float imageY = matrixValues[Matrix.MTRANS_Y];
    
            // Calculate the adjusted cropping area
            float left = Math.max(0, -visibleRect.left / matrixValues[Matrix.MSCALE_X] - imageX);
            float top = Math.max(0, -visibleRect.top / matrixValues[Matrix.MSCALE_Y] - imageY);
            float right = Math.min(imageWidth, (imageWidth - visibleRect.left) / matrixValues[Matrix.MSCALE_X] - imageX);
            float bottom = Math.min(imageHeight, (imageHeight - visibleRect.top) / matrixValues[Matrix.MSCALE_Y] - imageY);
    
            int width = (int) (right - left);
            int height = (int) (bottom - top);
    
            Bitmap sourceBitmap = ((BitmapDrawable) drawable).getBitmap();
            if (left >= 0 && top >= 0 && width > 0 && height > 0) {
                try {
                    // Create a cropped bitmap from the source bitmap using the calculated area
                    croppedBitmap = Bitmap.createBitmap(sourceBitmap, (int) left, (int) top, width, height);
    
                    // Check if the croppedBitmap is not null before attempting to compress it
                    if (croppedBitmap != null) {
                        // Create a temporary file to save the cropped bitmap
                        File tempFile = createTempImageFile(this);
    
                        if (tempFile != null) {
                            try {
                                // Write the cropped bitmap to the file
                                FileOutputStream fos = new FileOutputStream(tempFile);
                                croppedBitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                                fos.close();
    
                                // Create a Uri from the temporary file
                                Uri croppedImageUri = Uri.fromFile(tempFile);
                                return croppedImageUri;
    
                            } catch (IOException e) {
                                e.printStackTrace();
                                return null;
                            }
                        } else {
                            Log.d(TAG, "croppedBitmap is = null");
                            return null;
                        }
                    } else {
                        Log.d(TAG, "croppedBitmap is = null");
                        return null;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            } else {
                Log.d(TAG, "if(left >= 0 && top >= 0 && width > 0 && height > 0) failed");
                Log.d(TAG, "left = " + left);
                Log.d(TAG, "top = " + top);
                Log.d(TAG, "right = " + right);
                Log.d(TAG, "bottom = " + bottom);
                Log.d(TAG, "width = " + width);
                Log.d(TAG, "height = " + height);
                Toast.makeText(this, "Invalid cropping area", Toast.LENGTH_SHORT).show();
                return null;
            }
        } else {
            Log.d(TAG, "drawable equals null");
            return null;
        }
    }
    
    
    
    public class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        private float scaleFactor = 1.0f;
    
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            scaleFactor = Math.max(1.0f, Math.min(scaleFactor, 3.0f));
    
            // Adjust the matrix to apply zoom
            matrix.setScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY());
            imageView.setImageMatrix(matrix);
    
            return true;
        }
    }
    
    
    private File createTempImageFile(Context context) {
        try {
            // Create a temporary file in the app's cache directory
            File cacheDir = context.getCacheDir();
            File tempFile = File.createTempFile("temp_image", ".png", cacheDir);
            return tempFile;
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return null;
    }

}

// Calculate the adjusted cropping area within the image boundaries float left = Math.max(0, visibleRect.left / scaleFactor); float top = Math.max(0, visibleRect.top / scaleFactor); float right = Math.min(imageWidth, (imageWidth - visibleRect.left) / scaleFactor); float bottom = Math.min(imageHeight, (imageHeight - visibleRect.top) / scaleFactor);

This resulted in i same values, so width and height became zero.

0

There are 0 best solutions below