当前位置: 首页 > 知识库问答 >
问题:

保存的位图方向不正确

柳和怡
2023-03-14

这个问题已经被问了无数次,但是没有一个真正解决保存Bitmap时的旋转问题。

这是我最初如何保存一个位图到我的设备:

FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mStringFilePath);
//Time is us
int mPresentationTime = mPlayer.getPresentationTime();
Bitmap mBitmap = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

File mFileBitmap = new File(directoryToStore, "test.png");
try {
    FileOutputStream outputStream = new FileOutputStream(mFileBitmap);
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
    outputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

以上内容保存了。方向错误的png

然后我看到了这个答案,但问题是它将已经保存的位图旋转到正确的方向。例如,如果您想将Bitmap设置为ImageView,则可以这样做。但是,如果我想共享位图,或者想在设备库中打开它,方向仍然不正确。然后,我将不得不执行与上面相同的过程-FileOutputStream等。这将导致同样的问题。

如何将位图以正确的方向保存到设备?

尝试Long提供的答案。

我用您提供的2方法创建了一个名为RotateBit的新类。然后我将我的代码更改为:

FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mStringFilePath);
//Time is us
int mPresentationTime = mPlayer.getPresentationTime();
Bitmap mBitmapBeforeRotation = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

int rotatingInt = RotateBit.getBitmapOriention(mStringFilePath);
Bitmap mBitmap = RotateBit.rotateBitmap(mBitmapBeforeRotation, rotatingInt);

