Android進階之路 - 解決部分手機拍照之後圖片被旋轉的問題

這幾天犯了一個錯誤,初期想着甩鍋給後臺的,但是還好及時發現了是自身的問題~

產生問題:通過拍照或相冊回傳的照片,直接傳入後臺,在用於展示的時候,照片角度出現問題,均不規則的旋轉了90度,從而導致體驗效果變差!

問題思考:後臺一般都是你怎麼存的,它怎麼給你拿出來!所以在這裏就可以發現問題本身是由我們前端造成的!

覆蓋範圍:圖片被旋轉的情況並不是百分百出現在每個機型上,只是會出現在某一部分機型之上,但是本着兼容的原則,我們只有逐個處理

解決方法:找了大約五篇博文左右,我找到了最懶也是最簡單有效的方法,主要來自此篇文章,之所以沒有轉載而且署名原創的原因是因爲更全面記錄自己遇到的問題、場景、思路~

關聯文章:Android進階之路 - 拍照與相冊選圖(解決6.0,7.0的權限問題與文件保護問題)


主要代碼部分,已全局進行了註釋~
我想不會有比我還笨的人,加油把~

  • 拍照
    /**
     * 拍照
     */
    private void takePhoto() {
        //拍照時存儲的照片路徑,最好提爲全局變量,因爲成功回傳後需要使用到~
     String photoPath = Environment.getExternalStorageDirectory().getPath() + "/picture_dow_" + SystemClock.currentThreadTimeMillis() + ".jpg";
        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, FileProvider.getUriForFile(InfoActivity.this, "com.bakheet.garage.fileprovider", sdcardTempFile));
        } else {
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(sdcardTempFile));
        }
        startActivityForResult(intent, 1);
    }
  • 相冊選取
   /**
     * 從相冊選取照片
     */
    private void selectFromGallery() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_PICK);
        intent.setType("image/*");
        startActivityForResult(intent, 2);
    }
  • 重寫onActivityResult(此時照片已經回傳,我們在這裏進行圖片處理)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
          //拍照回傳
            case 1:
                if (resultCode == RESULT_OK && sdcardTempFile.exists()) {
                    //主要通過PhotoBitmapUtils內的amendRotatePhoto方法保存我們拍照時的照片狀態
                    String newPath = PhotoBitmapUtils.amendRotatePhoto(photoPath, this);
                    //此時的圖片file就是正確的了~
                    final File newSdcardTempFile = new File(newPath);
                    //這個方法是用於傳入後臺的,可忽略!!!
                    uploadImage(newSdcardTempFile);
                }
                break;
            //相冊回傳
            case 2:
                ContentResolver contentResolver = getContentResolver();
                if (data != null) {
                    //圖片的U
                    Uri uri = data.getData();
                    if (uri!=null){
                        //使用工具類獲取絕對路徑
                        String path = ToolUtil.getFilePathFromContentUri(uri, contentResolver);
                        if (resultCode == RESULT_OK && sdcardTempFile.exists()) {
                            //主要通過PhotoBitmapUtils內的amendRotatePhoto方法保存我們的照片狀態
                            String newPath = PhotoBitmapUtils.amendRotatePhoto(photoPath, this);
                             //此時的圖片file就是正確的了~
                            final File newSdcardTempFile = new File(newPath);
                             //這個方法是用於傳入後臺的,可忽略!!!
                            uploadImage(newSdcardTempFile);
                        }
                    }
                }
                break;
            default:
                break;
        }
    }
  • PhotoBitmapUtils(主要工具類):
/**
 * 集合一些圖片工具
 *
 * Created by zhuwentao on 2016-07-22.
 */
public class PhotoBitmapUtils {

    /**
     * 存放拍攝圖片的文件夾
     */
    private static final String FILES_NAME = "/MyPhoto";
    /**
     * 獲取的時間格式
     */
    public static final String TIME_STYLE = "yyyyMMddHHmmss";
    /**
     * 圖片種類
     */
    public static final String IMAGE_TYPE = ".png";

    // 防止實例化
    private PhotoBitmapUtils() {
    }

    /**
     * 獲取手機可存儲路徑
     *
     * @param context 上下文
     * @return 手機可存儲路徑
     */
    private static String getPhoneRootPath(Context context) {
        // 是否有SD卡
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
                || !Environment.isExternalStorageRemovable()) {
            // 獲取SD卡根目錄
            return context.getExternalCacheDir().getPath();
        } else {
            // 獲取apk包下的緩存路徑
            return context.getCacheDir().getPath();
        }
    }

    /**
     * 使用當前系統時間作爲上傳圖片的名稱
     *
     * @return 存儲的根路徑+圖片名稱
     */
    public static String getPhotoFileName(Context context) {
        File file = new File(getPhoneRootPath(context) + FILES_NAME);
        // 判斷文件是否已經存在,不存在則創建
        if (!file.exists()) {
            file.mkdirs();
        }
        // 設置圖片文件名稱
        SimpleDateFormat format = new SimpleDateFormat(TIME_STYLE, Locale.getDefault());
        Date date = new Date(System.currentTimeMillis());
        String time = format.format(date);
        String photoName = "/" + time + IMAGE_TYPE;
        return file + photoName;
    }

    /**
     * 保存Bitmap圖片在SD卡中
     * 如果沒有SD卡則存在手機中
     *
     * @param mbitmap 需要保存的Bitmap圖片
     * @return 保存成功時返回圖片的路徑,失敗時返回null
     */
    public static String savePhotoToSD(Bitmap mbitmap, Context context) {
        FileOutputStream outStream = null;
        String fileName = getPhotoFileName(context);
        try {
            outStream = new FileOutputStream(fileName);
            // 把數據寫入文件,100表示不壓縮
            mbitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
            return fileName;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (outStream != null) {
                    // 記得要關閉流!
                    outStream.close();
                }
                if (mbitmap != null) {
                    mbitmap.recycle();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 把原圖按1/10的比例壓縮
     *
     * @param path 原圖的路徑
     * @return 壓縮後的圖片
     */
    public static Bitmap getCompressPhoto(String path) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = false;
        options.inSampleSize = 10;  // 圖片的大小設置爲原來的十分之一
        Bitmap bmp = BitmapFactory.decodeFile(path, options);
        options = null;
        return bmp;
    }

    /**
     * 處理旋轉後的圖片
     * @param originpath 原圖路徑
     * @param context 上下文
     * @return 返回修復完畢後的圖片路徑
     */
    public static String amendRotatePhoto(String originpath, Context context) {

        // 取得圖片旋轉角度
        int angle = readPictureDegree(originpath);

        // 把原圖壓縮後得到Bitmap對象
        Bitmap bmp = getCompressPhoto(originpath);;

        // 修復圖片被旋轉的角度
        Bitmap bitmap = rotaingImageView(angle, bmp);

        // 保存修復後的圖片並返回保存後的圖片路徑
        return savePhotoToSD(bitmap, context);
    }

    /**
     * 讀取照片旋轉角度
     *
     * @param path 照片路徑
     * @return 角度
     */
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 旋轉圖片
     * @param angle 被旋轉角度
     * @param bitmap 圖片對象
     * @return 旋轉後的圖片
     */
    public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
        Bitmap returnBm = null;
        // 根據旋轉角度,生成旋轉矩陣
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        try {
            // 將原始圖片按照旋轉矩陣進行旋轉,並得到新的圖片
            returnBm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
        }
        if (returnBm == null) {
            returnBm = bitmap;
        }
        if (bitmap != returnBm) {
            bitmap.recycle();
        }
        return returnBm;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章