美文网首页Android 进阶技术篇专题我爱编程Android知识
Android 从相册选取图片,拍照、裁剪一篇就够了

Android 从相册选取图片,拍照、裁剪一篇就够了

作者: SwitchLife | 来源:发表于2018-05-08 19:21 被阅读141次

    开篇

      基于我们开App发过程中经常要选择图片(或拍照)并裁剪做为头像上传到服务器,我把选取图片、拍照、裁剪图片功能整理优化了,有了它你再也不用为这些芝麻小事所烦恼啦!这一篇就够了!

    立即体验

    扫描以下二维码下载体验App(从0.2.3版本开始,体验App内嵌版本更新检测功能):


    JSCKit库传送门:https://github.com/JustinRoom/JSCKit

    源码简析

    • void onActivityResult(int requestCode, int resultCode, Intent data)中处理选择、拍照、裁剪结果:
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            if (resultCode != RESULT_OK)
                return;
    
            switch (requestCode) {
                case REQUEST_CODE_PIC_PHOTO://手机相册
                    onPickPhotoResult(data.getData());
                    break;
                case REQUEST_CODE_TAKE_PHOTO://拍照
                    onTakePhotoResult(FileProviderCompat.getUriForFile(this, takePhotoTempFile), takePhotoTempFile);
                    break;
                case REQUEST_CODE_PHOTO_CROP://裁剪
                    onCropPhotoResult(data.getData(), cropPhotoTempFile);
                    break;
            }
        }
    

    在使用到Uri,请注意兼容Android7.0。FileProviderCompat.java

    • 1、从相册选取图片

    特别提示:
    1、需要权限android.permission.READ_EXTERNAL_STORAGE

        public void openAlbum() {
            Intent intent = new Intent(Intent.ACTION_PICK);
            intent.setDataAndType(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*");
            startActivityForResult(intent, REQUEST_CODE_PIC_PHOTO);
        }
    
    • 2、调用系统相机拍照

    特别提示:
    1、需要权限android.permission.WRITE_EXTERNAL_STORAGEandroid.permission.CAMERA

        public void openCamera(File directory, String photoPathName) {
            //如果没有设置文件夹,拍照后则保存在sdk根目录的Pictures文件夹下面
            if (directory == null)
                directory = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
    
            //如果没有设置图片名称,则根据当前系统时间设置默认的图片名称
            if (photoPathName == null || photoPathName.trim().length() == 0)
                photoPathName = getDefaultTakePhotoFileName(Bitmap.CompressFormat.JPEG);
    
            takePhotoTempFile = new File(directory, photoPathName);
            String takePhotoTempFilePath = takePhotoTempFile.getPath();
            //如果保存图片的文件夹还没有创建,则创建文件夹
            File dir = new File(takePhotoTempFilePath.substring(0, takePhotoTempFilePath.lastIndexOf(File.separator)));
            if (!dir.exists())
                dir.mkdirs();
    
            Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderCompat.getUriForFile(this, takePhotoTempFile));
            startActivityForResult(cameraIntent, REQUEST_CODE_TAKE_PHOTO);
        }
    
    • 3、裁剪

    特别提示:
    1、需要权限android.permission.WRITE_EXTERNAL_STORAGE
    2、如果有设置aspectX、aspectY或者outputX、outputY,那么它就是按比例裁剪;否则是自由裁剪
    3、比例优先。举个栗子:如果有设置aspectX=4、aspectY=3、outputX=480、outputY=560,那么它裁剪时真正的outputX=480、outputY=360。

        /**
         * open system crop photo feature.
         * <br/>1、如果有设置aspectX、aspectY或者outputX、outputY,那么它就是按比例裁剪;否则是自由裁剪
         * <br/>2、比例优先。举个栗子:如果有设置aspectX=4、aspectY=3、outputX=480、outputY=560,那么它裁剪时真正的outputX=480、outputY=360。
         * <br/>Caller must ensure {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission.
         *
         * @param uri
         * @param config
         */
        public void cropPhoto(Uri uri,CropConfig config) {
            if (config == null)
                config = new CropConfig();
            Intent intent = new Intent("com.android.camera.action.CROP");
            FileProviderCompat.setDataAndType(intent, uri, "image/*", true);
            intent.putExtra(CropConfig.EXTRA_CROP, String.valueOf(config.isCrop()));
            int outputX = config.getOutputX();
            int outputY = config.getOutputY();
            int aspectX = config.getAspectX();
            int aspectY = config.getAspectY();
            boolean isOutputSet = outputX > 0 && outputY > 0;
            boolean isAspectSet = aspectX > 0 && aspectY > 0;
    
            if (isAspectSet) {
                intent.putExtra(CropConfig.EXTRA_ASPECT_X, aspectX);
                intent.putExtra(CropConfig.EXTRA_ASPECT_Y, aspectY);
                //如果有设置outputX、outputY,则根据aspectX、aspectY计算出合适的outputX、outputY
                if (isOutputSet) {
                    if (aspectX == aspectY) {
                        outputX = outputY = Math.min(outputX, outputY);
                    } else {
                        double ratioX = outputX * 1.0 / aspectX;
                        double ratioY = outputY * 1.0 / aspectY;
                        if (ratioX > ratioY) {//以outputY为标准
                            int avg = outputY / aspectY;
                            outputX = avg * aspectX;
                            outputY = avg * aspectY;
                        } else if (ratioX < ratioY) {//以outputX为标准
                            int avg = outputX / aspectX;
                            outputX = avg * aspectX;
                            outputY = avg * aspectY;
                        }
                    }
                    config.setOutputX(outputX);
                    config.setOutputY(outputY);
                }
            }
            if (isOutputSet) {
                intent.putExtra(CropConfig.EXTRA_OUTPUT_X, outputX);
                intent.putExtra(CropConfig.EXTRA_OUTPUT_Y, outputY);
            }
            intent.putExtra(CropConfig.EXTRA_SCALE, config.isScale());
            intent.putExtra(CropConfig.EXTRA_CIRCLE_CROP, String.valueOf(config.isCircleCrop()));
    
            //如果没有设置文件夹,裁剪后则保存在sdk根目录的Pictures文件夹下面
            File directory = config.getDirectory();
            if (directory == null){
                directory = new File(Environment.getExternalStorageDirectory(), Environment.DIRECTORY_PICTURES);
                config.setDirectory(directory);
            }
    
            //如果没有设置图片名称,则根据当前系统时间设置默认的图片名称
            String photoPathName = config.getPhotoPathName();
            if (photoPathName == null || photoPathName.trim().length() == 0){
                photoPathName = getDefaultCropPhotoFileName(config.getOutputFormat());
                config.setPhotoPathName(photoPathName);
            }
            cropPhotoTempFile = new File(directory, photoPathName);
            String cropPhotoTempFilePath = cropPhotoTempFile.getPath();
            //如果保存图片的文件夹还没有创建,则创建文件夹
            File dir = new File(cropPhotoTempFilePath.substring(0, cropPhotoTempFilePath.lastIndexOf(File.separator)));
            if (!dir.exists())
                dir.mkdirs();
    
            intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProviderCompat.getUriForFile(this, cropPhotoTempFile));
            intent.putExtra(CropConfig.EXTRA_RETURN_DATA, config.isReturnData());
            intent.putExtra(CropConfig.EXTRA_NO_FACE_DETECTION, config.isNoFaceDetection());
            intent.putExtra(CropConfig.EXTRA_OUTPUT_FORMAT, config.getOutputFormat().name());
            startActivityForResult(intent, REQUEST_CODE_PHOTO_CROP);
        }
    

    看看CropConfig.java请参照注释:

        public static final String EXTRA_CROP = "crop";
        public static final String EXTRA_ASPECT_X = "aspectX";
        public static final String EXTRA_ASPECT_Y = "aspectY";
        public static final String EXTRA_OUTPUT_X = "outputX";
        public static final String EXTRA_OUTPUT_Y = "outputY";
        public static final String EXTRA_SCALE = "scale";
        public static final String EXTRA_CIRCLE_CROP = "circleCrop";
        public static final String EXTRA_RETURN_DATA = "return-data";
        public static final String EXTRA_NO_FACE_DETECTION = "noFaceDetection";
        public static final String EXTRA_OUTPUT_FORMAT = "outputFormat";
    
        private boolean crop;//发送裁剪信号(不一定有效)
        private int aspectX;//X方向上的比例
        private int aspectY;//Y方向上的比例
        private int outputX;//裁剪后的图片的宽。与裁剪框的宽没有半毛钱关系,不要搞混了!
        private int outputY;//裁剪后的图片的高。与裁剪框的高没有半毛钱关系,不要搞混了!
        private boolean scale;//是否保留比例(不一定有效)
        private boolean circleCrop;//是否是圆形裁剪区域(不一定有效)
        private boolean returnData;//是否将数据保留在Bitmap中返回
        private boolean noFaceDetection;//是否取消人脸识别
    
        private File directory;//裁剪后的图片的保存目录
        private String photoPathName;//裁剪后的图片名称,可以包含目录路径
        private Bitmap.CompressFormat outputFormat;//裁剪后的图片格式,系统默认为jpeg格式(不一定有效)。如果文件格是png,但图片格式可能是jpeg。
    

    如何使用

    使用请参照这里https://github.com/JustinRoom/JSCKit/blob/master/app/src/main/java/jsc/exam/jsckit/ui/PhotoActivity.java

    篇尾

      如果在使用过程中有问题请给我留言,一起学习,一起进步!我是JustinEoyQQ:1006368252

    人类的全部历史都告诫有智慧的人,不要笃信时运,而应坚信思想。 —— 爱献生

    相关文章

      网友评论

      本文标题:Android 从相册选取图片,拍照、裁剪一篇就够了

      本文链接:https://www.haomeiwen.com/subject/rqairftx.html