Как добавить ручную обрезку в приложение Android Studio? - PullRequest
0 голосов
/ 30 октября 2019

Прямо сейчас у меня есть приложение, которое я создал в Android Studio, в котором приложение автоматически обрезает изображение, устраняя пробелы. Все кодирование выполняется в файле MainActivity.java. То, что я хотел бы сделать, это добавить кнопку, которая, когда пользователь нажимает ее, они могут вручную обрезать изображение после того, как первоначальная автоматическая обрезка произошла. Я пробовал следовать учебникам, но ни один из них не работает должным образом. Я разместил Java-файл и XML-файл ниже:

MainActivity.Java:

package com.example.cropshot;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.ImageView;
import android.graphics.Color;


import com.google.android.material.bottomnavigation.BottomNavigationView;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import java.io.*;
import java.util.Random;

public class MainActivity extends AppCompatActivity {

    public static final int IMAGE_GALLERY_REQUEST = 20;

    // We need access to our image view
    ImageView imageView;
    Bitmap bitMap;
    Uri contentURI;
    Bitmap preCrop;

    enum DIR {TOP, BOTTOM}

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // ------------ TEMPLATE CODE --------------

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomNavigationView navView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
        NavigationUI.setupWithNavController(navView, navController);

        // ------------ TEMPLATE CODE --------------

        // Get access to the Cropping image image view, and store it in a variable
        imageView = (ImageView) findViewById(R.id.CroppingImg);
    }

    public Bitmap cropImage(Context context, Uri userImage) throws Exception {
        //Convert uri image to bitmap
        Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), userImage);
        Bitmap preCrop = MediaStore.Images.Media.getBitmap(context.getContentResolver(), userImage);

        //Crop out top 14 of height off image.
        Bitmap resizedBitmap1 = Bitmap.createBitmap(bitmap, 0, 120, bitmap.getWidth(), bitmap.getHeight() - 200);

        return resizedBitmap1;

    }

    public void onGalleryClick(View v) {
        // Invoke the image gallery using an implicit intent
        Intent photoPickerintent = new Intent(Intent.ACTION_PICK);

        // Where do we want to find the data?
        File pictureDirectory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

        String pictureDirectoryPath = pictureDirectory.getPath();

        // Finally, get a URI representation
        Uri data = Uri.parse(pictureDirectoryPath);

        // Set the data and type Get all images types
        photoPickerintent.setDataAndType(data, "image/*");

        startActivityForResult(photoPickerintent, IMAGE_GALLERY_REQUEST);
    }

    public void onCropClick(View v) {
        try {

            //Convert uri image to bitmap
            bitMap = MediaStore.Images.Media.getBitmap(getApplication().getContentResolver(), contentURI);


            // Call the FindBorder function for both top and bottom, to find the top and bottom border heights
            int topCropInt = FindBorder(DIR.TOP);
            int bottomCropInt = FindBorder(DIR.BOTTOM);


            bottomCropInt = bitMap.getHeight() - bottomCropInt;


            System.out.println("Top = " + topCropInt + "  Bottom = " + bottomCropInt + "  Height = " + (bitMap.getHeight()));

            // Crop the top of the bitmap. Because bitmaps 0,0 starts in upper left, we must insert topCropInt as the
            // Lower bounded value
            Bitmap croppedMap = Bitmap.createBitmap(bitMap, 0, topCropInt, bitMap.getWidth(), bitMap.getHeight() - topCropInt - bottomCropInt);

            //saveImage(bitMap, "IMG300");

            imageView.setImageBitmap(croppedMap);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void onDiscardClick(View v)
    {
       try {
           //revert to original display and remove original
           setContentView(R.layout.activity_main);
           imageView.setImageBitmap(preCrop);
       }
       catch(Exception e) {
           e.printStackTrace();
       }
    }

    public void onSaveNewClick (View v)
    {
        try {
            //creates new file
            saveImage(bitMap);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }



    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        // Only preform operations if we know that our result has successfully happened
        if (resultCode == RESULT_OK) {
            if (requestCode == IMAGE_GALLERY_REQUEST) {
                try {
                    // Let's get the URI (or address) of the image our user has selected
                    contentURI = data.getData();

                    // Set our imageView to the URI of the selected image from the gallery
                    imageView.setImageURI(contentURI);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }



    private void overwriteImage(Bitmap finalBitmap) {

    }


    private void saveImage(Bitmap finalBitmap) {


        String root = Environment.getExternalStorageDirectory().toString();
        File myDir = new File(root + "/saved_images");
        myDir.mkdirs();
        Random generator = new Random();
        int n = 10000;
        n = generator.nextInt(n);
        String fname = "Image-" + n + ".jpg";
        File file = new File(myDir, fname);
        while (file.exists()) {
            fname = fname+1;
        }
        Log.i("LOAD", root + fname);
        try {
            FileOutputStream out = new FileOutputStream(file);
            finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Checks the color of the left and right pixel
    // Returns true if the pixels are in a similar range
    // And false otherwise
    boolean CheckColor(int left, int right){
        int leftSum = Color.red(left) + Color.green(left) + Color.blue(left);
        int rightSum = Color.red(right) + Color.green(right) + Color.blue(right);
        int diff = leftSum - rightSum;


        if (diff < 10 && diff > -10) {
            return true;
        }
        else
            return false;
       }

    // Takes the bitmap, and given a direction (Top or bottom)
    // Scans for pixels that are identical on the same line
    // In order to find the top/bottom of an image
    int FindBorder(DIR direction) {
        // Get the middle position of the bitmap
        int middleY = bitMap.getHeight() / 2;

        if (direction == DIR.BOTTOM) {
            // Let's start with I at the middle of the image, and move positively until we reach the bottom
            for (int i = middleY; i < bitMap.getHeight(); i++)
            {

                // Generate the single rowed bitmap
                Bitmap subMap = Bitmap.createBitmap(bitMap, 0, i, bitMap.getWidth(), 1);
                int pixel = subMap.getPixel(0,0);

                if(SolidRow(subMap) && Color.red(pixel) == Color.blue(pixel) && Color.red(pixel) == Color.green(pixel))
                {
                    return i;
                }
            }

            //DIR == TOP
        } else {
            // Let's start with I at the middle of the image, and move negatively until we reach the top
            for (int i = middleY; i > 0; i--)
            {

                // Generate the single rowed bitmap
                Bitmap subMap = Bitmap.createBitmap(bitMap, 0, i, bitMap.getWidth(), 1);
                int pixel = subMap.getPixel(0,0);

                // if the colors are the same we want to return our i value for the top
                // Also if the color is white (255,255,255), as that designates top of image.
                if(SolidRow(subMap))
                {
                    return i;
                }
            }
        }
        return 0;
    }

    // NOTE: This doesn't actually check if all the pixels are the same!
    // It only checks if the pixels across from eachother are, i.e.
    // (left, right), (left + 1, right - 1)

    // Given a row of pixels in a bitmap, return true if all pixels
    // Are the same color, otherwise return false.
    boolean SolidRow(Bitmap row)
    {
        //Getting length and height for the bitmap
        int length = row.getWidth();
        int height = row.getHeight();
        int max = length - 1;
        int pixel = row.getPixel(0,0);

        //Iterates through the bitmap row
        for(int i = 1; i < (length - 1); i++) {
            //Gets variables
            int left_pixel = row.getPixel(0, height - 1);
            int right_pixel = row.getPixel(i, height - 1);

            //Checks if the pixels are the same color or if the pixels meet
            if (!CheckColor(left_pixel, right_pixel)) {
                return false;
            }
        }
      return true;
    }


    public Bitmap cropSolidRow(Bitmap bitmap, int cropHeight, DIR direction){
        int bitmapWidth = bitmap.getWidth();


        // Crop from solid row upward
        if (direction == DIR.TOP){
            int numOfRows = bitmap.getHeight() - cropHeight;

            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, cropHeight, bitmapWidth, numOfRows);
            return newBitmap;
        }

        // Crop from solid row downward
        //else if direction == DIR.BOTTOM
        else {
            // Height - number of rows to delete at end of picture
            int numOfRows = bitmap.getHeight() - (bitmap.getHeight() - cropHeight);

            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, numOfRows);
            return newBitmap;
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:menu="@menu/bottom_nav_menu" />

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

    <Button
        android:id="@+id/CropButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="160dp"
        android:layout_marginBottom="64dp"
        android:text="Crop"
        android:onClick="onCropClick"
        app:layout_constraintBottom_toTopOf="@+id/nav_view"
        app:layout_constraintStart_toStartOf="@+id/nav_view" />

    <Button
        android:id="@+id/SelectLayout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="45dp"
        android:layout_marginEnd="84dp"
        android:text="Layout"
        app:layout_constraintEnd_toEndOf="@+id/nav_host_fragment"
        app:layout_constraintTop_toTopOf="@+id/nav_host_fragment" />

    <Button
        android:id="@+id/ViewGallery"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="84dp"
        android:layout_marginTop="45dp"
        android:onClick="onGalleryClick"
        android:text="Gallery"
        app:layout_constraintStart_toStartOf="@+id/nav_host_fragment"
        app:layout_constraintTop_toTopOf="@+id/nav_host_fragment" />

    <ImageView
        android:id="@+id/CroppingImg"
        android:layout_width="273dp"
        android:layout_height="276dp"
        android:layout_marginEnd="68dp"
        android:layout_marginBottom="128dp"
        app:layout_constraintBottom_toTopOf="@+id/nav_view"
        app:layout_constraintEnd_toEndOf="@+id/nav_host_fragment"
        tools:srcCompat="@tools:sample/avatars[2]" />

</androidx.constraintlayout.widget.ConstraintLayout>
...