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

时间:2013-12-09 19:13:40

标签: android image android-intent android-camera image-gallery

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

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

Exif orientation tag returns 0

Exif data TAG_ORIENTATION always 0

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

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

5 个答案:

答案 0 :(得分:100)

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

根据相机驱动,在保存之前旋转图像或将旋转值保存到exif TAG_ORIENTATION。

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

代码

从EXIF获取方向:

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

旋转位图:

Bitmap bmRotated = rotateBitmap(bitmap, orientation);  

旋转位图的方法:

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

答案 1 :(得分:3)

对我来说,ExifInterface的效果非常好:

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

或者您可以尝试使用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]));
} 

类似解决方案:ExifInterface always returns 1

希望它有所帮助.. :)

答案 2 :(得分:2)

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

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

我不确定Picasso是否也管理EXIF,但有两个快速介绍:

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

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

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

答案 3 :(得分:1)

对于那些来这篇文章的人,请务必使用2016年12月推出的Android支持库中的exifinterface:

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

有关此库的详细信息,请参阅相应的Android开发人员博客文章:Introducing the ExifInterface Support Library

它们还包括用于处理存储在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;
}

答案 4 :(得分:1)

对我来说,解决方案是从输入流中创建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();
}

这是我的完整代码,用于获取从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;
}