Android相机拍摄后的图像是否应该旋转?

28

我正在编写一个使用相机的Android应用程序。 我将相机显示方向设置为90,我的活动以纵向方向显示:

camera.setDisplayOrientation(90);

我得到了一个方向正确的预览图片,但是生成的图像被旋转了-90度(逆时针方向)。

exif.getAttribute(ExifInterface.TAG_ORIENTATION)

返回ORIENTATION_NORMAL
这是否是预期行为?在捕获后,我应该旋转结果图像吗?

设备- Nexus S,API-10


我也遇到了同样的问题,我也在 Nexus S API 10 上;感谢你提出这个问题。 - serkanozel
请访问以下链接以获取有关Android相机意图拍摄的图像在某些设备上旋转的原因的答案:https://dev59.com/3WYq5IYBdhLWcg3w8VG8 - Shirish Herwade
4个回答

26

试一试

try {
        File f = new File(imagePath);
        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);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;

        Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f),
                null, options);
        bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
                bmp.getHeight(), mat, true);
        ByteArrayOutputStream outstudentstreamOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100,
                outstudentstreamOutputStream);
        imageView.setImageBitmap(bitmap);

    } catch (IOException e) {
        Log.w("TAG", "-- Error in setting image");
    } catch (OutOfMemoryError oom) {
        Log.w("TAG", "-- OOM Error in setting image");
    }

它会工作


2
你好奇是如何得出这将适用于所有设备的结论的。 - sudocoder

15

问题是相机方向及拍照完全混乱,因为OEMs不遵守标准。HTC手机采用一种方式,三星手机采用另一种方式,无论哪个供应商,Nexus系列似乎都遵守标准,基于CM7的ROM我认为无论是哪种硬件都遵循标准,但你懂的。你必须根据手机/ROM来确定要做什么。参见此处讨论:Android相机在某些设备上捕获时旋转难以解释(不在EXIF中)


6
我有和你一样的问题,但我已经解决了。
你应该使用相同的代码:
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(90);
camera.setParameters(parameters);

我希望您也能使用这段代码。


谢谢,问题已解决!在我的三星Galaxy S8+上运行良好。 - Mangi Morobe

2
camera.setDisplayOrientation(90);

我只为竖屏模式编写了应用程序。

将相机旋转90度可能导致在Android中不适用于所有设备,为了获得所有Android设备的正确预览,请使用开发人员网站中引用的以下代码。

下面您需要发送您的活动,cameraId = back是0,前置摄像头是1

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;
    //int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        // do something for phones running an SDK before lollipop
        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);
} 

这是如何设置相机的setDisplayOrientation:
现在你可能会遇到一个问题,就是在正确的方向上保存捕获的图像,在Android中支持所有设备的Camera API中存在的一个错误。你可以通过以下步骤来克服这个问题。
请注意,EXIF值在所有设备上都不能给出正确的值,因此这将对你有所帮助。
int CameraEyeValue = setPhotoOrientation(CameraActivity.this, cameraFront==true ? 1:0); // CameraID = 1 : front 0:back

通过使用我们之前用于 DisplayOrientation 的相同概念

public int setPhotoOrientation(Activity activity, int cameraId) {
    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;
    // do something for phones running an SDK before lollipop
    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;
    }

    return result;
}

所以你的最终PictureCallBack方法应该像这样:
private PictureCallback getPictureCallback() {
    PictureCallback picture = new PictureCallback() {

        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            //make a new picture file
            File pictureFile = getOutputMediaFile();

            if (pictureFile == null) {
                return;
            }
            try {
                //write the file
                FileOutputStream fos = new FileOutputStream(pictureFile);
                Bitmap bm=null;

                // COnverting ByteArray to Bitmap - >Rotate and Convert back to Data
                if (data != null) {
                    int screenWidth = getResources().getDisplayMetrics().widthPixels;
                    int screenHeight = getResources().getDisplayMetrics().heightPixels;
                    bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);

                    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                        // Notice that width and height are reversed
                        Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
                        int w = scaled.getWidth();
                        int h = scaled.getHeight();
                        // Setting post rotate to 90
                        Matrix mtx = new Matrix();

                        int CameraEyeValue = setPhotoOrientation(AndroidCameraExample.this, cameraFront==true ? 1:0); // CameraID = 1 : front 0:back
                        if(cameraFront) { // As Front camera is Mirrored so Fliping the Orientation
                            if (CameraEyeValue == 270) {
                                mtx.postRotate(90);
                            } else if (CameraEyeValue == 90) {
                                mtx.postRotate(270);
                            }
                        }else{
                                mtx.postRotate(CameraEyeValue); // CameraEyeValue is default to Display Rotation
                        }

                        bm = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
                    }else{// LANDSCAPE MODE
                        //No need to reverse width and height
                        Bitmap scaled = Bitmap.createScaledBitmap(bm, screenWidth, screenHeight, true);
                        bm=scaled;
                    }
                }
                // COnverting the Die photo to Bitmap



                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bm.compress(Bitmap.CompressFormat.JPEG, 100, stream);
                byte[] byteArray = stream.toByteArray();
                fos.write(byteArray);
                //fos.write(data);
                fos.close();

                Toast toast = Toast.makeText(myContext, "Picture saved: " + pictureFile.getName(), Toast.LENGTH_LONG);
                toast.show();

            } catch (FileNotFoundException e) {
            } catch (IOException e) {
            }

            //refresh camera to continue preview
            mPreview.refreshCamera(mCamera);
            mPreview.setCameraDisplayOrientation(CameraActivity.this,GlobalCameraId,mCamera);
        }
    };
    return picture;
}

由于该作品仅适用于使用前置和后置摄像头的纵向模式,因此在所有Android设备中,图片会被旋转为正确的纵向方向。

对于横向模式,您可以参考以下内容并对下面的代码块进行更改。

   if(cameraFront) { // As Front camera is Mirrored so Fliping the Orientation
         if (CameraEyeValue == 270) {
             mtx.postRotate(90); //change Here 
          } else if (CameraEyeValue == 90) {
             mtx.postRotate(270);//change Here 
           }
        }else{
           mtx.postRotate(CameraEyeValue); // CameraEyeValue is default to Display Rotation //change Here 
        }

我想始终以纵向捕获图像,但我找不到位图的旋转角度。 - MIkka Marmik

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