6.0以後授權手機攝像頭許可權拍照、選擇相簿照、裁剪
阿新 • • 發佈:2018-12-21
效果圖
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" />