1. 程式人生 > >6.0以後授權手機攝像頭許可權拍照、選擇相簿照、裁剪

6.0以後授權手機攝像頭許可權拍照、選擇相簿照、裁剪

效果圖

                 

1.在res檔案裡面建立一個xml檔案,然後建立file_paths檔案

2.檔案裡面改成自己的包名

3.在AndroidMainfest.xml檔案新增如下程式碼,並修改成自己的包名

4.在需要的Activity頁面新增引用

import static android.support.v4.content.PermissionChecker.PERMISSION_GRANTED;

5.加入以下程式碼使用即可

    //開啟相機的返回碼
    private static final int CAMERA_REQUEST_CODE = 1;
    //選擇圖片的返回碼
    private static final int IMAGE_REQUEST_CODE = 2;
    //剪下圖片的返回碼
    public static final int CROP_REREQUEST_CODE = 3;
//    private ImageView iv;

    //相機
    public static final int REQUEST_CODE_PERMISSION_CAMERA = 100;

    public static final int REQUEST_CODE_PERMISSION_GALLERY = 101;

    //照片圖片名
    private String photo_image;
    //截圖圖片名
    private String crop_image;

    //拍攝的圖片的真實路徑
    private String takePath;
    //拍攝的圖片的虛擬路徑
    private Uri imageUri;
    private Uri cropUri;
    //    private File tempFile = new File(Environment.getExternalStorageDirectory().getPath() + "/photo.jpg");
    /**
     * 拍照
     *
     * @param view
     */
    public void onClickTakePhoto(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkPermission(REQUEST_CODE_PERMISSION_CAMERA);
            return;
        }
        openCamera();
    }

    private void openCamera() {
        if (isSdCardExist()) {
            Intent cameraIntent = new Intent(
                    "android.media.action.IMAGE_CAPTURE");

            photo_image = new SimpleDateFormat("yyyy_MMdd_hhmmss").format(new Date()) + ".jpg";
            imageUri = getImageUri(photo_image);
            cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT
                    , imageUri);
            //新增這一句表示對目標應用臨時授權該Uri所代表的檔案
            cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            cameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);
            startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);
        } else {
            Toast.makeText(this, "SD卡不存在", Toast.LENGTH_SHORT).show();
        }
    }


    /**
     * 開啟相簿
     * 不需要用FileProvider
     *
     * @param view
     */
    public void onClickOpenGallery(View view) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkPermission(REQUEST_CODE_PERMISSION_GALLERY);
            return;
        }
        openGallery();
    }

    private void openGallery() {

        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");//相片型別
        startActivityForResult(intent, IMAGE_REQUEST_CODE);
    }

    /**
     * @param path 原始圖片的路徑
     */
    public void cropPhoto(String path) {
        crop_image = new SimpleDateFormat("yyyy_MMdd_hhmmss").format(new Date()) + "_crop" +
                ".jpg";
        File cropFile = createFile(crop_image);
        File file = new File(path);


        Intent intent = new Intent("com.android.camera.action.CROP");
        //TODO:訪問相簿需要被限制,需要通過FileProvider建立一個content型別的Uri
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            //新增這一句表示對目標應用臨時授權該Uri所代表的檔案
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            //TODO:訪問相簿需要被限制,需要通過FileProvider建立一個content型別的Uri
            imageUri = FileProvider.getUriForFile(getApplicationContext(),
                    BuildConfig.APPLICATION_ID + ".provider", file);
            cropUri = Uri.fromFile(cropFile);
            //TODO:cropUri 是裁剪以後的圖片儲存的地方。也就是我們要寫入此Uri.故不需要用FileProvider
            //cropUri = FileProvider.getUriForFile(getApplicationContext(),
            //    BuildConfig.APPLICATION_ID + ".provider", cropFile);
        } else {
            imageUri = Uri.fromFile(file);
            cropUri = Uri.fromFile(cropFile);
        }

        intent.setDataAndType(imageUri, "image/*");
        intent.putExtra("crop", "true");
