【问题标题】:How to pick image for crop from camera or gallery in Android 7.0?如何在 Android 7.0 中从相机或图库中选择要裁剪的图像?
【发布时间】:2017-01-11 19:55:43
【问题描述】:

从图库和相机中选择图像进行裁剪,它适用于 Android 7.0 以下,但在 Android Naught 中它会在相机中崩溃。我为此使用了文件提供程序,但不起作用。

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button mBtn;
private Context context;
private static final int SELECT_PICTURE_CAMARA = 101, SELECT_PICTURE = 201, CROP_IMAGE = 301;
private Uri outputFileUri;
String mCurrentPhotoPath;
private Uri selectedImageUri;
private File finalFile = null;
private ImageView imageView;
private PermissionUtil permissionUtil;
Uri fileUri;
File file = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mBtn = (Button) findViewById(R.id.btn_img);
    imageView = (ImageView) findViewById(R.id.img_photo);
    permissionUtil = new PermissionUtil();
    mBtn.setOnClickListener(this);
    context = this;
}

@Override
public void onClick(View view) {
    selectImageOption();
}

private void selectImageOption() {
    final CharSequence[] items = {"Capture Photo", "Choose from Gallery", "Cancel"};

    AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
    builder.setTitle("Add Photo!");
    builder.setItems(items, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int item) {
            if (items[item].equals("Capture Photo")) {
                if (permissionUtil.checkMarshMellowPermission()) {
                    if (permissionUtil.verifyPermissions(MainActivity.this, permissionUtil.getCameraPermissions()))
                        onClickCamera();
                    else
                        ActivityCompat.requestPermissions(MainActivity.this, permissionUtil.getCameraPermissions(), SELECT_PICTURE_CAMARA);
                } else
                    onClickCamera();
            } else if (items[item].equals("Choose from Gallery")) {
                if (permissionUtil.checkMarshMellowPermission()) {
                    if (permissionUtil.verifyPermissions(MainActivity.this, permissionUtil.getGalleryPermissions()))
                        onClickGallery();
                    else
                        ActivityCompat.requestPermissions(MainActivity.this, permissionUtil.getGalleryPermissions(), SELECT_PICTURE);
                } else
                    onClickGallery();
            } else if (items[item].equals("Cancel")) {
                dialog.dismiss();
            }
        }
    });
    builder.show();
}

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) {
        if (requestCode == SELECT_PICTURE) {
            selectedImageUri = data.getData();
            cropImage(selectedImageUri);

        } else if (requestCode == CROP_IMAGE) {

            Uri imageUri = Uri.parse(mCurrentPhotoPath);
            File file = new File(imageUri.getPath());
            try {
                InputStream ims = new FileInputStream(file);
                imageView.setImageBitmap(BitmapFactory.decodeStream(ims));
            } catch (FileNotFoundException e) {
                return;
            }

        } else if (requestCode == SELECT_PICTURE_CAMARA && resultCode == Activity.RESULT_OK) {
            cropImage1();
        }
    }
}

private void onClickCamera() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) {
       /* File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
        }
        if (photoFile != null) {

            Uri photoURI;
            if (Build.VERSION.SDK_INT >= 24) {
                photoURI = FileProvider.getUriForFile(MainActivity.this,
                        BuildConfig.APPLICATION_ID + ".fileprovider", photoFile);
            } else {
                photoURI = Uri.fromFile(photoFile);
            }
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, SELECT_PICTURE_CAMARA);

        }*/

        ContentValues values = new ContentValues(1);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
        fileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri);
        takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        startActivityForResult(takePictureIntent, SELECT_PICTURE_CAMARA);

    } else {
        Toast.makeText(this, getString(R.string.error_no_camera), Toast.LENGTH_LONG).show();
    }
}

