保存的位图方向不正确

时间:2018-09-06 07:19:16

标签: java android bitmap

这个问题被问了无数次,但是在保存Bitmap时,它们都没有解决轮换问题。

这是我最初将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保存为错误的方向。

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

有人可以帮助我了解如何将Bitmap以正确的方向保存到设备吗?


编辑1:

尝试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();
}

但是旋转仍然不正确。


编辑2:

我注意到此问题与FFmpegMediaMetadataRetriever有关,使用MediaMetadataRetriever时不会发生此问题。

3 个答案:

答案 0 :(得分:0)

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));

答案 1 :(得分:0)

您需要使用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;
        }
    }

有关此链接的更多详细信息,请参见:

How to get the Correct orientation of the image selected from the Default Image gallery

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

答案 2 :(得分:0)

我设法创建了一种解决方法。这可能不是应该怎么做,但目前为止,它可以正常工作。


根据正在播放的视频的旋转方式,我的Activity设置为纵向/横向。因此,我可以使用它来确定是否旋转Bitmap

我首先像以前一样创建一个Bitmap

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

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

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。我可以先用Bitmap创建一个MediaMetadataRetriever(因为MediaMetadataRetrieverBitmap提供了正确的旋转方式),然后执行以下操作:

int videoWidth;
int videoHeight;

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

Bitmap bmp = retriever.getFrameAtTime();

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

我可以做上面的事情。


我不会接受自己的回答,因为我没有在多台设备上进行测试,而且这是解决此问题的一种非常“ hack-ish”的方式。