Android 拍照或相簿剪裁後取頭像
引用
1、 ofollow,noindex">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應用設定中開啟此許可權"); }