private void onClickGallery() {
    List<Intent> targets = new ArrayList<>();
    Intent intent = new Intent();
    intent.setType("image/*");
    intent.setAction(Intent.ACTION_PICK);
    intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
    List<ResolveInfo> candidates = getApplicationContext().getPackageManager().queryIntentActivities(intent, 0);

    for (ResolveInfo candidate : candidates) {
        String packageName = candidate.activityInfo.packageName;
        if (!packageName.equals("com.google.android.apps.photos") && !packageName.equals("com.google.android.apps.plus") && !packageName.equals("com.android.documentsui")) {
            Intent iWantThis = new Intent();
            iWantThis.setType("image/*");
            iWantThis.setAction(Intent.ACTION_PICK);
            iWantThis.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
            iWantThis.setPackage(packageName);
            targets.add(iWantThis);
        }
    }
    if (targets.size() > 0) {
        Intent chooser = Intent.createChooser(targets.remove(0), "Select Picture");
        chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targets.toArray(new Parcelable[targets.size()]));
        startActivityForResult(chooser, SELECT_PICTURE);
    } else {
        Intent intent1 = new Intent(Intent.ACTION_PICK);
        intent1.setType("image/*");
        startActivityForResult(Intent.createChooser(intent1, "Select Picture"), SELECT_PICTURE);
    }
}

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";

    File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    File image = File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    if (Build.VERSION.SDK_INT >= 24) {
        mCurrentPhotoPath = String.valueOf(FileProvider.getUriForFile(MainActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", image));
    } else {
        mCurrentPhotoPath = String.valueOf(Uri.fromFile(image));
    }

    return image;
}

/*private Uri createImageUri(){
    ContentResolver contentResolver=getContentResolver();
    ContentValues cv=new ContentValues();
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    cv.put(MediaStore.Images.Media.TITLE,timeStamp);
    return contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,cv);
}*/

private void cropImage(Uri selectedImageUri) {
    Intent cropIntent = new Intent("com.android.camera.action.CROP");
    cropIntent.setDataAndType(selectedImageUri, "image/*");
    cropIntent.putExtra("crop", "true");
    cropIntent.putExtra("aspectX", 1);
    cropIntent.putExtra("aspectY", 1.5);
    cropIntent.putExtra("return-data", true);

    outputFileUri = Uri.fromFile(createCropFile());
    cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(cropIntent, CROP_IMAGE);
}

private void cropImage1() {
    Intent cropIntent = new Intent("com.android.camera.action.CROP");
    cropIntent.setDataAndType(fileUri, "image/*");
    cropIntent.putExtra("crop", "true");
    cropIntent.putExtra("aspectX", 1);
    cropIntent.putExtra("aspectY", 1.5);
    cropIntent.putExtra("return-data", true);

    if (Build.VERSION.SDK_INT >= 24) {
        outputFileUri = FileProvider.getUriForFile(MainActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", createCropFile());

    } else
        outputFileUri = Uri.fromFile(createCropFile());

    cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(cropIntent, CROP_IMAGE);

   /* ContentValues values = new ContentValues(1);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
    outputFileUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    cropIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
    startActivityForResult(cropIntent, CROP_IMAGE);*/
}

private File createCropFile() {
    File storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    //  path = path + (timeStamp + "1jpg");

    try {
        file = File.createTempFile(timeStamp, ".jpg", storageDir);
    } catch (IOException e) {
        e.printStackTrace();
    }

    /*if (Build.VERSION.SDK_INT >= 24)
        mCurrentPhotoPath = String.valueOf(FileProvider.getUriForFile(MainActivity.this,
                BuildConfig.APPLICATION_ID + ".provider", file));
    else*/
    mCurrentPhotoPath = String.valueOf(Uri.fromFile(file));
    return file;
}
}

这适用于所有设备,但不适用于 >= android 7.0 Naught device

【问题讨论】:

  • 能否提供logcat和minimal reproducible example
  • 请不要转发问题。您可以编辑上一个以将其撞到首页
  • 即使你没有转发,这里也没有足够的信息可以提供帮助。另一个问题要好得多
  • @shweta 你得到了如何在 android 7 和更低版本的 android 中裁剪图像的答案

标签: android android-gallery android-7.0-nougat


【解决方案1】:

我只是在 Nexus6p android N 上解决了这个问题,你需要授予 uri 权限,以便系统相机可以暂时访问文件等待裁剪,因为 StrictMode Android N 不支持传递文件:Uri in an Intent extra 不再见Scheme Ban in N Developer Preview,我们改用FileProvider。这是我的源代码:

AndroidManifest.xml

<provider
    android:name="android.support.v4.content.FileProvider"
        android:authorities="dreamgo.corp.provider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/filepaths"/>
</provider>

filepaths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="images" path="."/>
</paths>

MainActivity.java

Uri photoURI = FileProvider.getUriForFile(context, "dreamgo.corp.provider", file);
//grant uri with essential permission the first arg is the The packagename you would like to allow to access the Uri.
context.grantUriPermission("com.android.camera",photoURI,
                    Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);

Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(photoURI, "image/*");

//you must setup two line below
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 200);
intent.putExtra("outputY", 200);
intent.putExtra("return-data", true);
//you must setup this
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(intent, 1);

【讨论】:

  • 您能否建议我在裁剪后如何在 ImageView 中存储图像(当 requestCode == CROP_IMAGE 时)。因为在我裁剪图像后它会在 Android Naught In Camera 中崩溃。
  • 在 Android NI 使用 Bitmap bitmap = data.getParcelableExtra("data"); 之前,但这不适用于 Android NI 为相机创建一个临时文件,并在用户通过相机拍照后从此临时文件中获取 uri,剪切(裁剪)临时文件tempfile uri.system 将在用户剪切后更改 tempfile。我将在此问题下的另一个答案中发布所有代码。
  • 这里的文件名和上下文是什么
  • 谢谢,绝妙的解决方案,节省我的时间
  • 抱歉,这件事帮不了你。
【解决方案2】:

我得到了解决方案。发布我的答案。

在 MainActivity.java 中

public class MainActivity extends AppCompatActivity {

@BindView(R.id.img_camera)
CircleImageView mImgCamera;

private ChoosePhoto choosePhoto=null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
}

@OnClick(R.id.img_camera)
public void onViewClicked() {
    choosePhoto = new ChoosePhoto(this);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == Activity.RESULT_OK) {
        if (requestCode == ChoosePhoto.CHOOSE_PHOTO_INTENT) {
            if (data != null && data.getData() != null) {
                choosePhoto.handleGalleryResult(data);
            } else {
                choosePhoto.handleCameraResult(choosePhoto.getCameraUri());
            }
        }else if (requestCode == ChoosePhoto.SELECTED_IMG_CROP) {
            mImgCamera.setImageURI(choosePhoto.getCropImageUrl());
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == ChoosePhoto.SELECT_PICTURE_CAMERA) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            choosePhoto.showAlertDialog();
    }
}
}

选择Photo.java

public class ChoosePhoto {

public static int CHOOSE_PHOTO_INTENT = 101;
public static int SELECTED_IMG_CROP = 102;
public static int SELECT_PICTURE_CAMERA = 103;
public static int currentAndroidDeviceVersion = Build.VERSION.SDK_INT;

private int ASPECT_X = 1;
private int ASPECT_Y = 1;
private int OUT_PUT_X = 300;
private int OUT_PUT_Y = 300;
private boolean SCALE = true;

private Uri cropPictureUrl, selectedImageUri = null, cameraUrl = null;
private Context mContext;

public ChoosePhoto(Context context) {
    mContext = context;
    init();
}

private void init() {
    PermissionUtil permissionUtil = new PermissionUtil();

    if (permissionUtil.checkMarshMellowPermission()) {
        if (permissionUtil.verifyPermissions(mContext, permissionUtil.getCameraPermissions()) && permissionUtil.verifyPermissions(mContext, permissionUtil.getGalleryPermissions()))
            showAlertDialog();
        else {
            ActivityCompat.requestPermissions((Activity) mContext, permissionUtil.getCameraPermissions(), SELECT_PICTURE_CAMERA);
        }
    } else {
        showAlertDialog();
    }
}

public void showAlertDialog() {
    final Intent galleryIntent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    galleryIntent.setType("image/*");

    cameraUrl = FileUtil.getInstance(mContext).createImageUri();
    //Create any other intents you want
    final Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    cameraIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, cameraUrl);


    //Add them to an intent array
    Intent[] intents = new Intent[]{cameraIntent};

    //Create a choose from your first intent then pass in the intent array
    final Intent chooserIntent = Intent.createChooser(galleryIntent, mContext.getString(R.string.choose_photo_title));
    chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents);

    ((Activity) mContext).startActivityForResult(chooserIntent, CHOOSE_PHOTO_INTENT);
}

// Change this method(edited)
public void handleGalleryResult(Intent data) {
    try {
        cropPictureUrl = Uri.fromFile(FileUtil.getInstance(mContext)
                .createImageTempFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)));
        String realPathFromURI = FileUtil.getRealPathFromURI(mContext, data.getData());
        File file = new File(realPathFromURI == null ? getImageUrlWithAuthority(mContext, data.getData()) : realPathFromURI);
        if (file.exists()) {
            if (currentAndroidDeviceVersion > 23) {
                cropImage(FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", file), cropPictureUrl);
                
            } else {
                cropImage(Uri.fromFile(file), cropPictureUrl);
            }

        } else {
            cropImage(data.getData(), cropPictureUrl);
        }

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

public static String getImageUrlWithAuthority(Context context, Uri uri) {
    InputStream is = null;
    if (uri.getAuthority() != null) {
        try {
            is = context.getContentResolver().openInputStream(uri);
            Bitmap bmp = BitmapFactory.decodeStream(is);
            return writeToTempImageAndGetPathUri(context, bmp).toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return null;
}

public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
    String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
    return Uri.parse(path);
}


public void handleCameraResult(Uri cameraPictureUrl) {
    try {
        cropPictureUrl = Uri.fromFile(FileUtil.getInstance(mContext)
                .createImageTempFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)));

        cropImage(cameraPictureUrl, cropPictureUrl);
    } catch (IOException e) {
        e.printStackTrace();

    }

}

public Uri getCameraUri() {
    return cameraUrl;
}

public Uri getCropImageUrl() {
    return selectedImageUri;
}

private void cropImage(final Uri sourceImage, Uri destinationImage) {
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

    intent.setType("image/*");

    List<ResolveInfo> list = mContext.getPackageManager().queryIntentActivities(intent, 0);
    int size = list.size();
    if (size == 0) {
        //Utils.showToast(mContext, mContext.getString(R.string.error_cant_select_cropping_app));
        selectedImageUri = sourceImage;
        intent.putExtra(MediaStore.EXTRA_OUTPUT, sourceImage);
        ((Activity) mContext).startActivityForResult(intent, SELECTED_IMG_CROP);
        return;
    } else {
        intent.setDataAndType(sourceImage, "image/*");
        intent.putExtra("aspectX", ASPECT_X);
        intent.putExtra("aspectY", ASPECT_Y);
        intent.putExtra("outputY", OUT_PUT_Y);
        intent.putExtra("outputX", OUT_PUT_X);
        intent.putExtra("scale", SCALE);

        //intent.putExtra("return-data", true);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, destinationImage);
        selectedImageUri = destinationImage;
        if (size == 1) {
            Intent i = new Intent(intent);
            ResolveInfo res = list.get(0);
            i.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
            ((Activity) mContext).startActivityForResult(intent, SELECTED_IMG_CROP);
        } else {
            Intent i = new Intent(intent);
            i.putExtra(Intent.EXTRA_INITIAL_INTENTS, list.toArray(new Parcelable[list.size()]));
            ((Activity) mContext).startActivityForResult(intent, SELECTED_IMG_CROP);
        }
    }
}
}

FileUtil.java

public class FileUtil {
private static FileUtil sSingleton;
private Context context;

private FileUtil(Context ctx) {
    context = ctx;
}

/**
 * Gets instance.
 *
 * @param ctx the ctx
 * @return the instance
 */
public static FileUtil getInstance(Context ctx) {
    if (sSingleton == null) {
        synchronized (FileUtil.class) {
            sSingleton = new FileUtil(ctx);
        }
    }
    return sSingleton;
}

public Uri createImageUri() {
    ContentResolver contentResolver = context.getContentResolver();
    ContentValues cv = new ContentValues();
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
    cv.put(MediaStore.Images.Media.TITLE, timeStamp);
    return contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cv);
}

/**
 * Create image temp file file.
 *
 * @param filePathDir the file path dir
 * @return the file
 * @throws IOException the io exception
 */
@SuppressLint("SimpleDateFormat")
public File createImageTempFile(File filePathDir) throws IOException {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

    String imageFileName = "JPEG_" + timeStamp + "_";
    return File.createTempFile(
            imageFileName,  /* prefix */
            ".jpg",         /* suffix */
            filePathDir      /* directory */
    );
}

public static  String getUploadFileName() {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US);
    Date date = new Date();
    return String.format("profile_%s.png", sdf.format(date));
}

 //add this code(edited)
 //get Path
  @TargetApi(Build.VERSION_CODES.KITKAT)
  public static String getRealPathFromURI(Context context, final Uri uri) {
    final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;

    // DocumentProvider
    if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
        // ExternalStorageProvider
        if (isExternalStorageDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            if ("primary".equalsIgnoreCase(type)) {
                return Environment.getExternalStorageDirectory() + "/" + split[1];
            }
        }
        // DownloadsProvider
        else if (isDownloadsDocument(uri)) {
            final String id = DocumentsContract.getDocumentId(uri);
            final Uri contentUri = ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));

            return getDataColumn(context, contentUri, null, null);
        }
        // MediaProvider
        else if (isMediaDocument(uri)) {
            final String docId = DocumentsContract.getDocumentId(uri);
            final String[] split = docId.split(":");
            final String type = split[0];

            Uri contentUri = null;
            if ("image".equals(type)) {
                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
            } else if ("video".equals(type)) {
                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
            } else if ("audio".equals(type)) {
                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
            }

            final String selection = "_id=?";
            final String[] selectionArgs = new String[]{
                    split[1]
            };

            return getDataColumn(context, contentUri, selection, selectionArgs);
        }
    }
    // MediaStore (and general)
    else if ("content".equalsIgnoreCase(uri.getScheme())) {
        // Return the remote address
        if (isGooglePhotosUri(uri))
            return uri.getLastPathSegment();

        return getDataColumn(context, uri, null, null);
    }
    // File
    else if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
    } else
        return getRealPathFromURIDB(uri);

    return null;
}

/**
 * Gets real path from uri.
 *
 * @param contentUri the content uri
 * @return the real path from uri
 */
private static String getRealPathFromURIDB(Uri contentUri) {
    Cursor cursor = context.getContentResolver().query(contentUri, null, null, null, null);
    if (cursor == null) {
        return contentUri.getPath();
    } else {
        cursor.moveToFirst();
        int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        String realPath = cursor.getString(index);
        cursor.close();
        return realPath;
    }
}

/**
 * Gets data column.
 *
 * @param uri           the uri
 * @param selection     the selection
 * @param selectionArgs the selection args
 * @return the data column
 */
public static String getDataColumn(Context context, Uri uri, String selection,
                                   String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {
            column
    };

    try {
        cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
                null);
        if (cursor != null && cursor.moveToFirst()) {
            final int index = cursor.getColumnIndexOrThrow(column);
            return cursor.getString(index);
        }
    } finally {
        if (cursor != null)
            cursor.close();
    }
    return null;
}

/**
 * Is external storage document boolean.
 *
 * @param uri The Uri to check.
 * @return Whether the Uri authority is ExternalStorageProvider.
 */
public static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
}

/**
 * Is downloads document boolean.
 *
 * @param uri The Uri to check.
 * @return Whether the Uri authority is DownloadsProvider.
 */
public static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}

/**
 * Is media document boolean.
 *
 * @param uri The Uri to check.
 * @return Whether the Uri authority is MediaProvider.
 */
public static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
}

/**
 * Is google photos uri boolean.
 *
 * @param uri The Uri to check.
 * @return Whether the Uri authority is Google Photos.
 */
public static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
  }

PermissionUtil.java

public class PermissionUtil {
      private String[] galleryPermissions = {
          "android.permission.WRITE_EXTERNAL_STORAGE",
          "android.permission.READ_EXTERNAL_STORAGE"
      };

private String[] cameraPermissions = {
        "android.permission.CAMERA",
        "android.permission.WRITE_EXTERNAL_STORAGE",
        "android.permission.READ_EXTERNAL_STORAGE"
};

public String[] getGalleryPermissions(){
    return galleryPermissions;
}

public String[] getCameraPermissions() {
    return cameraPermissions;
}

public boolean verifyPermissions(Context context, String[] grantResults) {
    for (String result : grantResults) {
        if (ActivityCompat.checkSelfPermission(context, result) != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}

public boolean checkMarshMellowPermission(){
    return(Build.VERSION.SDK_INT> Build.VERSION_CODES.LOLLIPOP_MR1);
}

public static void showPermissionDialog(Context mContext,String msg){
    AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.DatePicker);
    builder.setTitle("Need Permission");
    builder.setMessage(msg);
    builder.setPositiveButton(mContext.getString(R.string.invitation_yes), (dialogInterface, i) -> {
        dialogInterface.dismiss();
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", mContext.getPackageName(), null);
        intent.setData(uri);
        (mContext).startActivity(intent);
    });

    builder.setNegativeButton(mContext.getString(R.string.invitation_del_no), (dialogInterface, i) -> {
        dialogInterface.dismiss();
    });
    builder.show();
}

}

provide_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

【讨论】:

  • 你做得很好,但你能告诉我如何删除裁剪部分并获得完整图像
  • @Shweta 你能在这里发帖吗PermissionUtil 文件
  • 是的。让我补充一下。
  • @pb123 PermissionUtil 类已添加。
  • @KrishnakantDalal :对于 android 7,我也遇到了同样的错误,之后我添加了这个答案。现在,我还必须检查 Android 8.0。每当我解决问题时通知您。
【解决方案3】:

我有两个裁剪来源,一个是画廊,另一个是相机

方法库:

//take a photo from gallery
public void gallery() {
    //set UUID to filename
    String PHOTO_FILE_NAME = UUID.randomUUID().toString()+".jpg";
    Utils.putValue(this, Constants.UserPortraitFilePath,PHOTO_FILE_NAME);
    Intent intent = new Intent(Intent.ACTION_PICK);
    intent.setType("image/*");
    startActivityForResult(intent, PHOTO_REQUEST_GALLERY);
}

方法相机:

    //take a photo from camera
public void camera() {
    //check sdcard is usable or not
    if (Utils.hasSdcard()) {
        //set UUID to filename
        String PHOTO_FILE_NAME = UUID.randomUUID().toString()+".jpg";
        Utils.putValue(this,Constants.UserPortraitFilePath,PHOTO_FILE_NAME);
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        //set file location to DreamGo/Image
        File path = Environment.getExternalStorageDirectory();
        File dir = new File(path, "DreamGo/Image");
        if(!dir.exists())
            dir.mkdirs();
        //Android N need use FileProvider get file 
        //uri because StrictMode System
        //getUriForFile(content,provider author,file)
        Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider",
                new File(dir.getAbsolutePath(), PHOTO_FILE_NAME));
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
        startActivityForResult(intent, PHOTO_REQUEST_CAMERA);
    }else {
        showToast("no storage device");
    }
}

裁剪方法:

    //Android N crop image
public void crop(Uri uri) {
    context.grantUriPermission("com.android.camera",uri,
            Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    //Android N need set permission to uri otherwise system camera don't has permission to access file wait crop
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.putExtra("crop", "true");
    //The proportion of the crop box is 1:1
    intent.putExtra("aspectX", 1);
    intent.putExtra("aspectY", 1);
    //Crop the output image size
    intent.putExtra("outputX", 800);
    intent.putExtra("outputY", 800);
    //image type
    intent.putExtra("outputFormat", "JPEG");
    intent.putExtra("noFaceDetection", true);
    //true - don't return uri |  false - return uri
    intent.putExtra("return-data", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    startActivityForResult(intent, PHOTO_REQUEST_CUT);
}

onActivityResult 方法:

private static final int PHOTO_REQUEST_CAMERA = 0;//camera
private static final int PHOTO_REQUEST_GALLERY = 1;//gallery
private static final int PHOTO_REQUEST_CUT = 2;//image crop
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    String PHOTO_FILE_NAME = Utils.getValue(this, Constants.UserPortraitFilePath);
    File path = Environment.getExternalStorageDirectory();
    File dir = new File(path, "DreamGo/Image");
    if(!dir.exists())
        dir.mkdirs();
    switch (requestCode)
    {
        case PHOTO_REQUEST_GALLERY:
            if (data != null){
                //file from gallery
                File sourceFile = new File(getRealPathFromURI(data.getData()));
                //blank file DreamGo/Image/uuid.jpg
                File destFile = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
                Log.e("photo",data.getData().getPath());
                try {
                    //copy file from gallery to DreamGo/Image/uuid.jpg
                    // otherwise crop method can't cut image without write permission
                    copyFile(sourceFile,destFile);
                    //Android N need use FileProvider to get file uri
                    Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider", destFile);
                    //cut image
                    crop(photoURI);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            break;
        case PHOTO_REQUEST_CAMERA:
            //whether sdcard is usable has been checked before use camera
            File tempFile = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
            Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider", tempFile);
            crop(photoURI);
            break;
        case PHOTO_REQUEST_CUT:
            try {
                if(data!=null) {
                    file = new File(dir.getAbsolutePath(), PHOTO_FILE_NAME);
                    icon.loadImage("file://" + file.getAbsolutePath());
                }else {
                    showToast("a error happened when cut picture");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            break;
        default:
            break;
    }
}

真实代码:

//copy sourceFile to destFile
public void copyFile(File sourceFile, File destFile) throws IOException {
    if (!sourceFile.exists()) {
        return;
    }
    FileChannel source = new FileInputStream(sourceFile).getChannel();
    FileChannel destination = new FileOutputStream(destFile).getChannel();
    if (destination != null && source != null) {
        destination.transferFrom(source, 0, source.size());
    }
    if (source != null) {
        source.close();
    }
    if (destination != null) {
        destination.close();
    }
}

//file uri to real location in filesystem
public String getRealPathFromURI(Uri contentURI) {
    Cursor cursor = getContentResolver().query(contentURI, null, null, null, null);
    if (cursor == null) {
        // Source is Dropbox or other similar local file path
        return contentURI.getPath();
    } else {
        cursor.moveToFirst();
        int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        return cursor.getString(idx);
    }
}

public static final String getValue(Context context, String key) {
    return getSharedPreference(context).getString(key, "");
}
public static final boolean putValue(Context context, String key,
                                     String value) {
    value = value == null ? "" : value;
    SharedPreferences.Editor editor = getSharedPreference(context).edit();
    editor.putString(key, value);
    boolean result = editor.commit();
    if (!result) {
        return false;
    }
    return true;
}

【讨论】:

  • Uri photoURI = FileProvider.getUriForFile(context, "dream.go.provider", destFile);在这些行中,我正在获取文件未找到异常
【解决方案4】:

你在 Manifest.xml 中添加了这个吗??

<application
        ........
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
</application>

这必须存在于您的清单中.. 才能在 naugut android 7.0 中生效。

再次,您需要在 xml 中添加 provider_paths.xml 文件。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

【讨论】:

  • 我参考了本教程,并从本教程中获得了此解决方案(提供者)。从本教程中,我完成了使用 camare 进行裁剪,但裁剪后崩溃。
【解决方案5】:
    Uri uri = FileProvider.getUriForFile(this, getPackageName() + Configs.FILE_PROVIDER_NAME, inFile);
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
    intent.setDataAndType(uri, "image/*");
    intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(outFile));

您应该注意到 EXTRA_OUTPUT 的 uri 不应被 FileProvider 修改。 你的paths.xml应该是这样的

<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_sd" path="."/>
<external-files-path name="external_app" path="."/>
<files-path name="files" path="."/>
<cache-path name="cache" path="."/>

因为您在 getExternalFilesDir 下创建了裁剪文件。所以&lt;external-files-path&gt;是必要的。

【讨论】:

    【解决方案6】:

    以下解决方案对我有用。我已经使用图库、Google 云端硬盘、照片等进行了测试。

    示例采用Kotlin 语言。

    ImagePickUtils.kt

    fun getImageUri(context: Context, contentURI: String): Uri {
        var conUri = Uri.parse(contentURI)
        var filePath = ""
        if (DocumentsContract.isDocumentUri(context, conUri)) {
            val wholeID = DocumentsContract.getDocumentId(conUri)
    
            // Split at colon, use second item in the array
            val id = wholeID.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
    
            val column = arrayOf(MediaStore.Images.Media.DATA)
    
            // where id is equal to
            val sel = MediaStore.Images.Media._ID + "=?"
    
            val cursor = context.contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, arrayOf(id), null) ?: return conUri
    
            val columnIndex = cursor.getColumnIndex(column[0])
    
            if (cursor.moveToFirst()) {
                filePath = cursor.getString(columnIndex)
            }
            cursor.close()
    
            if (filePath.isNotEmpty()) {
                filePath = filePath.replace(" ".toRegex(), "%20")
                conUri = Uri.parse("file://$filePath")
            }
        }
        return conUri
    }
    

    onActivityResult 的 Activity / Fragment:

    if (data != null) {
        val imagePath: Uri
        if (data.data != null) {
               val mImageUri = data.data
               imagePath = getImageUri(this@HomeActivity, mImageUri.toString())
               Log.i(TAG+" Image actual path", imagePath.toString())
        }
    }
    

    希望这会对你有所帮助。

    【讨论】:

      【解决方案7】:
      Intent pickImageIntent = new Intent("com.android.camera.action.CROP");
      Uri contentUri = imageUri;
      pickImageIntent.setDataAndType(contentUri, "image/*");
      pickImageIntent.putExtra("crop", "true");
      pickImageIntent.putExtra("aspectX", 1);
      pickImageIntent.putExtra("aspectY", 1);
      pickImageIntent.putExtra("outputX", 400);
      pickImageIntent.putExtra("outputY", 400);
      pickImageIntent.putExtra("return-data", true);
      startActivityForResult(pickImageIntent, RESULT_CROP);
      

      【讨论】:

      • 您应该提供额外的context 关于如何和/或为什么此代码解决问题。这将提高答案的长期价值。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人!请edit您的答案添加解释,并说明适用的限制和假设。提及为什么这个答案比其他答案更合适也没有什么坏处。
      【解决方案8】:

      这对我来说就像 Marshmallow 和 7.1.2 (Naugat) 的魅力一样

      1. this answer 中所述,要从相机中挑选图像,请按照this 博客中的以下步骤操作:

      为 Marshmallow 和 7.1.2 (Naugat) 编写此步骤中描述的代码

      1. 要裁剪图像,如果你想使用intent com.android.camera.action.CROP(实际上不推荐但仍然有很多开发人员使用),那么你可以用旧样式的URI调用这些方法。即Uri.fromFile(file)

      cropIntent.setDataAndType(Uri.fromFile(file), "image/*");

      cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));

      以及其他方法(请搜索如何调用意图com.android.camera.action.CROP

      最后,之前调用startActivityForResult(cropIntent, CROP_ACTIVITY_CODE) 一定要写这个...

              if(Build.VERSION.SDK_INT>=24)
              {
                  try
                  {
                      Method m = StrictMode.class.getMethod("disableDeathOnFileUriExposure");
                      m.invoke(null);
                  }
                  catch(Exception e)
                  {
                      e.printStackTrace();
                  }
              }
      

      就是这样!我希望它可以帮助某人。

      【讨论】:

        【解决方案9】:

        您可以轻松使用此library,这将有助于从样板代码中清除您的项目以进行图像挑选和裁剪。

        【讨论】:

          【解决方案10】:
          Intent intent = new Intent("com.android.camera.action.CROP"); 
          

          这种裁剪方法不适用于谷歌照片,我意识到并非所有设备和画廊都支持它,所以我创建了自己的裁剪方法。如果有人也可以帮助我解决这个问题,我仍然面临两个小问题。否则这个类可以正常工作。

          可绘制:

          crop_rectangle.xml

          <?xml version="1.0" encoding="utf-8"?>
          <shape xmlns:android="http://schemas.android.com/apk/res/android"
          android:shape="rectangle">
          
          <stroke android:color="@color/white"
              android:width="3dp"
              android:dashGap="10dp"
              android:dashWidth="10dp"/>
          </shape>
          

          布局: activity_crop.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:layout_width="match_parent"
          android:layout_height="match_parent"
          android:background="@color/black">
          
          <androidx.constraintlayout.widget.ConstraintLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_marginVertical="70dp">
          
              <FrameLayout
          
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  app:layout_constraintBottom_toBottomOf="parent"
                  app:layout_constraintTop_toTopOf="parent">
          
                  <ImageView
                      android:id="@+id/full_screen_image_view"
                      android:layout_width="match_parent"
                      android:layout_height="wrap_content"
                      android:adjustViewBounds="true"
                      android:scaleType="centerCrop"
                      app:layout_constraintBottom_toBottomOf="parent"
                      app:layout_constraintTop_toTopOf="parent"
                      tools:tint="#aa111111" />
          
                  <androidx.constraintlayout.widget.ConstraintLayout
                      android:id="@+id/image_container"
                      android:layout_width="match_parent"
                      android:layout_height="match_parent">
          
                      <ImageView
                          android:id="@+id/crop_area"
                          android:layout_width="0dp"
                          android:layout_height="0dp"
                          android:layout_centerInParent="true"
                          android:adjustViewBounds="true"
                          android:background="@drawable/crop_rectangle"
                          android:scaleType="fitCenter"
                          app:layout_constraintBottom_toBottomOf="parent"
                          app:layout_constraintEnd_toEndOf="parent"
                          app:layout_constraintStart_toStartOf="parent"
                          app:layout_constraintTop_toTopOf="parent" />
          
                  </androidx.constraintlayout.widget.ConstraintLayout>
          
              </FrameLayout>
          
          </androidx.constraintlayout.widget.ConstraintLayout>
          
          <ImageView
              android:id="@+id/close_image_viewer"
              android:layout_width="30dp"
              android:layout_height="30dp"
              android:layout_margin="20dp"
              android:padding="5dp"
              android:src="@drawable/ic_close"
              app:layout_constraintStart_toStartOf="parent"
              app:layout_constraintTop_toTopOf="parent"
              app:tint="@color/white" />
          
          <ImageView
              android:id="@+id/save_image"
              android:layout_width="30dp"
              android:layout_height="30dp"
              android:layout_margin="20dp"
              android:padding="5dp"
              android:scaleType="fitCenter"
              android:src="@drawable/ic_tick"
              app:layout_constraintEnd_toEndOf="parent"
              app:layout_constraintTop_toTopOf="parent"
              app:tint="@color/white" />
          
          </androidx.constraintlayout.widget.ConstraintLayout>
          

          CropActivity.kt

          class CropActivity : Activity() {
          
          private lateinit var closeBt: ImageView
          private lateinit var imageView: ImageView
          private lateinit var cropArea: ImageView
          private lateinit var saveImage: ImageView
          
          private var mScaleGestureDetector: ScaleGestureDetector? = null
          private var mGestureListener: GestureDetector? = null
          var mScaleFactor = 1.0f
          var xPos = 0.0f
          var yPos = 0.0f
          val minZoom = 0.2f
          val maxZoom = 1.0f
          
          lateinit var bmp: Bitmap
          
          var oldE2X: Float = 0f
          var oldE2Y: Float = 0f
          var height: Int = 0
          var width: Int = 0
          
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_crop)
              closeBt = findViewById(R.id.close_image_viewer)
              imageView = findViewById(R.id.full_screen_image_view)
              cropArea = findViewById(R.id.crop_area)
              saveImage = findViewById(R.id.save_image)
          
              val displayMetrics = DisplayMetrics()
              windowManager.defaultDisplay.getMetrics(displayMetrics)
              height = displayMetrics.heightPixels
              width = displayMetrics.widthPixels
          
              val filepath = intent.getStringExtra(AppConsts.IMAGE_STRING)
              try {
                  //val file = File(filepath!!)
                  bmp = getResizedBitmap(BitmapFactory.decodeFile(filepath), width)!!
                  imageView.setImageBitmap(bmp)
          
                  val layoutParams = cropArea.layoutParams as ConstraintLayout.LayoutParams
                  val ratio = if (intent.hasExtra(AppConsts.IMAGE_RATIO))
                      intent.getStringExtra(AppConsts.IMAGE_RATIO)
                  else
                      "H,1:1"
          
                  layoutParams.dimensionRatio = ratio
          
                  val imageWidth = bmp.width
                  val imageHeight = bmp.height
                  val bitmapRatio: Float = imageWidth.toFloat() / imageHeight.toFloat()
          
                  cropArea.layoutParams = layoutParams
          
                  if (bitmapRatio <= 1f) {
                      cropArea.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
                  } else {
                      cropArea.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
                  }
          
              } catch (e: Exception) {
                  e.printStackTrace()
                  Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
                  finish()
              }
          
              xPos = cropArea.x
              yPos = cropArea.y
              mScaleGestureDetector = ScaleGestureDetector(this, ScaleListener())
              mGestureListener = GestureDetector(this, GestureListener())
          
              saveImage.setOnClickListener {
                  saveImage()
              }
          
          }
          
          private fun saveImage() {
              val loc = IntArray(2)
              cropArea.getLocationOnScreen(loc)
          
              val locImage = IntArray(2)
              imageView.getLocationOnScreen(locImage)
          
              var bx = loc[0] - locImage[0]
              var by = loc[1] - locImage[1]
              val bWidth = (cropArea.width * mScaleFactor).toInt()
              val bHeight = (cropArea.height * mScaleFactor).toInt()
          
              if (bx + bWidth > bmp.width)
                  bx = getCorrectBx(bx, bWidth)
          
              if (bx < 0)
                  bx = 0
          
              if (by + bHeight > bmp.height)
                  by = getCorrectYx(by, bHeight)
          
              if (by < 0)
                  by = 0
          
              val croppedBmp: Bitmap = Bitmap.createBitmap(
                  bmp,
                  bx,
                  by,
                  bWidth,
                  bHeight
              )
          
              val dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath
              val file = File(dir!!)
              if (!file.exists())
                  file.mkdirs()
          
              val path = "$dir/cameraResult.png"
              val image = File(path)
              if (!image.exists())
                  image.createNewFile()
          
              val byteArrayOutputStream = ByteArrayOutputStream()
              croppedBmp.compress(Bitmap.CompressFormat.PNG, 30, byteArrayOutputStream)
              val byteArray: ByteArray = byteArrayOutputStream.toByteArray()
              image.writeBytes(byteArray)
          
              val data = Intent()
              data.putExtra(AppConsts.FILE_URI, Uri.fromFile(image).toString())
              setResult(RESULT_OK, data)
              finish()
              //imageView.setImageBitmap(croppedBmp)
          }
          
          private fun getCorrectBx(bx: Int, bWidth: Int): Int {
              val newbx = bx - (bmp.width - (bx + bWidth) + 10)
              return if (newbx + bWidth > bmp.width)
                  getCorrectBx(newbx, bWidth)
              else
                  newbx
          }
          
          private fun getCorrectYx(by: Int, bHeight: Int): Int {
              val newby = by - (bmp.height - (by + bHeight) + 10)
              return if (newby + bHeight > bmp.height)
                  getCorrectBx(newby, bHeight)
              else
                  newby
          }
          
          override fun onTouchEvent(motionEvent: MotionEvent?): Boolean {
              super.onTouchEvent(motionEvent)
              mScaleGestureDetector!!.onTouchEvent(motionEvent)
              mGestureListener!!.onTouchEvent(motionEvent)
              return true
          }
          
          inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
              override fun onScale(scaleGestureDetector: ScaleGestureDetector): Boolean {
                  mScaleFactor *= scaleGestureDetector.scaleFactor
                  mScaleFactor = minZoom.coerceAtLeast(mScaleFactor.coerceAtMost(maxZoom))
                  cropArea.scaleX = mScaleFactor
                  cropArea.scaleY = mScaleFactor
                  val loc = IntArray(2)
                  cropArea.getLocationOnScreen(loc)
                  return true
              }
          }
          
          inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
              override fun onScroll(
                  e1: MotionEvent?,
                  e2: MotionEvent?,
                  distanceX: Float,
                  distanceY: Float
              ): Boolean {
                  val oldCropLoc = IntArray(2)
                  cropArea.getLocationOnScreen(oldCropLoc)
          
                  val locImage = IntArray(2)
                  imageView.getLocationOnScreen(locImage)
          
                  if (oldE2X - e2!!.x > 100f || oldE2X - e2.x < -100f) {
                      oldE2X = e2.x
                      return true
                  }
          
                  if (oldE2Y - e2.y > 100f || oldE2Y - e2.y < -100f) {
                      oldE2Y = e2.y
                      return true
                  }
          
                  when {
                      oldCropLoc[0] < locImage[0] + 10f && (oldE2X - e2.x) > 0f -> {
                          //cropArea.translationX = (-oldCropLoc[0]).toFloat()
                          //cropArea.left = imageView.left + 1
                          oldE2X = width.toFloat()
                      }
          
                      (oldCropLoc[0] + cropArea.width * mScaleFactor) + 10f > locImage[0] + imageView.width &&
                              (oldE2X - e2.x) < 0f -> {
                          //cropArea.right = imageView.right - 1
                          oldE2X = 0f
                      }
          
                      else -> {
                          xPos += distanceX
                          cropArea.translationX = -xPos
                      }
                  }
          
                  when {
                      oldCropLoc[1] < locImage[1] + 10f && (oldE2Y - e2!!.y) > 0f -> {
                          //cropArea.top = imageView.top + 1
                          oldE2Y = height.toFloat()
                      }
          
                      (oldCropLoc[1] + cropArea.height * mScaleFactor) + 10f > locImage[1] + imageView.height &&
                              (oldE2Y - e2.y) < 0f -> {
                          oldE2Y = 0f
                          //cropArea.bottom = imageView.bottom - 1
                      }
          
                      else -> {
                          yPos += distanceY
                          cropArea.translationY = -yPos
                      }
                  }
                  oldE2X = e2.x
                  oldE2Y = e2.y
                  return true
              }
          }
          
          private fun highlightPixels(myBitmap: Bitmap/*, a: Int, b: Int, c: Int, d: Int*/){
              val pixels = IntArray(myBitmap.height * myBitmap.width)
              myBitmap.getPixels(pixels, 0, myBitmap.width, 0, 0, myBitmap.width, myBitmap.height)
              for (i in 0 until myBitmap.width * 5) pixels[i] = Color.BLUE
              myBitmap.setPixels(pixels, 0, myBitmap.width, 0, 0, myBitmap.width, myBitmap.height)
          }
          
          private fun getResizedBitmap(image: Bitmap, maxSize: Int): Bitmap? {
              var width = image.width
              var height = image.height
              val bitmapRatio = width.toFloat() / height.toFloat()
              width = maxSize
              height = (width / bitmapRatio).toInt()
              return Bitmap.createScaledBitmap(image, width, height, true)
          }
          }
          

          使用方法:

          假设您从图像选择器中获取正确的 Uri,则从您的图像选择活动中。将该 Uri 传递给以下函数:

          private fun openCropActivity(contentUri: Uri) {
              val bitmap = MediaStore.Images.Media.getBitmap(
                  contentResolver, contentUri
              )
          
              val dir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.absolutePath
              val file = File(dir!!)
              if (!file.exists())
                  file.mkdirs()
          
              val path = "$dir/cameraResult.png"
              val image = File(path)
              if (!image.exists())
                  image.createNewFile()
          
              val byteArrayOutputStream = ByteArrayOutputStream()
              bitmap.compress(Bitmap.CompressFormat.PNG, 30, byteArrayOutputStream)
              val byteArray: ByteArray = byteArrayOutputStream.toByteArray()
              image.writeBytes(byteArray)
          
              val cropIntent = Intent(this, CropActivity::class.java)
              cropIntent.putExtra(AppConsts.IMAGE_STRING, path)
              startActivityForResult(cropIntent, RESULT_CROP)
          }
          

          并在您的活动结果中获取裁剪图像的 uri,如下所示

          if (resultCode == RESULT_OK && data != null) {
              val uri: Uri? = Uri.parse(data.getStringExtra(AppConsts.FILE_URI))
          }
          

          根据您的意愿分配常量。

          我面临的两个问题是。

          1. 纵横比仍然是您从意图中获得的固定比例,如果不是,则为 1:1。您无法使用手势或任何方式更改纵横比

          2. 我想突出显示未裁剪/裁剪的区域,以便在背景为白色时可以轻松区分这些区域。

          【讨论】:

            猜你喜欢
            • 2016-11-19
            • 1970-01-01
            • 2012-06-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-12-21
            • 2017-06-25
            • 1970-01-01
            相关资源
            最近更新 更多