Android Firebase头像上传旋转问题:ExifInterface实现求助
Hey there! That image rotation bug is such a classic—phones store photo orientation data in Exif tags, and neither raw Bitmap loading nor Firebase Storage automatically applies that rotation for you. Let's fix this by integrating Exif orientation handling into your existing workflow step by step.
First: Understand the Root Cause
When you take a photo with most phones, the actual pixel data stays in landscape mode, but the phone saves an Exif Orientation tag to tell viewers how to rotate it. Your current code loads the Bitmap without reading this tag, so it shows up rotated—and since you're uploading that uncorrected Bitmap to Firebase, the stored image stays rotated too.
Step 1: Build a Helper Function to Correct Bitmap Orientation
Create a reusable function that takes a file path (or InputStream) and a Bitmap, then adjusts it based on the Exif orientation data:
import android.graphics.Bitmap import android.graphics.Matrix import android.media.ExifInterface fun correctBitmapOrientation(filePath: String, bitmap: Bitmap): Bitmap { val exif = ExifInterface(filePath) val orientation = exif.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL ) val matrix = Matrix() when (orientation) { ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f) ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f) ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f) ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.postScale(-1f, 1f) ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.postScale(1f, -1f) // Add other edge-case orientations if needed } return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) }
If you're working with an InputStream instead of a file path, use ExifInterface(inputStream) (available in API 24+; for older versions, save the stream to a temporary file first to read Exif data).
Step 2: Integrate with Your Firebase Upload Workflow
Modify your existing code to correct the Bitmap before uploading it to Firebase Storage. Here's a full, practical example:
Example: Pick Image → Correct Orientation → Upload to Firebase
import android.content.Intent import android.graphics.BitmapFactory import android.net.Uri import android.os.Bundle import android.provider.MediaStore import androidx.appcompat.app.AppCompatActivity import com.google.firebase.storage.FirebaseStorage import com.google.firebase.storage.StorageReference import java.io.ByteArrayOutputStream import java.io.File class AvatarUploadActivity : AppCompatActivity() { private lateinit var storageRef: StorageReference private val currentUserUid = "your-user-uid-here" // Replace with actual user ID override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_avatar_upload) // Initialize Firebase Storage reference for the user's avatar storageRef = FirebaseStorage.getInstance().reference.child("avatars/$currentUserUid") } // Trigger system image picker fun pickAvatar() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, PICK_AVATAR_REQUEST) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_AVATAR_REQUEST && resultCode == RESULT_OK && data != null) { val imageUri: Uri = data.data ?: return // Get real file path from Uri (adjust for API 29+ if needed) val filePath = getRealPathFromUri(imageUri) ?: return // Load original Bitmap from file val originalBitmap = BitmapFactory.decodeFile(filePath) // Fix orientation using our helper function val correctedBitmap = correctBitmapOrientation(filePath, originalBitmap) // Update in-app preview with the corrected image avatarPreviewImageView.setImageBitmap(correctedBitmap) // Upload the fixed Bitmap to Firebase uploadCorrectedAvatar(correctedBitmap) } } private fun uploadCorrectedAvatar(bitmap: Bitmap) { val baos = ByteArrayOutputStream() // Compress Bitmap to JPEG (adjust quality as needed) bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos) val imageData = baos.toByteArray() val uploadTask = storageRef.putBytes(imageData) uploadTask.addOnSuccessListener { taskSnapshot -> // Get download URL and save to Firebase Database if needed storageRef.downloadUrl.addOnSuccessListener { uri -> val avatarUrl = uri.toString() // Save this URL to your user's record in Firebase Database } }.addOnFailureListener { exception -> // Handle upload failure (show error toast, log, etc.) } } // Helper to get real file path from Uri (adjust for your target SDK) private fun getRealPathFromUri(uri: Uri): String? { return try { val projection = arrayOf(MediaStore.Images.Media.DATA) val cursor = contentResolver.query(uri, projection, null, null, null) val columnIndex = cursor?.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) cursor?.moveToFirst() val path = columnIndex?.let { cursor.getString(it) } cursor?.close() path } catch (e: Exception) { null } } companion object { private const val PICK_AVATAR_REQUEST = 1001 } }
Key Tips to Avoid Headaches
- Memory Management: High-res photos can cause OutOfMemoryErrors—use
BitmapFactory.Optionsto downsample the image before correcting orientation. - API Compatibility: For devices below API 24, save the image InputStream to a temporary file first to read Exif data.
- Test All Cases: Make sure to test photos taken in portrait, landscape, flipped, and 180° rotated modes to cover all Exif orientation scenarios.
Why This Works
By reading the Exif orientation tag and adjusting the Bitmap before upload, you're modifying the actual pixel data to match the intended orientation. This ensures both your in-app preview and the image stored in Firebase display correctly, no more rotated avatars!
内容的提问来源于stack exchange,提问作者ImTheNun

