简体   繁体   English

某些设备(不是EXIF)捕获Android相机无法解释的旋转

[英]Android camera unexplainable rotation on capture for some devices (not in EXIF)

What I'm doing seems like it should be simple, but I'm still lost after I've read every possible Stackoverflow answer I can find and Googled every article I can find. 我正在做的事情似乎应该很简单,但在我阅读了每一个可能的Stackoverflow答案之后我仍然迷失了,我可以找到并搜索我能找到的每篇文章。

I'm using a preview SurfaceView and capturing an image from an activity that is set for screenOrientation="landscape" in my AndroidManifest.xml. 我正在使用预览SurfaceView并从我在AndroidManifest.xml中为screenOrientation =“landscape”设置的活动中捕获图像。

I followed the sample Camera app code and thought things were working until I tried my app on a few Motorola devices running 1.5. 我按照示例相机应用程序代码进行操作,直到我在运行1.5的一些摩托罗拉设备上尝试我的应用程序之前一直工作。

I have the OrientationEventListener running OK and I use reflection to see if set the rotation as such: 我让OrientationEventListener运行正常,我使用反射来查看是否设置旋转:

final int latchedOrientation = roundOrientation(mLastOrientation + 90);

Parameters parameters = preview.camera.getParameters();

JPLog.d("Setting camera rotation = %d", latchedOrientation);
try {
    // if >= 2.0
    Method method = Camera.Parameters.class.getMethod("setRotation",
        int.class);

    if(method != null) {
        method.invoke(parameters, latchedOrientation);
    }

} catch(Throwable t) {
    // if < 2.0
    parameters.set("rotation", latchedOrientation);
}

preview.camera.setParameters(parameters);

NexusOne (OS 2.2) - Works great. NexusOne(OS 2.2) - 效果很好。 latchedOrientation = 0, picture OK without any rotation in the EXIF header. latchedOrientation = 0,图片OK在EXIF标题中没有任何旋转。

T-Mobile G1 (OS 1.6) - Also works great. T-Mobile G1(OS 1.6) - 也很棒。 latchedOrientation = 0, picture OK. latchedOrientation = 0,图片确定。

Motorola Backflip (OS 1.5) - Image rotated. 摩托罗拉Backflip(OS 1.5) - 图像旋转。 latchedOrientation = 0, picture has no EXIF rotation in it. latchedOrientation = 0,图片中没有EXIF旋转。

Motorola CLIQ (OS 1.5) - Image rotated. Motorola CLIQ(OS 1.5) - 图像旋转。 latchedOrientation = 0, picture has no EXIF rotation in it. latchedOrientation = 0,图片中没有EXIF旋转。

What's going on with these Motorola devices? 这些摩托罗拉设备发生了什么变化? I thought my problem was the Motorola camera driver wasn't rotating the images, so found the Sanselan EXIF reading classes for Android and was preparing to rotate them myself. 我认为我的问题是摩托罗拉相机驱动程序没有旋转图像,所以找到了Android的Sanselan EXIF阅读课,并准备自己旋转它们。 Funny thing is, there is EXIF headers but no rotation element. 有趣的是,有EXIF标题但没有旋转元素。

If I set the rotation manually to 90 degrees, the images come out perfect the Motorola devices, but now the G1 and the NexusOne have images that are rotated 90 degrees (not what I want). 如果我手动将旋转设置为90度,图像就会完美地展现出摩托罗拉设备,但现在G1和NexusOne的图像旋转了90度(不是我想要的)。 There has to be something I'm not getting here. 必须有一些我没有到达的地方。

I'm doubting this is a 1.5 issue, or else someone would've posted info on it? 我怀疑这是1.5问题,否则有人会在上面发布信息?

I had this issue and I used this method to capture the image. 我有这个问题,我使用这种方法来捕捉图像。 (Without creating a custom camera) (无需创建自定义相机)

final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(image));
startActivityForResult(intent, 0);

and did the rest in onActivityResult(int requestCode, int resultCode, Intent data) {} 并在onActivityResult中完成了其余的工作(int requestCode,int resultCode,Intent data){}

But the original image (Actual SD card image) was correct and Bitmap was rotated when I fetched like this. 但原始图像(实际SD卡图像)是正确的,当我这样取出时,位图被旋转。 Bitmap bmp = BitmapFactory.decodeStream(.. 位图bmp = BitmapFactory.decodeStream(..

The solution: 解决方案:

    try {
        File f = new File(SD_CARD_IMAGE_PATH);
        ExifInterface exif = new ExifInterface(f.getPath());
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        int angle = 0;

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
            angle = 90;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
            angle = 180;
        } 
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
            angle = 270;
        }

        Matrix mat = new Matrix();
        mat.postRotate(angle);

        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
        Bitmap correctBmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);                 
    }
    catch (IOException e) {
        Log.w("TAG", "-- Error in setting image");
    }   
    catch(OutOfMemoryError oom) {
        Log.w("TAG", "-- OOM Error in setting image");
    }

This is actually a device-specific issue that mostly affects Motorola devices. 这实际上是一个特定于设备的问题,主要影响摩托罗拉设备。 The google devs included a setDisplayOrientation call in API 8 to work around the issue. 谷歌开发者在API 8中包含了一个setDisplayOrientation调用来解决这个问题。 The main bug is filed here . 主要的错误是在这里提交的。

For those that can't go to API 8, the two common solutions are: 对于那些无法进入API 8的人来说,两种常见的解决方案是:

Override onDraw 覆盖onDraw
Override onDraw in a top-level ViewGroup and rotate the canvas by 90 degrees to compensate for the rotation. 在顶级ViewGroup中覆盖onDraw并将画布旋转90度以补偿旋转。 Note there is a caveat here as your touch events will also need to be rotated. 请注意,此处有一个警告,因为您的触摸事件也需要旋转。

Use Landscape Mode 使用横向模式
Lock the activity to landscape mode but draw assets as if they are in portrait. 将活动锁定为横向模式,但绘制资产就像是纵向一样。 This means you do your layout and rotate your image assets to look like you are in portrait mode so that the view looks normal. 这意味着您可以进行布局并将图像资源旋转为看起来像是处于纵向模式,以便视图看起来正常。 This unfortunately makes it difficult to use the menu since the menu will open horizontally. 遗憾的是,由于菜单将水平打开,因此很难使用菜单。

I have also seen people use an animation controller to rotate the view. 我也看到人们使用动画控制器来旋转视图。 The drawback here that I wasn't able to overcome is that the rotated view doesn't stretch to fill the screen. 我无法克服的缺点是旋转的视图不会伸展以填满屏幕。 See the answer by Georg for a sample implementation. 请参阅Georg答案,了解实施示例。

Here is the code I used onActivityResult() in my activity. 这是我在我的活动中使用onActivityResult()的代码。 The intent returned was for picking an image of the type image/*. 返回的意图是选择图像类型/ *的图像。 Works well for me! 对我来说效果很好!

Uri imageUri = intent.getData();
                String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
                Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
                int orientation = -1;
                if (cur != null && cur.moveToFirst()) {
                    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
                }  
                Matrix matrix = new Matrix();
                matrix.postRotate(orientation);

It looks like the 'use landscape mode' suggestion is the only thing that really works. 看起来“使用景观模式”建议是唯一真正有效的建议。 It seems that it's ok for this to be in either the manifest, or done via a call to setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) in the activity onCreate. 似乎可以将它放在清单中,或通过调用活动onCreate中的setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)来完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM