【问题标题】:Bitmap is rotated after taking photo with Camera用相机拍照后位图旋转
【发布时间】:2015-05-12 12:13:07
【问题描述】:

使用相机 API 和预览SurfaceView 在设备处于纵向时拍摄照片后,创建的图像将旋转 90 度。我知道这是一个影响 一些 android 手机的问题,包括我正在开发的三星 Galaxy S5 - 有几个堆栈溢出问题 - see herehere。建议图像文件将包含 EXIF 元数据,该元数据将说明旋转的方向,以便您可以使用它来旋转图像以获得正确的方向。我已经这样做了,但由于某种原因,ExifInterface.TAG_ORIENTATION1 - ORIENTATION_NORMAL。因此,我无法确定图像需要旋转多少才能确保它适用于所有设备。尽管该解决方案似乎对其他人有效。我做错了什么,或者如何解决这个问题?

一些伪代码:

//in onCreate
camera = getCameraInstance();
setCameraDisplayOrientation(this, cameraID, camera);

//in OnClickListener
camera.takePicture(null, null, picCallback);

//callback:
onPictureTaken {
    //create a File using getExternalStoragePublicDirectory(PICTURES) + "appname" - create directory if doesn't exist
    //write file to disk via FileOutputStream

    //attempt to correct the image orientation if needed
    Bitmap correctBitmap = getCorrectOrientationBitmap(picFile.getAbsolutePath());
}

public Bitmap getCorrectOrientationBitmap(String photoFilePath) {
    // Read EXIF Data
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(photoFilePath);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
    //problem: orientation is 1 - ORIENTATION_NORMAL despite the fact the image is rotated to the right 90 degrees
    //rotate the image based on EXIF orientation
}

//later on
myImageView.setImageBitmap(correctBitmap); 
//shows image rotated to the right because getCorrectOrientationBitmap didn't rotate it

【问题讨论】:

  • stackoverflow.com/questions/14066038/… 仔细阅读所有答案..你没有得到正确的 bmp.ORIENT ..请参阅链接上“mediaStore”上的内容查询..这是三星唯一的问题 AFAIK
  • @RobertRowntree 我没有使用MediaStore
  • @JordanH 你能解决这个问题吗?我也被困在同一点上。图像被保存为旋转。您可以为此发布解决方案吗?

标签: android bitmap imageview android-camera exif


【解决方案1】:

前段时间我在处理这个问题,并在GitHub here 上发布了一些相机代码。问题是您要处理 3 个不同的实体:

  • 表面方向 - 取决于当前的设备方向
  • 预览从'surfaceChanged'获得的宽度/高度
  • 从“takePicture”获得的最终图片方向

在提到的示例中,我rotate the final 图像的数量与我旋转preview at the beginning 的数量相同。我还没有在 S5 上测试过,所以如果你这样做,请让我知道它是否可以在那里工作。

另外,一些平板电脑 (see readme.md) 也存在问题,其中一些具有 'natural' orientation landscape (Nex7 1Gen),而另一些 (Nex7 2Gen) 则具有纵向 - 与手机相同。

祝你好运

【讨论】:

    【解决方案2】:

    --编辑-- 在我的代码中...

    matrix.postRotate(旋转);

    使用 felix 的代码从光标返回的“旋转”值。

    我认为你的照片有一个 URI....查看界面与使用静态 attr 值的类型....

    public static int getOrientation(Context context, Uri photoUri) {
        /* it's on the external media. */
        Cursor cursor = context.getContentResolver().query(photoUri,
                new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
        if(null == cursor){
            return -1;
        }
        if (cursor.getCount() != 1) {
            return -1;
        }
    

    .....

    if (getOrientation(mctx, mURI) != 0 && != -1) doRotate();
    
    
    public doRotate(){
        Bitmap lbit =   
        BitmapFactory.decodeStream(                                               getContentResolver().openInputStream(_uri),null,options);
        Log.i(TAG, "Rotating... " + rotation);
        lbit = lbit.copy(Bitmap.Config.ARGB_8888, true);
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);
        lbit = Bitmap.createBitmap(lbit, 0, 0, lbit.getWidth(),
        lbit.getHeight(), matrix, true);
        Picture.setBmp(lbit);
    
        cursor.moveToFirst();
        return cursor.getInt(0);
        }
    }
    

    【讨论】:

    • cursornull,当我尝试这样做时。如果我使用 Felix 回答中的 getRotation 方法,它会返回 0 - 但 mediaCursor 不为空。
    • Felix=对你来说可能的解决方案。如果 mediaCursor 不为空,则尝试使用返回值来驱动旋转,就像在 Felix 的代码中一样。请注意,我得到的解决方案是基于我认为 felix 的代码构建的。我找不到任何其他关于新三星平板电脑轮换的解释,而 felix 代码解决了这个问题。我的代码可能逐字可用,但我试图打包一些有意义的东西。了解 felix 的意图。
    • 他的getRotation 代码从不使用selectedImage Uri - 这总是返回图库中最后一张照片的方向,而不是应用程序中拍摄的照片
    • 尝试在你的 picCallback 中使用上下文的 Uri。当它从相机返回时,隐含意图的“getData()”应该有最后一张照片的 uri...my orig。代码示例的 Uri 是通过对媒体类型照片进行 Intent 选择来设置的,并使用从该操作返回的 Uri。
    【解决方案3】:

    当您使用图片回调而不是相机捕获意图时,EXIF 方向未设置。但另一方面,当用户单击“捕获”按钮或其等效按钮时,您可以准确地知道设备方向。

    如果您的活动被锁定为纵向,这将变得更加容易 - 您可以无条件地应用 90° 旋转。

    位图旋转在内存和性能方面可能非常昂贵,因此如果通过设置正确的TAG_ORIENTATION 来满足您的用例,那么只需将此更改应用于您保存的图像。请注意,ExifInterface 适用于文件,而不是 byte[],因此违反直觉,您应该先保存缓冲区,然后应用旋转,然后再次保存。

    【讨论】:

    • 如果我能始终确保在锁定纵向的活动中拍照时,每部手机都会将图像向右旋转 90 度,那就太棒了。您能否确认会出现这种情况 - 从我的研究来看,这种行为(错误?)仅存在于少数手机(尤其是三星)中。
    • 很遗憾,答案是否定的。考虑具有“自然”方向横向的平板电脑,而其他平板电脑(通常为 7 英寸)默认为纵向。在回调中不设置 TAG_ORIENTATION 是合法的,但根据当前设备方向设置它也是合法的。
    【解决方案4】:

    拍照前需要根据当前设备方向setDisplayOrientation()。这不是自动完成的,默认情况下始终设置为 0 度,通常对应于横向。

    这不是 Galaxy s5 的问题

    【讨论】:

    • 我已经打电话给setDisplayOrientation。将更新代码以显示这一点。
    • 还有问题吗?
    • 是的,在发布问题之前我的代码中就有这个
    • setDisplayOrientation 仅适用于您在使用相机时显示的预览。它对拍摄的实际照片没有影响。问题在于旋转后的 camera.takePicture 拍摄的图像。 @JordanH 如果您找到解决方案,请在此处发布。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    相关资源
    最近更新 更多