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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20478765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:55:57  来源:igfitidea点击:

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

androidimageandroid-intentandroid-cameraimage-gallery

提问by ramsraj111

I have gone through some of the links to get the correct image orientation of the image selected from the default image gallery to be worked standard in all devices the exif tag always returns 0.

我已经浏览了一些链接,以获得从默认图像库中选择的图像的正确图像方向,以便在所有设备中正常工作,exif 标签始终返回 0。

EXIF orientation tag value always 0 for image taken with portrait camera app android

对于使用人像相机应用程序 android 拍摄的图像,EXIF 方向标签值始终为 0

Exif orientation tag returns 0

Exif 方向标签返回 0

Exif data TAG_ORIENTATION always 0

Exif 数据 TAG_ORIENTATION 始终为 0

http://mobisocial.stanford.edu/news/2011/08/rotating-images-in-android/

http://mobisocial.stanford.edu/news/2011/08/rotating-images-in-android/

How to get an exact solution that will work on all devices?

如何获得适用于所有设备的精确解决方案?

回答by ramaral

If the image(photo) was taken by a program made by you, you must set Parameters.setRotation with the correct rotation value.

如果图像(照片)是由您制作的程序拍摄的,您必须使用正确的旋转值设置 Parameters.setRotation。

This, depending of camera drive, rotates the image before save or save the rotation value to exif TAG_ORIENTATION.

这取决于相机驱动器,在保存之前旋转图像或将旋转值保存到 exif TAG_ORIENTATION。

Therefore, if TAG_ORIENTATION is null or zero, the image are in the correct orientation, otherwise you must rotate image according the value in TAG_ORIENTATION.

因此,如果 TAG_ORIENTATION 为空或零,则图像处于正确的方向,否则您必须根据 TAG_ORIENTATION 中的值旋转图像。

CODE

代码

Get orientation from EXIF:

从 EXIF 获取方向:

ExifInterface exif = null;
try {
    exif = new ExifInterface(path);
} catch (IOException e) {
    e.printStackTrace();
}  
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 
                                       ExifInterface.ORIENTATION_UNDEFINED);

Get bitmap rotated:

获取位图旋转:

Bitmap bmRotated = rotateBitmap(bitmap, orientation);  

Method to rotate bitmap:

旋转位图的方法:

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

回答by Ankit Popli

For me ExifInterface worked quite well like this:

对我来说,ExifInterface 工作得很好,就像这样:

ExifInterface exifInterface = new ExifInterface(imagePath);
degree = Integer.parseInt(exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION));

or you can try to get the details of image using MediaStorelike this:

或者您可以尝试使用以下方法获取图像的详细信息MediaStore

String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
    orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
} 

Similar Solution: ExifInterface always returns 1

类似的解决方案:ExifInterface 总是返回 1

Hope it helps.. :)

希望能帮助到你.. :)

回答by Mehlyfication

For those who come along this post, make sure to use the exifinterface from the Android Support Library that was introduced in December 2016:

对于那些看到这篇文章的人,请确保使用 2016 年 12 月推出的 Android 支持库中的 exifinterface:

compile "com.android.support:exifinterface:25.1.0" // or newer

Details about this library can be found in the according Android Developers Blog post: Introducing the ExifInterface Support Library

有关此库的详细信息可以在相应的 Android 开发者博客文章中找到:ExifInterface 支持库介绍

They also included a sample code for dealing with rotation information stored in the exif interface:

他们还包括一个示例代码,用于处理存储在 exif 界面中的旋转信息:

int rotation = 0;
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

switch (orientation) {
   case ExifInterface.ORIENTATION_ROTATE_90:
     rotation = 90;
     break;
  case ExifInterface.ORIENTATION_ROTATE_180:
     rotation = 180;
     break;
  case ExifInterface.ORIENTATION_ROTATE_270:
     rotation = 270;
     break;
}

回答by Santi Iglesias

I followed last answer and I tried hard to create a system to manage pictures, rotate, resize, cache and load into ImageViews and I can tell it is a hell. Even when all it was done it crashes sometimes cause OutOfMemory in some devices. Answer is correct but it is difficult to manage Bitmaps in Android.

我遵循了最后一个答案,我努力创建一个系统来管理图片、旋转、调整大小、缓存和加载到 ImageViews 中,我可以说这是一个地狱。即使完成了所有操作,它有时也会在某些设备中导致 OutOfMemory 崩溃。答案是正确的,但在 Android 中很难管理位图。

My point is do not reinvent the wheel, it has a perfect design. Google itself encourage you to use Glide. It works in one line, super easy to use, lightweight in size and functions number, it manage EXIF by default, and it use memory like a charm.. It is simply black magic coded ;)

我的观点是不要重新发明轮子,它有一个完美的设计。Google 本身鼓励您使用Glide。它在一行中工作,超级易于使用,体积和功能数量轻巧,默认情况下管理 EXIF,并且它像魅力一样使用内存......它只是黑魔法编码;)

I'm not sure if Picassoalso manages EXIF, but there is a quick intro to both of them:

我不确定毕加索是否也管理 EXIF,但有一个对它们的快速介绍:

https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

My Advice: do not waste your time and use them. You can solve your problem in one line:

我的建议:不要浪费你的时间并使用它们。您可以在一行中解决您的问题:

Glide.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);

回答by Grant Luck

The solution for me was to create the ExifInterface from the input stream. Do not try to create it from a path, which maybe a content provider path and will fail to give the correct result. Convert the orientation into degrees and rotate image if required. Below is the key code for the solution when using the support library (e.g androidx.exifinterface.media.ExifInterface).

我的解决方案是从输入流创建 ExifInterface。不要尝试从路径创建它,这可能是内容提供者路径,并且无法给出正确的结果。如果需要,将方向转换为度数并旋转图像。以下是使用支持库(例如androidx.exifinterface.media.ExifInterface)时解决方案的关键代码。

int orientation = 0;
InputStream input = mContext.getContentResolver().openInputStream(uri);
if (input != null){
    ExifInterface exif = new ExifInterface(input);
    orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    input.close();
}

Here is my full code to obtain a correctly orientated bitmap selected from the Gallery, which also takes a maxsize. If using it make sure you check for the null return case.

这是我的完整代码,用于获取从 Gallery 中选择的正确方向的位图,它也需要一个 maxsize。如果使用它,请确保检查空返回情况。

public Bitmap getBitmapFromGalleryUri(Context mContext, Uri uri, Double maxSize)throws IOException {
    int orientation = 0;

    InputStream input = mContext.getContentResolver().openInputStream(uri);
    if (input != null){
        ExifInterface exif = new ExifInterface(input);
        orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        //Log.d("Utils", "rotation value = " + orientation);
        input.close();
    }


    input = mContext.getContentResolver().openInputStream(uri);

    BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
    onlyBoundsOptions.inJustDecodeBounds = true;
    onlyBoundsOptions.inDither = true;//optional
    onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
    BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
    try {
        input.close();

    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
        return null;
    }

    int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;

    double ratio = (originalSize > maxSize) ? (originalSize / maxSize) : 1.0;

    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
    bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
    bitmapOptions.inDither = true; //optional
    bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//
    input = mContext.getContentResolver().openInputStream(uri);
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
    try {
        input.close();

    } catch (NullPointerException e) {
        e.printStackTrace();
    }
    Matrix matrix = new Matrix();

    //Log.d("Utils", "rotation value = " + orientation);

    int rotationInDegrees = exifToDegrees(orientation);
    //Log.d("Utils", "rotationInDegrees value = " + rotationInDegrees);

    if (orientation != 0) {
        matrix.preRotate(rotationInDegrees);
    }

    int bmpWidth = 0;
    try {
        bmpWidth = bitmap.getWidth();
    } catch (NullPointerException e) {
        e.printStackTrace();
    }
    Bitmap adjustedBitmap = bitmap;
    if (bmpWidth > 0) {
        adjustedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }

    return adjustedBitmap;

}
private static int getPowerOfTwoForSampleRatio(double ratio){
    int k = Integer.highestOneBit((int)Math.floor(ratio));
    if(k==0) return 1;
    else return k;
}

public static int exifToDegrees(int exifOrientation) {
    if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {  return 180; }
    else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {  return 270; }
    return 0;
}