android7.0以上呼叫系統相機拍照並顯示到ImageView上

野生野鸡码农發表於2024-07-07

/*
*  第一步:新建檔案 res/xml/file_paths.xml
   <paths xmlns:android="http://schemas.android.com/apk/res/android">
      <external-path path="." name="camera_photos" />
   </paths>
*  第二步:AndroidManifest.xml檔案的application標籤中插入下邊
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.lrogzin.memo.fileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
*  第三步:在你需要的地方呼叫startCamera()
*  第四步:在你的onActivityResult()中加入:
*
* */
public class UseSysCameraUtil {

    public static final int CAMERA_CODE = 110;
    public static Uri takePictureUri;//拍照圖片uri
    private static Uri cropPictureTempUri;//裁剪圖片uri
    private static File takePictureFile;//拍照圖片File

    public static void startCamera(Activity activity, String displayName) {
        takePictureUri = createImagePathUri(activity, displayName);
        if (takePictureUri != null) {
            Intent i = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            i.putExtra(MediaStore.EXTRA_OUTPUT, takePictureUri);//輸出路徑(拍照後的儲存路徑)
            activity.startActivityForResult(i, CAMERA_CODE);
        } else {
            Toast.makeText(activity, "開啟相機失敗", Toast.LENGTH_LONG).show();
        }
    }

    public static Uri createImagePathUri(Activity activity, String displayName) {
        //適配 Android=Q Android=7 API=29
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //圖片名稱
            //String displayName = String.valueOf(System.currentTimeMillis());
            //String displayName = "head";
            ContentValues values = new ContentValues(2);
            values.put(MediaStore.Images.Media.DISPLAY_NAME, displayName);
            values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
            //SD 卡是否可用,可用則用 SD 卡,否則用內部儲存
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                takePictureUri = activity.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                takePictureUri = activity.getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
            }
        } else {
            String pathName = new StringBuffer().append(FileUtils.getExtPicturesPath()).append(File.separator)
                    .append(System.currentTimeMillis()).append(".jpg").toString();
            takePictureFile = new File(pathName);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { //解決Android 7.0 拍照出現FileUriExposedException的問題
                String authority = activity.getPackageName() + ".fileProvider";
                takePictureUri = FileProvider.getUriForFile(activity, authority, takePictureFile);
            } else {
                takePictureUri = Uri.fromFile(takePictureFile);
            }
        }
        return takePictureUri;
    }

    public static void onCameraRes(int requestCode, int resultCode, Activity activity) {
        try {
            if (requestCode == CAMERA_CODE && resultCode == activity.RESULT_OK) {
                Bitmap headBitmap = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(takePictureUri));
                //mainAvatar.setImageBitmap(headBitmap);

            }
        } catch (Exception e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        }
    }

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

    static int CROP_CODE = 3;

    //呼叫系統的裁剪功能的實現
   /*
   *   onActivityResult()
   *   case CROP_CODE:
                //裁剪返回的
                if (data != null) {
                    Bundle extras = data.getExtras();
                    headBitmap = extras.getParcelable("data");
                    if (headBitmap != null) {
                        mainAvatar.setImageBitmap(headBitmap);// 用ImageView顯示出來
                        dialogAvatar.setImageBitmap(headBitmap);
                    }
                }
   */
    public static void cropPhoto(Uri uri, Activity activity) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.setDataAndType(uri, "image/*");
        intent.putExtra("crop", "true");
        // aspectX aspectY 是寬高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪圖片寬高
        intent.putExtra("outputX", 150);
        intent.putExtra("outputY", 150);
        intent.putExtra("return-data", true);
        activity.startActivityForResult(intent, CROP_CODE);
    }

    int PERMISSIONS_REQUEST_CAMERA = 1111;

    // 請求相機許可權
    private void requestCameraPermission(Activity activity) {
        if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, PERMISSIONS_REQUEST_CAMERA);
        } else {
            //goCamera();
            //jumpToTakePhoto();
            //startCamera();
        }
    }

   /*@Override
   public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
      if (requestCode == PERMISSIONS_REQUEST_CAMERA) {
         if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // 許可權被授予,執行拍照操作
            //goCamera();
            //jumpToTakePhoto();
            startCamera();
         } else {
            // 許可權被拒絕
            Toast.makeText(activity, "Camera permission is required to take a photo.", Toast.LENGTH_SHORT).show();
         }
      }
   }*/

    /**
     * 獲取圖片路徑
     *
     * @param context Context
     * @param uri     圖片 Uri
     * @return 圖片路徑
     */
    public static String getImagePath(Context context, Uri uri) {
        Cursor cursor = null;
        try {
            String[] proj = {MediaStore.Images.Media.DATA};
            cursor = context.getContentResolver().query(uri, proj, null, null, null);
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            String s = cursor.getString(column_index);
            return s;
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    /**
     * 獲取圖片 Uri
     *
     * @param context Context
     * @param path    圖片路徑
     * @return 圖片 Uri
     */
    public static Uri getImageUri(Context context, String path) {
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media._ID},
                MediaStore.Images.Media.DATA + "=? ", new String[]{path}, null);
        if (cursor != null && cursor.moveToFirst()) {
            int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
        } else {
            if (new File(path).exists()) {
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, path);
                return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            } else {
                return null;
            }
        }
    }

}

public final class FileUtils {

   /**
    * 得到SD卡根目錄,SD卡不可用則獲取內部儲存的根目錄
    */
   public static File getRootPath() {
      File path = null;
      if (sdCardIsAvailable()) {
         path = Environment.getExternalStorageDirectory(); //SD卡根目錄    /storage/emulated/0
      } else {
         path = Environment.getDataDirectory();//內部儲存的根目錄    /data
      }
      return path;
   }

   /**
    * 獲取圖片目錄
    *
    * @return 圖片目錄(/storage/emulated/0/Pictures)
    */
   public static File getExtPicturesPath() {
      File extPicturesPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
      if (!extPicturesPath.exists()) {
         extPicturesPath.mkdir();
      }
      return extPicturesPath;
   }

   /**
    * 獲取快取圖片的目錄
    *
    * @param context Context
    * @return 快取圖片的目錄
    */
   public static String getImageCacheDir(Context context) {
      String cachePath;
      if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
         cachePath = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath();
      } else {
         cachePath = context.getCacheDir().getPath();
      }
      return cachePath;
   }

   /**
    * 刪除快取圖片目錄中的全部圖片
    *
    * @param context
    */
   public static void deleteAllCacheImage(Context context) {
      String cacheImagePath = getImageCacheDir(context);
      File cacheImageDir = new File(cacheImagePath);
      File[] files = cacheImageDir.listFiles();
      if (files != null) {
         for (File file : files) {
            if (file.isFile()) {
               file.delete();
            }
         }
      }
   }

   /**
    * SD卡是否可用
    */
   public static boolean sdCardIsAvailable() {
      if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
         File sd = new File(Environment.getExternalStorageDirectory().getPath());
         return sd.canWrite();
      } else
         return false;
   }

   /**
    * 判斷目錄是否存在,不存在則判斷是否建立成功
    *
    * @param dirPath 檔案路徑
    * @return {@code true}: 存在或建立成功<br>{@code false}: 不存在或建立失敗
    */
   public static boolean createOrExistsDir(String dirPath) {
      return createOrExistsDir(getFileByPath(dirPath));
   }

   /**
    * 判斷目錄是否存在,不存在則判斷是否建立成功
    *
    * @param file 檔案
    * @return {@code true}: 存在或建立成功<br>{@code false}: 不存在或建立失敗
    */
   public static boolean createOrExistsDir(File file) {
      // 如果存在,是目錄則返回true,是檔案則返回false,不存在則返回是否建立成功
      return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
   }

   /**
    * 根據檔案路徑獲取檔案
    *
    * @param filePath 檔案路徑
    * @return 檔案
    */
   public static File getFileByPath(String filePath) {
      return isSpace(filePath) ? null : new File(filePath);
   }

   /**
    * 判斷字串是否為 null 或全為空白字元
    *
    * @param s
    * @return
    */
   private static boolean isSpace(final String s) {
      if (s == null)
         return true;
      for (int i = 0, len = s.length(); i < len; ++i) {
         if (!Character.isWhitespace(s.charAt(i))) {
            return false;
         }
      }
      return true;
   }

}

相關文章