File mFileBitmap = new File(directoryToStore, "test.png");
try {
    FileOutputStream outputStream = new FileOutputStream(mFileBitmap);
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
    outputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

但是旋转仍然是不正确的。

我注意到这个问题与ffmpegmediataretriever有关,当使用mediamadedataretriever时,这个问题不会发生。


共有3个答案

祝花蜂
2023-03-14

我设法创造了一个变通办法。这可能不是应该做的,但就目前而言,它是有效的。

我的活动设置为纵向/横向取决于我正在播放的视频的旋转。因此,我可以使用它来确定是否旋转位图。

我首先创建了一个位图,就像我以前做的那样:

Bitmap mBitmapBeforeRotation = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

然后我得到屏幕的旋转,位图的宽度/高度,并相应地旋转位图

int mBitW = Integer.parseInt(String.valueOf(mBitmapBeforeRotation.getWidth()));
int mBitH = Integer.parseInt(String.valueOf(mBitmapBeforeRotation.getHeight()));

int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Do nothing because Landscape doesn't give wrong Bitmap rotation
} else {
    if (mBitW>mBitH){
    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    Bitmap fixedBitmapRotation = Bitmap.createBitmap(mBitmapBeforeRotation, 0, 0, mBitmapBeforeRotation.getWidth(), mBitmapBeforeRotation.getHeight(), matrix, true);

    String nameOfImage = "nameOfImage" + ".jpeg";
    final File mFile = new File(directoryyToStore, nameOfImage);

    try {
        FileOutputStream outputStream = new FileOutputStream(mFile);
        fixedBitmapRotation.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
    texeBit = mp.getPath();

}

只是一个旁注。我不必使用屏幕的旋转来确定是否应该旋转Bitmap。我可以先创建一个位图MediaMetadataRetriever(因为MediaMetadataRetriever给我的位图的正确旋转),然后这样做:

int videoWidth;
int videoHeight;

MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(this, mVideoUri);

Bitmap bmp = retriever.getFrameAtTime();

videoWidth = bmp.getWidth();
videoHeight = bmp.getHeight();

我可以像上面那样做。

我不会接受我自己的答案,因为我没有在多台设备上测试过,而且这是一种非常“黑客式”的解决方法。

凌轶
2023-03-14

您需要使用ExifInterface进行旋转。

public static void normalizeImageForUri(Context context, Uri uri, ImageView imgImageView) {
        try {
//            Log.d(TAG, "URI value = " + uri.getPath());
            ExifInterface exif = new ExifInterface(getRealPathFromURI(context, uri));
//            Log.d(TAG, "Exif value = " + exif);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
            Bitmap rotatedBitmap = rotateBitmap(bitmap, orientation);
            imgImageView.setImageBitmap(rotatedBitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
}

用于检查位图的旋转:

private static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
        }
        try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();

            return bmRotated;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }

更多详情请参考以下链接:

如何获得从默认图像库中选择的图像的正确方向

https://github.com/google/cameraview/issues/22#issuecomment-269321811

魏雅惠
2023-03-14
public static int getBitmapOriention(String path){
    ExifInterface exif = null;
    int orientation = 0;
    try {
        exif = new ExifInterface(path);
        orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);
        //Log.e("getBitmapOriention", "getBitmapOriention: "+orientation );
    } catch (Exception e) {
        e.printStackTrace();
    }
    return orientation;
}
/**
 * @param bitmap bitmap from path
 * @param orientation ExifInterface
 * @return oriention flag
 */
public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {

    Matrix matrix = new Matrix();
    switch (orientation) {
        case ExifInterface.ORIENTATION_NORMAL:
            return bitmap;
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
            matrix.setScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.setRotate(180);
            break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            matrix.setRotate(180);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
            matrix.setRotate(90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.setRotate(90);
            break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
            matrix.setRotate(-90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.setRotate(-90);
            break;
        default:
            return bitmap;
    }
    try {
        Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap.recycle();
        return bmRotated;
    }
    catch (OutOfMemoryError e) {
        e.printStackTrace();
        return null;
    }
}

它对我有用

rotateBitmap(mBitmap,getBitmapOriention(mPath));
 类似资料:
  • 我在Android上工作。我需要保存一个没有质量损失的位图。 我使用位图的方法进行了尝试,将质量设置为100。这对我不起作用,位图失去了太多的质量。我已经测试了JPEG和PNG格式。 我已经测试过将位图复制到,然后提取,并使用保存它。在这种情况下,我无法显示用这种方式保存的图像,我只看到一个空白页。 我的问题是,有没有办法在不压缩的情况下将位图保存在SD卡中? 编辑:这里我的代码的一部分 我检测到

  • 问题内容: 如果在保存之前使用图像,那是正常的。但是,如果我保存并以后使用,则需要旋转90度。我如何确保它不会横向保存? 问题答案: 如果需要以正确的旋转方式保存PNG,则如果方向不正确,则需要重新绘制图像。您可以按以下方式重绘它: 编辑/更新: 对于iOS10 + tvOS10 +,您可以使用: 游乐场测试: 不透明图像的用法: 具有透明度:

  • 所以我用下面的方法设置了摄像头- 如您所见,我在摄像机参数上使用了setRoation()来实际指定图像方向,并在摄像机本身上使用了setDisplayOriation()来处理表面预览中的方向更改。(注释和未注释的代码似乎都没有保留方向。当我检查数据时,它返回0) 之后,在回调中,我甚至尝试使用矩阵保存具有方向的图像。 实际问题 > 当我在肖像模式下拍照时,一切正常。它看起来像是被拿走了。 但是

  • 问题内容: 我正在显示一组图像,然后,如果用户希望,可以将图像保存到SD卡。我需要将其保存到外部存储的帮助。有人可以帮我这个忙吗? 网格视图: ImageAdapter: 问题答案: 嗨,我还没有使用过作为应用程序一部分提供的代码,但是我确实使用它来调试了其中一个应用程序在运行时生成的位图。 使用此代码,只要您有位图,就只需要此+清单权限 希望能帮到您 杰森

  • 我正在从相机中保存一个处于横向模式的图像。所以它被保存在横向模式下,然后我在它上面应用一个覆盖层,它也是在横向模式下。我想旋转那个图像,然后保存。例如,如果我有这个 我想顺时针旋转90度一次,这样做,并将其保存到SD卡: 如何做到这一点?

  • 我是新的Android和工作在一个项目中,我必须使用自定义相机与覆盖图像捕获图像。 我可以用叠加(组合图像)捕获图像,但问题是叠加图像方向在保存新的组合图像后发生变化,即叠加图像主要设置在纵向模式,但在保存后显示在横向模式。 我已经搜索了很多关于如何改变可绘制图像的方向,但所有方向的改变都是针对位图图像的。若我将可绘制图像更改为位图并更改旋转,它不会显示任何覆盖图像。我不知道代码出了什么问题。我的