设置setDisplayOrientation的示例代码是否正确?

17

相机设置显示方向的文档页面包含以下代码示例,说明使用它将“使相机图像在与显示器相同的方向上显示”:

 public static void setCameraDisplayOrientation(Activity activity,
         int cameraId, android.hardware.Camera camera) {
     android.hardware.Camera.CameraInfo info =
             new android.hardware.Camera.CameraInfo();
     android.hardware.Camera.getCameraInfo(cameraId, info);
     int rotation = activity.getWindowManager().getDefaultDisplay()
             .getRotation();
     int degrees = 0;
     switch (rotation) {
         case Surface.ROTATION_0: degrees = 0; break;
         case Surface.ROTATION_90: degrees = 90; break;
         case Surface.ROTATION_180: degrees = 180; break;
         case Surface.ROTATION_270: degrees = 270; break;
     }

     int result;
     if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
         result = (info.orientation + degrees) % 360;
         result = (360 - result) % 360;  // compensate the mirror
     } else {  // back-facing
         result = (info.orientation - degrees + 360) % 360;
     }
     camera.setDisplayOrientation(result);
 }

然而,我在使用它时遇到了问题,有时图像会出现倒置的情况。经过一些试错,我发现正确的代码应该是(替换该方法的最后8行):

    int result = (360 + info.orientation - degrees) % 360;
    camera.setDisplayOrientation(result);

(这意味着用于背面相机的计算方法对前置相机也是正确的。)“补偿镜子”的评论有点奇怪,因为旋转无法撤消镜像,该操作只会交换90°和270°的旋转,这对我来说没有任何意义。

所以问题是:示例确实有误还是我漏了什么? 我在多台设备上尝试过,包括前置和后置摄像头以及所有支持的方向,因此我知道我的代码是有效的。可能值得一提的一个小细节是:所有我的设备都将90°返回为info.orientation

编辑:这里是我的与相机相关的代码,我已在Nexus One和三星Galaxy S Plus上测试过。它用于我的头部跟踪3D应用程序,预览显示在左下角,并且应始终具有正确的方向。

解决方案 (有点): 看起来代码是正确的,但我的测试手机 (三星 Galaxy S Plus) 返回了前置摄像头的 CameraInfo.orientation 的错误值。关于此型号预览显示颠倒的相关讨论很多 (例如 这里这里)。修复的方法是包括一个手动旋转图像的选项。

5
很遗憾,安卓文档中存在许多错误,但现在已经变得越来越好了。我测试了你的代码,在我的设备上也遇到了与你相同的问题。我建议你去这里:https://code.google.com/p/android/issues/entry?template=Developer%20Documentation - Richard Taylor
1个回答

13
你引用的代码片段,在我的项目中使用和应用都没有问题。在我测试的所有设备(Galaxy Note、Galaxy S III、Galaxy Nexus、Galaxy Ace II、Nexus S)中,info.Orientation在前置摄像头上都返回270,在后置摄像头上返回90。
经过与提问者的讨论,我发现我误解了问题,因此将答案分为两部分。
有关相机预览错误方向的解决方案,请参考以下解决方案:
解决相机预览错误方向的方法:
请先确保info.Orientation在前置摄像头上返回270,在后置摄像头上返回90。 然后,请尝试将相机预览活动(或类似处理预览的类)的方向设置为横向。
因此,当您浏览代码时,您会发现:
对于屏幕方向,degree = 90,对于前置摄像头,info.Orientation = 270。然后,您将得到result =(270-90 + 360)%360,result = 180,这意味着它将顺时针旋转180度,以纠正前置摄像头倒置的问题。
有关相机照片结果方向不正确的解决方案:
如果此info.Orientation适用于您,则问题可能是:
一些三星(或其他)设备(如Galaxy Note、Galaxy SIII)仅会写入Orientation标签,而不会旋转实际像素。 如果您正在使用前置摄像头并使用上述代码,则将以正确的方向显示预览,但如果您拍摄照片,则会显示“颠倒”的图片。
解决方案:
/**
 *
 * Get the orientation from EXIF
 * @param filepath
 * @return orientation
 */
public int getExifOrientation(String filepath) {
    int degree = 0;
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(filepath);
    } catch (IOException ex) {
        Log.e("EXIF info", "cannot read exif", ex);
    }
    if (exif != null) {
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
        if (orientation != -1) {
            // We only recognize a subset of orientation tag values.
            switch(orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                degree = 90;
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                degree = 180;
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                degree = 270;
                break;
            }
        }
    } else {
        degree = 1;
    }
    Log.i("EXIF info", "Orientation degrees: " + degree);
    return degree;
}

那么

if (isFromCamera) {

    if (fromFrontCam) {
        // try change here if the orientation still wrong, -90 means rotate counter-clockwise 90 degrees.
        matrix.preRotate(-90);
     } else {
        matrix.preRotate(90);
     }
} else {
    // read EXIF data
    getExifOrientation(path)
    // don't forget to handle the situation that some devices won't write exif data
    matrix.preRotate(degree);
}

@MártonMolnár 是的,这个文档的方法对我有效,我可以在相机预览中获得正确的方向。请问你用的是哪个设备?由于你的问题是关于预览方向的,请问我也可以更新我的回答,抱歉一开始没有完全理解你的问题 :) - dumbfingers
@MártonMolnár,能否让我看看您如何将代码应用到您的项目中?例如,您在哪里调用了这个方法?谢谢。 - dumbfingers
我已添加了您要求的详细信息。 - molnarm
1
根据我的经验,@MártonMolnár,你应该将你的活动(包括相机)设置为横向。 - landry
1
@MártonMolnár谢谢,但我认为我仍然可以帮助您,因为您已经说了您通过代码设置视图,那么您可以尝试:setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);来将相机活动(就像@landry所说的那样,这就是我想告诉您的)设置为横向。希望您理解我在以前的评论中的计算。 - dumbfingers
显示剩余10条评论

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