Android 拍照或相册剪裁后取头像

作者: Kandy_JS | 来源:发表于2018-10-31 20:52 被阅读50次

    引用

    1、Android7.0 头像 拍照、照片裁剪
    2、联合使用:Android 仿IOS的PopupWindow和通用BasePopupWindow搭建

    截图

    crop_img.png croping.png

    实现

    1、功能步骤
    • 1.1、相机和相册使用到的权限
    • 1.2、打开相机、打开相册
    • 1.3、相机拍照回调、相册选取回调
    • 1.4、两种不同方式回调后的uri使用并开启剪裁
    • 1.5、剪裁图片回调、展示图片(各种样式)
    • 1.6、其他注意:android 7.0 后的共享文件FileProvider配置等
    2、工具类
    • 2.1、此工具类不一定符合所有业务,可自行扩展或者弄成接口类来完成各种功能
    • 2.2、使用相机:注意android 7.0的fileprovider来获取uri,完成拍照存储
    • 2.3、使用相册:注意ACTION_PICK和ACTION_GET_CONTENT的区别,并在不同api下返回的uri值不一样导致“无法加载图片”的问题,代码中写了注释
    • 2.4、相机图片剪裁:注意要加上intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);作为图片来源加载在剪切图中
    • 2.5、相册图片剪裁:不用加【2.4】内容
    • 2.6、剪裁输出源:可直接intent.putExtra("return-data", true);返回直接是bitmap有可能导致oom,还是设置false,然后靠uri来指向输出源比较好
    /**
     * Created by wujn on 2018/10/31.
     * Version : v1.0
     * Function: crop photo by camera or album
     */
    public class CropPhotoHelper {
        private Activity instance;
    
        // 裁剪后图片的宽(X)和高(Y),320 X 320的正方形。
        private static int output_X = 480;
        private static int output_Y = 480;
    
        private String localUserImgName ;       //原始拍照图片
        private String localUserImgPath;
        private Uri takePhotoUri;               //拍照的uri
    
        private String localUserCropImgName;    //最后的剪裁图片
        private String localUserCropImgPath;
        private Uri localUserIconUri;           //用户头像图片uri
    
        private String parentDir;               //父目录
    
    
        public CropPhotoHelper(Activity instance, String localUserImgName, String localUserCropImgName, String parentDir){
            this.instance = instance;
            this.localUserImgName = localUserImgName;
            this.localUserImgPath = parentDir + localUserImgName;
            this.localUserCropImgName = localUserCropImgName;
            this.localUserCropImgPath = parentDir + localUserCropImgName;
            this.parentDir = parentDir;
        }
    
    
        /**
         * 拍照
         * uri = content://.fileprovider/external_storage_root/xxx/xxx.jpg
         * */
        public void takePhoto(boolean isDeleteOld, int requestCode){
            FileUtil.mkDir(parentDir);
            File tmpFile=new File(localUserImgPath); //固定的,用户图片
    
            //删除旧的
            if (isDeleteOld) {
                try {
                    if (tmpFile.exists()) {
                        tmpFile.delete();//删除
                    }
                    tmpFile.createNewFile();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                takePhotoUri = Uri.fromFile(tmpFile);
            }else{
                takePhotoUri = FileProvider.getUriForFile(instance, Constant.FileProviderValue, tmpFile);
            }
    
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, takePhotoUri);
            //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
            //intent.putExtra("aspectX", 4);
            //intent.putExtra("aspectY", 3);
            //intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 120 * 1024);
            //intent.putExtra("return-data", true);
            instance.startActivityForResult(intent, requestCode);
        }
    
    
        /**
         * 打开相册
         * 1、Intent.ACTION_PICK,null :
         * uri=content://media/external/images/media/86916
         *
         * 2、Intent.ACTION_GET_CONTENT :
         *   (1)<=4.3 : uri 返回的是带文件路径的
         *   (2)>4.3 : uri 返回content://com.android.providers.media.documents/document/image:3951
         *       这样的,没有路径,只有图片编号的uri.这就导致接下来无法根据图片路径来裁剪的步骤了.
         * */
        public void openAlbum(int requestCode){
            //method 1
    //        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    //        intent.setType("image/*");
    
            //method 2
            Intent intent = new Intent(Intent.ACTION_PICK);
            //intent.setType("image*//*");
            intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,"image/*");
    
            instance.startActivityForResult(intent,requestCode);//打开相册
        }
    
    
    
        /**
         * 从相机拍照的图片剪裁
         * */
        public void cropRawByCamera(int requestCode){
            LogUtil.i("cropRawByCamera inputUri="+ takePhotoUri.toString());
            Intent intent = getCropImgIntent();
            //输入原始图片:来源于拍照
            if(takePhotoUri != null){
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent.setDataAndType(takePhotoUri, "image/*");
            }
            instance.startActivityForResult(intent, requestCode);
        }
    
        /**
         * 从相册图片剪裁
         * */
        public void cropRawByAlbum(Uri inputUri, int requestCode){
            LogUtil.i("cropRawByAlbum inputUri="+ inputUri.toString());
            Intent intent = getCropImgIntent();
            //输入原始图片:来源于相册
            if(inputUri != null){
                //intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                intent.setDataAndType(inputUri, "image/*");
            }
            instance.startActivityForResult(intent, requestCode);
        }
    
    
        /**
         * 裁剪原始的图片意图
         */
        private Intent getCropImgIntent(){
            //剪裁action
            Intent intent = new Intent("com.android.camera.action.CROP");
    
            // 设置裁剪
            intent.putExtra("crop", "true");
    
            // aspectX , aspectY :宽高的比例
            intent.putExtra("aspectX", 1);
            intent.putExtra("aspectY", 1);
    
            // outputX , outputY : 裁剪图片宽高
            intent.putExtra("outputX", output_X);
            intent.putExtra("outputY", output_Y);
            intent.putExtra("scale",true);
    
            // 返回类型和文件指向
            // return data is bitmap , maybe oom
            //intent.putExtra("return-data", true);             //返回bitmap
            intent.putExtra("return-data", false);  //返回uri
    
            //输出剪裁图片
            File cropFile = new File(localUserCropImgPath);
            try {
                if (cropFile.exists()){
                    cropFile.delete();//删除
                }
                cropFile.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
            localUserIconUri = Uri.fromFile(cropFile);
            if (localUserIconUri != null) {
                //intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, localUserIconUri);
            }
    
            //取消人脸识别
            intent.putExtra("noFaceDetection", true);
            //压缩图片
            intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    
            return intent;
    
        }
    
        /**
         * 获取剪切后的bitmap
         * */
        public Bitmap getCropBitmap(){
            try {
                return BitmapFactory.decodeStream(instance.getContentResolver().openInputStream(localUserIconUri));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        //获取剪裁后的路径
        public String getLocalUserCropImgPath() {
            return localUserCropImgPath;
        }
    }
    
    3、使用
    • 3.1、各种回调请求的code
    /**
         * 权限访问请求code
         * */
        public static final int REQUEST_PERMISSION_CODE = 1;
        public static final int REQUEST_PERMISSION_CODE_1 = 2;
    
        /**
         * ActivityResult回调的请求code
         * */
        public static final int REQUEST_TACKPIC_CODE = 10001;           //相机
        public static final int REQUEST_CHOOSE_PHOTO_CODE = 10002;      //相册
        public static final int REQUEST_CROP_IMAGE_CODE = 10003;        //剪裁图片
    
    • 3.2、使用相机和相册的权限询问
    • 3.3、按照【1】所说的步骤来使用
    • 3.4、图片最后使用了AvatarImageView来加载图片,这个剪裁图片加载就不再这里写了,可以使用的方法巨多...
    //剪裁帮助类
        private CropPhotoHelper cropPhotoHelper;
        @BindView(R.id.avatar_img) AvatarImageView avatar_img;
    
        @Override
        protected void init() {
            //剪裁帮助类:原始图片,剪裁图片,父目录
            cropPhotoHelper = new CropPhotoHelper(instance,
                    "img_org.jpg",
                    "img_crop.jpg",
                    Constant.IMG_DIR);
        }
    
        //拍照取图
        public void OnSelectCamera(View v){
            if (EasyPermissions.hasPermissions(instance, permissions_camear)) {
                cropPhotoHelper.takePhoto(false, Constant.REQUEST_TACKPIC_CODE);
            }else{
                EasyPermissions.requestPermissions(instance, "App 运行需要获取权限",Constant.REQUEST_PERMISSION_CODE, permissions_camear);
            }
        }
        //相册取图
        public void OnSelectAlbum(View v){
            if (EasyPermissions.hasPermissions(instance, permissions_album)) {
                cropPhotoHelper.openAlbum(Constant.REQUEST_CHOOSE_PHOTO_CODE);
            }else{
                EasyPermissions.requestPermissions(instance, "App 运行需要获取权限",Constant.REQUEST_PERMISSION_CODE_1, permissions_album);
            }
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (resultCode == RESULT_OK) {
                switch (requestCode) {
                    //拍照回调
                    case Constant.REQUEST_TACKPIC_CODE:
                        LogUtil.d("take picture success");
                        cropPhotoHelper.cropRawByCamera(Constant.REQUEST_CROP_IMAGE_CODE);
                        break;
    
                    //选择照片回调
                    case Constant.REQUEST_CHOOSE_PHOTO_CODE:
                        LogUtil.d("choose picture success");
                        if (data != null) {
                            //不同api下获取相册图片的path
                            //String photoPath = AppUtil.getPhotoPath(instance, data);
                            cropPhotoHelper.cropRawByAlbum(data.getData(),Constant.REQUEST_CROP_IMAGE_CODE);
                        } else {
                            ToastUtil.showShort(instance,"相册无返回值!");
                        }
                        break;
    
                    //剪裁完
                    case Constant.REQUEST_CROP_IMAGE_CODE:
                        Bitmap bitmap = cropPhotoHelper.getCropBitmap();
                        if(bitmap != null){
                            avatar_img.setBitmap(bitmap);
                        }else{
                            ToastUtil.showShort(instance,"剪裁失败!");
                        }
                        break;
    
                    default:
                        break;
                }
            }
    
        }
    
    
    
        //=============================================权限部分=====================================================
        //相机权限
        private String[] permissions_camear = {
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA
        };
        //文件权限
        private String[] permissions_album = {
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
        }
        @Override
        public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) {
            LogUtil.i("onPermissionsGranted requestCode="+requestCode);
            if(Constant.REQUEST_PERMISSION_CODE == requestCode){
                cropPhotoHelper.takePhoto(false, Constant.REQUEST_TACKPIC_CODE);
            }
            else if(Constant.REQUEST_PERMISSION_CODE_1 == requestCode){
                cropPhotoHelper.openAlbum(Constant.REQUEST_CHOOSE_PHOTO_CODE);
            }
    
        }
        @Override
        public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) {
            DialogUtil.errorDialog(instance,"拒绝开启,请前往APP应用设置中打开此权限");
        }
    
    哈哈,朝CV工程师在进一步!!!!

    相关文章

      网友评论

        本文标题:Android 拍照或相册剪裁后取头像

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