首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android 相機拍照圖片上傳旋轉 90 度的 EXIF 方向修正方案

     編輯:程式設計綜合問答

問題現象

Android 應用調用相機拍照後上傳圖片,部分設備上傳到伺服器的圖片會逆時針旋轉 90 度。嘗試使用 ExifInterface 讀取圖片方向屬性進行修正,但在所有設備(包括有問題的設備)上讀取到的 orientation 值均為 0(即 ORIENTATION_NORMAL),無法正確識別實際旋轉角度。

原始嘗試代碼

Uri selectedImage = data.getData();
File imageFile = new File(selectedImage.toString());
ExifInterface exif;
try {
    exif = new ExifInterface(imageFile.getAbsolutePath());
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90: rotate = 90; break;
        case ExifInterface.ORIENTATION_ROTATE_180: rotate = 180; break;
    }
} catch (IOException e) { e.printStackTrace(); }

根因分析

  • data.getData() 返回的 Uri 可能指向縮略圖或臨時文件,而非原始圖片文件,導致 EXIF 信息丟失或不準確。
  • 部分設備相機應用不寫入標準 EXIF 方向標籤,或寫入非標準格式。
  • File(selectedImage.toString()) 直接將 Uri 轉為文件路徑不正確,Uri 可能為 content:// 協議,需通過 ContentResolver 打開輸入流讀取。

解決方案:通過 MediaStore 查詢真實圖片方向

利用 MediaStore.Images.ImageColumns.ORIENTATION 從系統媒體數據庫獲取最新圖片的方向信息,該值由相機應用寫入,更可靠。

完整修正代碼

private int getImageOrientation(Context context, Uri imageUri) {
    // 僅查詢方向欄位,按 ID 降序取最新一條
    String[] projection = {MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION};
    String sortOrder = MediaStore.Images.Media._ID + " DESC";
    
    try (Cursor cursor = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            projection, null, null, sortOrder)) {
        
        if (cursor != null && cursor.moveToFirst()) {
            int orientationColumn = cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION);
            int orientation = cursor.getInt(orientationColumn);
            Log.d("ImageOrientation", "Detected orientation: " + orientation);
            return orientation;
        }
    } catch (Exception e) {
        Log.e("ImageOrientation", "Failed to query orientation", e);
    }
    return 0; // 預設無旋轉
}

結合 Bitmap 旋轉修正

public Bitmap rotateBitmapIfNeeded(Context context, Uri uri, Bitmap bitmap) {
    int orientation = getImageOrientation(context, uri);
    if (orientation == 0) return bitmap;
    
    Matrix matrix = new Matrix();
    switch (orientation) {
        case 90: matrix.postRotate(90); break;
        case 180: matrix.postRotate(180); break;
        case 270: matrix.postRotate(270); break;
        default: return bitmap;
    }
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

進階最佳實踐

  1. 使用 FileProvider 獲取原始文件 Uri:避免 data.getData() 返回縮略圖 Uri。
    // 拍照意圖
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    File photoFile = createImageFile(); // 創建臨時文件
    Uri photoUri = FileProvider.getUriForFile(context, "com.example.fileprovider", photoFile);
    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    
  2. 上傳前統一修正方向:在壓縮/上傳流程中調用 rotateBitmapIfNeeded,確保伺服器收到正向圖片。
  3. 考慮使用 ExifInterface 兼容庫:AndroidX exifinterface 庫支持更多格式且 API 統一。
    implementation "androidx.exifinterface:exifinterface:1.3.6"
    ExifInterface exif = new ExifInterface(inputStream); // 支持 InputStream
    
  4. 處理大圖 OOM 風險:使用 inSampleSize 縮放解碼,或採用 BitmapRegionDecoder 逐塊處理。

關鍵點總結

方法可靠性適用場景
ExifInterface 讀取文件路徑低文件路徑正確且 EXIF 完整
MediaStore 查詢 ORIENTATION高系統相機拍照,需 ContentResolver 權限
FileProvider + ExifInterface(InputStream)最高現代 Android (API 24+),最佳實踐

總結:圖片上傳旋轉 90 度問題源於 EXIF 方向信息讀取不準。通過 MediaStore 查詢系統記錄的方向值,結合 Matrix 旋轉 Bitmap 修正,並採用 FileProvider 獲取原始文件,可全面解決各機型兼容性問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved