A very easy-to-use Android image selection framework to select, cut and take photos of avatars in one step

Posted by liquidd on Thu, 17 Feb 2022 08:54:36 +0100

preface

Almost every APP needs image selection and clipping function. Because it involves camera and storage, this function still needs to consider a lot of compatibility. This is why there are a lot of picture selection frameworks on github, but you will find that the picture selection framework found on github is not just picture selection. It also includes a lot of functions such as video selection, video recording, picture compression and so on. In fact, you only need one avatar selection function. You can't use many functions of those frameworks, and the code has at least dozens of classes. It's troublesome to change problems in the later stage. So I encapsulated a code and its concise picture selection framework, without any redundant functions. There are only three main function classes involved, and the use is very simple.

 

Original address: https://www.jianshu.com/p/6ac6b681c413

 

The renderings are as follows:

 

design sketch. jpg

Functional features

  • Support obtaining pictures by taking photos
  • Support to get pictures through photo album
  • Support image clipping
  • Support the effect of imitating the action sheet of the pop-up selection menu at the bottom of IOS
  • Support 6.0 dynamic authorization
  • Solve the problem of black edge in the picture
  • Solve the problem of calling the camera message FileUriExposedException in 7.0
  • Solve the crash problem of Xiaomi miui system calling the system clipping picture function

use

Step 1. Add JitPack warehouse

In the project build Add JitPack warehouse to gradle

 

allprojects {
    repositories {
        ...
        maven { url "https://jitpack.io" }
    }
}

Step 2. Add dependency

Add dependencies in the module s to be used (see for the latest version) PictureSelector)

 

dependencies {
    compile 'com.github.wildma:PictureSelector:1.1.1'
}

Or reference the local lib

 

compile project(':pictureselector')

Step 3. Take a picture or choose a picture from an album

 

        /**
         * create()The first parameter of the method is the context, which is passed in the activity This, pass the fragment in the fragment this.  Parameter 2 is the request code, which is used to determine the result callback in onActivityResult
         * selectPicture()The method parameters are whether to crop, the width of the cropped picture (unit px), the height, width ratio and height ratio of the cropped picture. If it is not transmitted, the default is clipping, with a width of 200, a height of 200, and a width height ratio of 1:1.
         */
        PictureSelector
                .create(MainActivity.this, PictureSelector.SELECT_REQUEST_CODE)
                .selectPicture(true, 200, 200, 1, 1);

Step 4. Get the cropped picture address

 

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        /*Result callback*/
        if (requestCode == PictureSelector.SELECT_REQUEST_CODE) {
            if (data != null) {
                String picturePath = data.getStringExtra(PictureSelector.PICTURE_PATH);
            }
        }
    }

code

I have written the notes of each class very clearly, so only the main picture tool classes are posted here. For others, you can check the source code on my Github (see the end of the article).

Select Picture tool class

 

package com.wildma.pictureselector;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.widget.Toast;

import java.io.File;
import java.io.FileNotFoundException;


/**
 * Author       wildma
 * Github       https://github.com/wildma
 * CreateDate   2018/6/10
 * Desc         ${Select Picture tool class}
 * usage method:
 * 1. Call getByCamera() and getByAlbum() to get pictures by taking photos or albums
 * 2. The onActivityResult method of this tool class is invoked in onActivityResult to process pictures obtained through photo albums or photographs.
 */
public class PictureSelectUtils {

    public static final int GET_BY_ALBUM  = 0x11;//Album tag
    public static final int GET_BY_CAMERA = 0x12;//Photo mark
    public static final int CROP          = 0x13;//Trim marks 
    private static Uri takePictureUri;//Photo uri
    public static Uri cropPictureTempUri;//Crop picture uri

    /**
     * Get pictures from album
     * @param activity
     */
    public static void getByAlbum(Activity activity) {
        Intent intent = new Intent(Intent.ACTION_PICK,
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        intent.setType("image/*");
        activity.startActivityForResult(intent, GET_BY_ALBUM);
    }

    /**
     * Get pictures by taking pictures
     * @param activity
     */
    public static void getByCamera(Activity activity) {
        takePictureUri = createImagePathUri(activity);
        if (takePictureUri != null) {
            Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            i.putExtra(MediaStore.EXTRA_OUTPUT, takePictureUri);//Output path (save path after taking photos)
            activity.startActivityForResult(i, GET_BY_CAMERA);
        } else {
            Toast.makeText(activity, "Unable to save to album", Toast.LENGTH_LONG).show();
        }
    }

    /**
     * Create a picture address uri to save the photos after taking photos
     *
     * @param activity
     * @return          uri of the picture
     */
    public static Uri createImagePathUri(Activity activity) {

        try {
            FileUtils.createOrExistsDir(Constant.DIR_ROOT);
            StringBuffer buffer = new StringBuffer();
            String pathName = buffer.append(Constant.DIR_ROOT).append(Constant.APP_NAME).append(".").append(System.currentTimeMillis()).append(".jpg").toString();
            File file = new File(pathName);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //Solve the problem of FileUriExposedException in Android 7.0 photography
                String authority = activity.getPackageName() + ".fileProvider";
                takePictureUri = FileProvider.getUriForFile(activity, authority, file);
            } else {
                takePictureUri = Uri.fromFile(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(activity, "Unable to save to album", Toast.LENGTH_LONG).show();
        }
        return takePictureUri;
    }

    /**
     * Photo album, 1:480 by default, or 1:480 by default
     * @param activity      context
     * @param requestCode   Request code
     * @param resultCode    Result code
     * @param data          Intent
     * @return
     */
    public static Bitmap onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
        return onActivityResult(activity, requestCode, resultCode, data, 0, 0, 0, 0);
    }

    /**
     * Process pictures taken from photos or albums
     * @param activity      context
     * @param requestCode   Request code
     * @param resultCode    Result code
     * @param data          Intent
     * @param w             Output width
     * @param h             Output high
     * @param aspectX       Width ratio
     * @param aspectY       High proportion
     * @return
     */
    public static Bitmap onActivityResult(Activity activity, int requestCode, int resultCode, Intent data,
                                          int w, int h, int aspectX, int aspectY) {
        Bitmap bm = null;
        if (resultCode == Activity.RESULT_OK) {
            Uri uri = null;
            switch (requestCode) {
                case GET_BY_ALBUM:
                    uri = data.getData();
                    activity.startActivityForResult(crop(uri, w, h, aspectX, aspectY), CROP);
                    break;
                case GET_BY_CAMERA:
                    uri = takePictureUri;
                    activity.startActivityForResult(crop(uri, w, h, aspectX, aspectY), CROP);
                    break;
                case CROP:
                    bm = dealCrop(activity);
                    break;
            }
        }
        return bm;
    }

    /**
     * Clipping, default clipping output 480 * 480, scale 1:1
     * @param uri   uri of the picture
     * @return
     */
    public static Intent crop(Uri uri) {
        return crop(uri, 480, 480, 1, 1);
    }

    /**
     * Cropping, for example: output 100 * 100 size pictures, with a width height ratio of 1:1
     * @param uri     uri of the picture
     * @param w       Output width
     * @param h       Output high
     * @param aspectX Width ratio
     * @param aspectY High proportion
     * @return
     */
    public static Intent crop(Uri uri, int w, int h, int aspectX, int aspectY) {
        if (w == 0 && h == 0) {
            w = h = 480;
        }
        if (aspectX == 0 && aspectY == 0) {
            aspectX = aspectY = 1;
        }
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        intent.putExtra("aspectX", aspectX);
        intent.putExtra("aspectY", aspectY);
        intent.putExtra("outputX", w);
        intent.putExtra("outputY", h);

        /*Solve the problem of black edge in the picture*/
        intent.putExtra("scale", true);
        intent.putExtra("scaleUpIfNeeded", true);

        /*Solve the problem of "picture loading failed" when jumping to the clipping prompt*/
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

        /*Solve the problem that Xiaomi miui system calls the system clipping picture function camera action. Problems after app reopens or crashes*/
        StringBuffer buffer = new StringBuffer();
        String pathName = buffer.append("file:///").append(FileUtils.getRootPath()).append(File.separator).append(Constant.APP_NAME).append(".temp.jpg").toString();
        cropPictureTempUri = Uri.parse(pathName);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropPictureTempUri);//Output path (saved path after clipping)
        // Output format
        intent.putExtra("outputFormat", "JPEG");
        // Do not enable face recognition
        intent.putExtra("noFaceDetection", true);
        //Whether to keep data in Bitmap and return
        intent.putExtra("return-data", false);
        return intent;
    }

    /**
     * Process clipping and obtain the clipped picture
     * @param context   context
     * @return
     */
    public static Bitmap dealCrop(Context context) {
        Bitmap bitmap = null;
        try {
            bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(cropPictureTempUri));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return bitmap;
    }

}

github address: PictureSelector
ps: if it's helpful to you, clicking like is my greatest recognition.

 

Topics: IDE