You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Canvas异常问题:Bitmap在真机上自行旋转90度

Fix: Bitmap Rotates 90 Degrees on Real Devices (Works on Emulator)

Hey there! That’s a super common Android gotcha—real devices often respect EXIF orientation metadata that emulators ignore, leading to unexpected rotation when working with Bitmaps and Canvas. Let’s break down why this happens and how to fix it:

Why This Occurs

When you get a Bitmap (e.g., from a camera, gallery, or another screen), it might have an EXIF tag specifying its intended orientation (like 90 degrees clockwise). Emulators sometimes skip processing this tag, so your code works as expected there. But real devices apply this orientation, making it look like the Bitmap rotated on its own when you use it with Canvas.

Your current code copies and scales the Bitmap but doesn’t adjust the pixel data to match the EXIF orientation—so the underlying pixel data stays in the original (rotated) state, and the device’s system applies the EXIF rotation on top, causing the mismatch.

Step 1: Read the EXIF Orientation

First, grab the orientation value from the original image’s EXIF data. If you have the file path of the source image, use this helper method:

int getExifOrientation(String imagePath) {
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(imagePath);
    } catch (IOException e) {
        e.printStackTrace();
    }
    if (exif == null) return ExifInterface.ORIENTATION_NORMAL;
    
    return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}

If you don’t have the file path, make sure the previous page passes both the Bitmap and its orientation (since Bitmaps don’t store EXIF data directly).

Step 2: Rotate the Bitmap to Match the Orientation

Use this helper method to adjust the Bitmap’s pixel data to match the EXIF orientation:

Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
    Matrix matrix = new Matrix();
    switch (orientation) {
        case ExifInterface.ORIENTATION_NORMAL:
            return bitmap;
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
            matrix.setScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.setRotate(180);
            break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            matrix.setRotate(180);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
            matrix.setRotate(90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.setRotate(90);
            break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
            matrix.setRotate(-90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.setRotate(-90);
            break;
        default:
            return bitmap;
    }
    try {
        Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap.recycle(); // Free up memory from the original bitmap
        return rotatedBitmap;
    } catch (OutOfMemoryError e) {
        e.printStackTrace();
        return bitmap;
    }
}

Step 3: Update Your Canvas Logic

Modify your code to apply the rotation before creating the Canvas:

// Get orientation from the original image (adjust this to your source)
int orientation = getExifOrientation(originalImagePath);

// Copy and scale the bitmap as before
mBitmap = backgroundPicture.copy(Bitmap.Config.ARGB_8888, true);
mBitmap = Bitmap.createScaledBitmap(mBitmap, width, height, true);

// Rotate to correct orientation
mBitmap = rotateBitmap(mBitmap, orientation);

// Now create your Canvas with the properly oriented bitmap
mCanvas = new Canvas(mBitmap);

Alternative: Adjust the Canvas Matrix (Memory-Friendly)

If you want to avoid creating a new Bitmap, adjust the Canvas’s matrix to compensate for the orientation. This way, all your drawing operations will automatically align correctly:

// Get orientation
int orientation = getExifOrientation(originalImagePath);

// Create Canvas with the original scaled bitmap
mCanvas = new Canvas(mBitmap);

// Apply rotation to the Canvas
Matrix canvasMatrix = new Matrix();
switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        canvasMatrix.postRotate(90, mBitmap.getWidth()/2, mBitmap.getHeight()/2);
        break;
    case ExifInterface.ORIENTATION_ROTATE_270:
        canvasMatrix.postRotate(-90, mBitmap.getWidth()/2, mBitmap.getHeight()/2);
        break;
    // Add other orientation cases if needed
}
mCanvas.setMatrix(canvasMatrix);

Why Emulators Work

Emulators often skip processing EXIF orientation metadata, so they display the Bitmap’s raw pixel data directly. Real devices, however, respect these tags, leading to the rotation mismatch you’re seeing.


内容的提问来源于stack exchange,提问作者Matthieu Meunier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:42:53