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 信息丟失或不準確。File(selectedImage.toString()) 直接將 Uri 轉為文件路徑不正確,Uri 可能為 content:// 協議,需通過 ContentResolver 打開輸入流讀取。利用 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; // 預設無旋轉
}
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);
}
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);
rotateBitmapIfNeeded,確保伺服器收到正向圖片。
exifinterface 庫支持更多格式且 API 統一。
implementation "androidx.exifinterface:exifinterface:1.3.6"
ExifInterface exif = new ExifInterface(inputStream); // 支持 InputStream
inSampleSize 縮放解碼,或採用 BitmapRegionDecoder 逐塊處理。
| 方法 | 可靠性 | 適用場景 |
|---|---|---|
| ExifInterface 讀取文件路徑 | 低 | 文件路徑正確且 EXIF 完整 |
| MediaStore 查詢 ORIENTATION | 高 | 系統相機拍照,需 ContentResolver 權限 |
| FileProvider + ExifInterface(InputStream) | 最高 | 現代 Android (API 24+),最佳實踐 |
總結:圖片上傳旋轉 90 度問題源於 EXIF 方向信息讀取不準。通過 MediaStore 查詢系統記錄的方向值,結合 Matrix 旋轉 Bitmap 修正,並採用 FileProvider 獲取原始文件,可全面解決各機型兼容性問題。