为什么在某些安卓设备上使用相机意图拍摄的图片会被旋转?

467

我正在捕获一张图片并将其设置为图像视图。

public void captureImage() {

    Intent intentCamera = new Intent("android.media.action.IMAGE_CAPTURE");
    File filePhoto = new File(Environment.getExternalStorageDirectory(), "Pic.jpg");
    imageUri = Uri.fromFile(filePhoto);
    MyApplicationGlobal.imageUri = imageUri.getPath();
    intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
    startActivityForResult(intentCamera, TAKE_PICTURE);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intentFromCamera) {
    super.onActivityResult(requestCode, resultCode, intentFromCamera);

    if (resultCode == RESULT_OK && requestCode == TAKE_PICTURE) {

        if (intentFromCamera != null) {
            Bundle extras = intentFromCamera.getExtras();
            if (extras.containsKey("data")) {
                bitmap = (Bitmap) extras.get("data");
            }
            else {
                bitmap = getBitmapFromUri();
            }
        }
        else {
            bitmap = getBitmapFromUri();
        }
        // imageView.setImageBitmap(bitmap);
        imageView.setImageURI(imageUri);
    }
    else {
    }
}

public Bitmap getBitmapFromUri() {

    getContentResolver().notifyChange(imageUri, null);
    ContentResolver cr = getContentResolver();
    Bitmap bitmap;

    try {
        bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri);
        return bitmap;
    }
    catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

但问题在于,有些设备每次旋转后图像会发生变化。例如,在三星设备上它效果良好,但在Sony Xperia上,图像会旋转90度,在Toshiba Thrive(平板电脑)上会旋转180度。


1
尝试在您的活动清单中添加以下内容: android:configChanges="orientation" android:screenOrientation="portrait" - Narendra Pal
1
我认为当您使用内部意图处理相机应用程序时,它会旋转图像。这取决于您如何持有设备来捕获图像。因此,您可以限制用户以特定方式拍摄图像,即用户始终通过纵向或横向持有设备来捕获图像。之后,您可以将其更改为特定角度以获取所需的图像。或者,另一种选择是制作自己的相机应用程序。 - Narendra Pal
3
我相信捕获意图会始终调用默认的相机应用程序,该应用程序在每个设备上都有特定的方向,并因此具有固定的照片方向。这不取决于用户拿设备的方式或调用该意图的活动的方向。 - Alex Cohn
1
为了避免存储权限问题,请参考回答,或使用Glide - Pavel
1
有人发现了ORIENTATION_UNDEFINED的解决方案吗?因为在一些设备上(例如Android 8模拟器),图像会旋转,而在另一些设备上(例如Android 9模拟器)它不会旋转,尽管Orientation值相同。如何知道图像是否需要旋转? - Harshit Saxena
显示剩余4条评论
23个回答

0

这是 Xamarin.Android 的版本:

来自 @Jason Robinson 的 answer

Bitmap rotate(Bitmap bitmap, int angle)
{
    var matrix = new Matrix();
    matrix.PostRotate(angle);

    return Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
}

Bitmap rotateIfRequired(Bitmap bitmap, string imagePath)
{
    var ei = new ExifInterface(imagePath);
    var orientation = ei.GetAttributeInt(ExifInterface.TagOrientation, (int)Android.Media.Orientation.Undefined);

    switch (orientation)
    {
        case (int)Android.Media.Orientation.Rotate90: return rotate(bitmap, 90);
        case (int)Android.Media.Orientation.Rotate180: return rotate(bitmap, 180);
        case (int)Android.Media.Orientation.Rotate270: return rotate(bitmap, 270);
        default: return bitmap;
    }
}

接下来是calculateInSampleSize方法:

int calculateInSampleSize(BitmapFactory.Options options, int reqW, int reqH)
{
    float h = options.OutHeight;
    float w = options.OutWidth;
    var inSampleSize = 1;

    if (h > reqH || w > reqW)
    {
        if (reqH == 0) inSampleSize = (int)Math.Floor(w / reqW);
        else if (reqW == 0) inSampleSize = (int)Math.Floor(h / reqH);
        else
        {
            var hRatio = (int)Math.Floor(h / reqH);
            var wRatio = (int)Math.Floor(w / reqW);
            inSampleSize = false ? Math.Max(hRatio, wRatio) : Math.Min(hRatio, wRatio);
        }
    }

    return inSampleSize;
}

来自 @Sami Eltamawy 的 回答

Bitmap handleSamplingAndRotationBitmap(string imagePath)
{
    var maxHeight = 1024;
    var maxWidth = 1024;

    var options = new BitmapFactory.Options();
    options.InJustDecodeBounds = true;
    BitmapFactory.DecodeFile(imagePath, options);

    options.InSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);

    options.InJustDecodeBounds = false;

    var bitmap = BitmapFactory.DecodeFile(imagePath, options);

    bitmap = rotateIfRequired(bitmap, imagePath);

    return bitmap;
}

嗨,我的Xamarin Android应用程序出现了旋转问题。问题在于使用后置摄像头时,图像会被保存为向右90度。但是使用前置摄像头时,它会保存为向左90度。 因此,使用此代码解决旋转仅适用于前置摄像头。你遇到过这个问题吗? - Anand
你好,我认为这是因为前置摄像头默认翻转了。如果你关闭它,那么这段代码对于两个摄像头的结果就相等了吗? - Mehdi Dehghani
你好,你能帮我解决这个问题吗?我在这里提出了一个问题,但是仍然一无所知。https://stackoverflow.com/questions/64278491/camera-capture-image-rotate-to-portrait-xamarin-android/64294447?noredirect=1#comment113703379_64294447 - Anand

0
如果您正在使用Fresco,您可以使用以下内容 -
final ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
.setRotationOptions(RotationOptions.autoRotate())
.build();

mSimpleDraweeView.setController(
Fresco.newDraweeControllerBuilder()
    .setImageRequest(imageRequest)
    .build());

这将根据Exif数据自动旋转图像。

来源:https://frescolib.org/docs/rotation.html


0

针对这个问题,我们可以不使用ExifInterface来得到答案。我们可以获取相机的旋转角度,无论是前置摄像头还是后置摄像头,然后在创建位图时使用Matrix.postRotate(degree)来旋转位图。

public int getRotationDegree() {
    int degree = 0;

    for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            degree = info.orientation;

            return degree;
        }
    }

    return degree;
}

在计算旋转角度后,您可以像下面这样旋转位图:

 Matrix matrix = new Matrix();

 matrix.postRotate(getRotationDegree());

 Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);

这里的 bm 应该是您的位图。

如果您想知道前置摄像头的旋转情况,请将上面的 Camera.CameraInfo.CAMERA_FACING_BACK 更改为 Camera.CameraInfo.CAMERA_FACING_FRONT

希望这能帮到您。


2
回答很糟糕,但我不小心点了赞。这段代码假设你的相册中的每张图片都是用“你自己”的相机拍摄的。但事实并非如此。 - Zun
@Zun 所提出的问题是关于图像捕获而非从相册中选择图像。 - Om Prakash Agrahari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接