//        //設定寬高比例
//        intent.putExtra("aspectX", 1);
//        intent.putExtra("aspectY", 1);
        //設定裁剪圖片寬高
        intent.putExtra("outputX", 400);
        intent.putExtra("outputY", 400);
        intent.putExtra("scale", true);
        //裁剪成功以後儲存的位置
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        intent.putExtra("noFaceDetection", true);
        startActivityForResult(intent, CROP_REREQUEST_CODE);


    }


    /**
     * 獲得一個uri。該uri就是將要拍攝的照片的uri
     *
     * @return
     */
    private Uri getImageUri(String name) {
        if (isSdCardExist()) {
            File file = createFile(name);
            if (file != null) {
                takePath = file.getAbsolutePath();
                Log.e("zmm", "圖片的路徑---》" + takePath);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    return FileProvider.getUriForFile(getApplicationContext(),
                            BuildConfig.APPLICATION_ID + ".provider", file);
                } else {
                    return Uri.fromFile(file);
                }

            }
        }
        return Uri.EMPTY;
    }

    public File createFile(String name) {
        if (isSdCardExist()) {
            File[] dirs = ContextCompat.getExternalFilesDirs(this, null);
            if (dirs != null && dirs.length > 0) {
                File dir = dirs[0];
                return new File(dir, name);
            }
        }

        return null;
    }

    Uri shangchaunImg;
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == RESULT_OK) {
            switch (requestCode) {
                case CAMERA_REQUEST_CODE://拍照成功並且返回
                    Log.e("zmm", "選擇的圖片的虛擬地址是------------>" +takePath);
                    cropPhoto(takePath);
//                    cropPhoto(getMediaUriFromPath(this,takePath),false);
                    break;

                case IMAGE_REQUEST_CODE://選擇圖片成功返回
                    if (data != null && data.getData() != null) {
                        imageUri = data.getData();

                        cropPhoto(imageUri,true);
                    }
                    break;
                case CROP_REREQUEST_CODE:
                    Log.e("zmm", "裁剪以後的地址是------------>" + cropUri);
                    shangchaunImg  = cropUri;
                    decodeImage(cropUri);
                    break;
            }
        }
    }
    // 圖片裁剪
    private void cropPhoto(Uri uri, boolean fromCapture) {
        Intent intent = new Intent("com.android.camera.action.CROP"); //開啟系統自帶的裁剪圖片的intent
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("scale", true);

//        // 設定裁剪區域的寬高比例
//        intent.putExtra("aspectX", 1);
//        intent.putExtra("aspectY", 1);

        // 設定裁剪區域的寬度和高度
        intent.putExtra("outputX", 400);
        intent.putExtra("outputY", 400);

        // 取消人臉識別
        intent.putExtra("noFaceDetection", true);
        // 圖片輸出格式
        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());

        // 若為false則表示不返回資料
        intent.putExtra("return-data", false);

        // 指定裁剪完成以後的圖片所儲存的位置,pic info顯示有延時
        if (fromCapture) {
            // 如果是使用拍照,那麼原先的uri和最終目標的uri一致
            cropUri = uri;
        } else { // 從相簿中選擇,那麼裁剪的圖片儲存在take_photo中
            String time = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA).format(new Date());
            String fileName = "photo_" + time;
            File mCutFile = new File(Environment.getExternalStorageDirectory() + "/take_photo", fileName + ".jpeg");
            if (!mCutFile.getParentFile().exists()) {
                mCutFile.getParentFile().mkdirs();
            }
            cropUri = getUriForFile(this, mCutFile);
        }
        intent.putExtra(MediaStore.EXTRA_OUTPUT, cropUri);
        Toast.makeText(this, "剪裁圖片", Toast.LENGTH_SHORT).show();
        // 以廣播方式刷新系統相簿,以便能夠在相簿中找到剛剛所拍攝和裁剪的照片
        Intent intentBc = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        intentBc.setData(uri);
        this.sendBroadcast(intentBc);

        startActivityForResult(intent, CROP_REREQUEST_CODE); //設定裁剪引數顯示圖片至ImageVie
    }
    // 從file中獲取uri
    // 7.0及以上使用的uri是contentProvider content://com.rain.takephotodemo.FileProvider/images/photo_20180824173621.jpg
    // 6.0使用的uri為file:///storage/emulated/0/take_photo/photo_20180824171132.jpg
    private static Uri getUriForFile(Context context, File file) {
        if (context == null || file == null) {
            throw new NullPointerException();
        }
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(context.getApplicationContext(),  BuildConfig.APPLICATION_ID + ".provider", file);
        } else {
            uri = Uri.fromFile(file);
        }
        return uri;
    }
    /**
     * 根據uri拿到bitmap
     *
     * @param imageUri 這個Uri是
     */
    private void decodeImage(Uri imageUri) {
        try {
            Bitmap bitmapFormUri = getBitmapFormUri(this, imageUri);
            img_suolv.setImageBitmap(bitmapFormUri);
            beginupload(imageUri);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static Bitmap getBitmapFormUri(Activity ac, Uri uri) throws FileNotFoundException, IOException {
        InputStream input = ac.getContentResolver().openInputStream(uri);
        BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
        onlyBoundsOptions.inJustDecodeBounds = true;
        onlyBoundsOptions.inDither = true;//optional
        onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
        input.close();
        int originalWidth = onlyBoundsOptions.outWidth;
        int originalHeight = onlyBoundsOptions.outHeight;
        if ((originalWidth == -1) || (originalHeight == -1))
            return null;
        //圖片解析度以480x800為標準
        float hh = 800f;//這裡設定高度為800f
        float ww = 480f;//這裡設定寬度為480f
        //縮放比。由於是固定比例縮放,只用高或者寬其中一個數據進行計算即可
        int be = 1;//be=1表示不縮放
        if (originalWidth > originalHeight && originalWidth > ww) {//如果寬度大的話根據寬度固定大小縮放
            be = (int) (originalWidth / ww);
        } else if (originalWidth < originalHeight && originalHeight > hh) {//如果高度高的話根據寬度固定大小縮放
            be = (int) (originalHeight / hh);
        }
        if (be <= 0)
            be = 1;
        //比例壓縮
        BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
        bitmapOptions.inSampleSize = be;//設定縮放比例
        bitmapOptions.inDither = true;//optional
        bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
        input = ac.getContentResolver().openInputStream(uri);
        Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
        input.close();

        return compressImage(bitmap);//再進行質量壓縮
    }
    /**
     * 質量壓縮方法
     *
     * @param image
     * @return
     */
    public static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這裡100表示不壓縮,把壓縮後的資料存放到baos中
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100) {  //迴圈判斷如果壓縮後圖片是否大於100kb,大於繼續壓縮
            baos.reset();//重置baos即清空baos
            //第一個引數 :圖片格式 ,第二個引數: 圖片質量,100為最高,0為最差  ,第三個引數:儲存壓縮後的資料的流
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這裡壓縮options%,把壓縮後的資料存放到baos中
            options -= 10;//每次都減少10
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮後的資料baos存放到ByteArrayInputStream中
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream資料生成圖片
        return bitmap;
    }
    /**
     * 檢查許可權
     *
     * @param requestCode
     */
    private void checkPermission(int requestCode) {

        boolean granted = PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this,
                Manifest.permission_group.CAMERA);
        if (granted) {//有許可權
            if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) {
                openCamera();//開啟相機
            } else {
                openGallery();//開啟相簿
            }
            return;
        }
        //沒有許可權的要去申請許可權
        //注意:如果是在Fragment中申請許可權,不要使用ActivityCompat.requestPermissions,
        // 直接使用Fragment的requestPermissions方法,否則會回撥到Activity的onRequestPermissionsResult
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest
                        .permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE},
                requestCode);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (grantResults.length > 0) {
            boolean flag = true;
            for (int i = 0; i < grantResults.length; i++) {
                if (grantResults[i] != PERMISSION_GRANTED) {
                    flag = false;
                    break;
                }
            }
            //許可權通過以後。自動回撥拍照
            if (flag) {
                if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) {
                    openCamera();//開啟相機
                } else {
                    openGallery();//開啟相簿
                }
            } else {
                Toast.makeText(this, "請開啟許可權", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * 檢查SD卡是否存在
     */
    public boolean isSdCardExist() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

6.使用拍照或者開啟相簿

onClickTakePhoto(view); //拍照
onClickOpenGallery(view);//相簿

7.記得要加入使用的許可權

<!-- 往SDCard寫入資料許可權 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 請求訪問使用照相裝置 -->
<uses-permission android:name="android.permission.INTERNET" /> <!-- 網路許可權 -->
<uses-permission android:name="android.permission.VIBRATE" /> <!-- 震動許可權 -->
<uses-permission android:name="android.permission.CAMERA" /> <!-- 攝像頭許可權 -->
<uses-feature android:name="android.hardware.camera.autofocus" /> <!-- 自動聚焦許可權 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <!-- 讀取sd卡 -->     
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<!-- 寫入撥打電話許可權 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />