从图库中选择的 Android 图像方向始终为 0:Exif TAG

Posted

技术标签:

【中文标题】从图库中选择的 Android 图像方向始终为 0:Exif TAG【英文标题】:Android image selected from gallery Orientation is always 0 : Exif TAG 【发布时间】:2012-11-10 18:32:03 【问题描述】:

当我从图库中选择一张图片并将其设置在我的 android 应用程序的 imageview 上时,我看到 它被反转了 180 或 270 或 90 度。所以要检查/解决这个问题我使用了EXIF 方向,但它总是给我“0”。

我无法解决问题所在。

代码:

Uri selectedImageUri = data.getData();

                    absolutePath = selectedImageUri.getPath();

                    exifMedia = new ExifInterface(absolutePath);
                    String exifOrint = exifMedia.getAttribute(ExifInterface.TAG_ORIENTATION);

                    exifOrientation = Integer.parseInt(exifOrint);

                    System.out.println("Orientation Tag is:"+exifOrientation);

                    /** Convert URI into byte */
                    ContentResolver cr = getBaseContext()
                    .getContentResolver();
                    InputStream inputStream = cr
                    .openInputStream(selectedImageUri);
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);

                    rotatedBMP = getResizedBitmapImage(
                            bitmap, 100, 100,exifOrientation);

                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    rotatedBMP.compress(Bitmap.CompressFormat.PNG, 100,
                            stream);
                    byteArray = stream.toByteArray();
                    mimProfileImageBrowse.setImageBitmap(rotatedBMP);

方法:

public  Bitmap getResizedBitmapImage(Bitmap bm, int newHeight, int newWidth, int exifOrientation) 
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        /**
         *  create a matrix for the manipulation
         */

        Matrix matrix = new Matrix();
        /**
         *  resize the bit map
         */


        /*

         1 = Horizontal (normal) 
2 = Mirror horizontal 
3 = Rotate 180 
4 = Mirror vertical 
5 = Mirror horizontal and rotate 270 CW 
6 = Rotate 90 CW 
7 = Mirror horizontal and rotate 90 CW 
8 = Rotate 270 CW

         */


        switch (exifOrientation) 
        case ExifInterface.ORIENTATION_ROTATE_270:

            rotate = 270;

            break;


        case ExifInterface.ORIENTATION_ROTATE_180:

            rotate = 180;


            break;

        case ExifInterface.ORIENTATION_ROTATE_90:

            rotate = 90;

            break;

        case ExifInterface.ORIENTATION_TRANSPOSE:

            rotate = 45;

            break;

        default:
            break;
        


        matrix.postScale(scaleWidth, scaleHeight);
        matrix.postRotate(rotate);

        /**
         * recreate the new Bitmap
         */
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        resizedBitmap = Bitmap.createScaledBitmap(bm, 65, 65, true);

        return resizedBitmap;

    

请帮忙。 matrix.postROTATE 也没有旋转位图。我不知道为什么。

谢谢

【问题讨论】:

【参考方案1】:

在您获得所选图像的 Uri 后,使用此方法调用以下函数, 像这样,

Uri selectedImageUri = data.getData();
Bitmap bitmap = scaleImage(this,selectedImageUri);

要包含在您的活动中的两个功能是,

 public static Bitmap scaleImage(Context context, Uri photoUri) throws IOException 
        InputStream is = context.getContentResolver().openInputStream(photoUri);
        BitmapFactory.Options dbo = new BitmapFactory.Options();
        dbo.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, dbo);
        is.close();

        int rotatedWidth, rotatedHeight;
        int orientation = getOrientation(context, photoUri);

        if (orientation == 90 || orientation == 270) 
            rotatedWidth = dbo.outHeight;
            rotatedHeight = dbo.outWidth;
         else 
            rotatedWidth = dbo.outWidth;
            rotatedHeight = dbo.outHeight;
        

        Bitmap srcBitmap;
        is = context.getContentResolver().openInputStream(photoUri);
        if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) 
            float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
            float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
            float maxRatio = Math.max(widthRatio, heightRatio);

            // Create the bitmap from file
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = (int) maxRatio;
            srcBitmap = BitmapFactory.decodeStream(is, null, options);
         else 
            srcBitmap = BitmapFactory.decodeStream(is);
        
        is.close();

        /*
         * if the orientation is not 0 (or -1, which means we don't know), we
         * have to do a rotation.
         */
        if (orientation > 0) 
            Matrix matrix = new Matrix();
            matrix.postRotate(orientation);

            srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                    srcBitmap.getHeight(), matrix, true);
        

        String type = context.getContentResolver().getType(photoUri);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        if (type.equals("image/png")) 
            srcBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
         else if (type.equals("image/jpg") || type.equals("image/jpeg")) 
            srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        
        byte[] bMapArray = baos.toByteArray();
        baos.close();
        return BitmapFactory.decodeByteArray(bMapArray, 0, bMapArray.length);
    

    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 (cursor.getCount() != 1) 
            return -1;
        

        cursor.moveToFirst();
        return cursor.getInt(0);
    

要从文件中获取 Uri,请使用:

public static Uri getImageContentUri(Context context, File imageFile) 
        String filePath = imageFile.getAbsolutePath();
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                new String[]  MediaStore.Images.Media._ID ,
                MediaStore.Images.Media.DATA + "=? ",
                new String[]  filePath , null);
        if (cursor != null && cursor.moveToFirst()) 
            int id = cursor.getInt(cursor
                    .getColumnIndex(MediaStore.MediaColumns._ID));
            Uri baseUri = Uri.parse("content://media/external/images/media");
            return Uri.withAppendedPath(baseUri, "" + id);
         else 
            if (imageFile.exists()) 
                ContentValues values = new ContentValues();
                values.put(MediaStore.Images.Media.DATA, filePath);
                return context.getContentResolver().insert(
                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
             else 
                return null;
            
        
    

问。你能告诉我什么是“MAX_IMAGE_DIMENSION”吗? – Dhrupal 2013 年 3 月 13 日 A. 它基于您的图像视图大小或您想要显示的图像大小.. 无论是 60X60 然后 60、100X100 然后 100 @Dhrupal

【讨论】:

我已经解决了EXIF问题。您能否检查一下为什么位图不旋转。它在逻辑上正确执行所有行,但没有旋转位图 你能告诉我什么是“MAX_IMAGE_DIMENSION”吗? 它基于您的图像视图大小或您想要显示的图像大小.. 无论是 60X60 然后 60、100X100 然后 100 @Dhrupal 不幸的是,这在 KitKat 上不起作用,因为它为 Intent.ACTION_GET_CONTENT 返回不同的 Uri static int getOrientation 有泄漏。光标未正确关闭。【参考方案2】:

已经很久没有提问了。但我反驳了同样的问题,并解决了这个问题。当您将文件路径放入 exifInterface 的构造函数时,请使用真实路径,例如“/storage/sdcard0/DCIM/Camera/blahbalh.jpg”,而不是使用 /content:/media/external/images/media/blah 之类的东西,这会给出总是 0 信息。 希望有人会得到帮助。退学。

哎呀。下面一个是相同的方法。还有更多。 用这个。

/**
 * @ref http://***.com/questions/3401579/get-filename-and-path-from-uri-from-mediastore
 * @param contentUri
 * @return
 */
public String getRealPathFromURI(Uri contentUri) 
    String[] proj =  MediaStore.Images.Media.DATA ;
    Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);

【讨论】:

@Piotr 你的设备是什么? LG G2 。它只是返回 null @mylifeforIU:谢谢,这引导我走上了正确的道路。路径是一个问题,主要来自 KitKat。有关解决方案,请参见此处:***.com/a/20559175/690777【参考方案3】:

我猜你不应该使用“selectedImageUri.getPath()”来获取路径,因为它并没有真正返回图像文件路径。相反,您应该使用ContentResolver 来查询MediaStore.Images.ImageColumns.DATA 的值,这是图像的实际路径。

其实如果你只想获取方向,你不必从Exif中获取,只需查询MediaStore.Images.ImageColumns.ORIENTATION的值即可。

【讨论】:

我做对了。但还有一个问题是我的 matrix.postRotate 正在执行但我的位图没有旋转 酷。只是好奇,为什么要分配 resizedBitmap 两次?位图 resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); resizedBitmap = Bitmap.createScaledBitmap(bm, 65, 65, true);【参考方案4】:

试试下面的代码:-

ExifInterface exif = new ExifInterface(filename);  
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);  
Bitmap bmRotated = rotateBitmap(bitmap, orientation); 

调用下面的方法:-

public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) 

    try
        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;
        
    
    catch (IOException e) 
        e.printStackTrace();
        return null;
    
    return bitmap;

【讨论】:

【参考方案5】:

你应该使用 getRealPathFromURI 函数:

public static String getRealPathFromURI(Context context, Uri uri,
            String data) 

    String[] largeFileProjection =  MediaStore.Images.ImageColumns._ID,
            MediaStore.Images.ImageColumns.DATA ;

    String largeFileSort = MediaStore.Images.ImageColumns._ID + " DESC";
    Cursor myCursor = context.getContentResolver().query(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
            largeFileProjection, null, null, largeFileSort);
    String largeImagePath = "";
    try 
        myCursor.moveToFirst();
        largeImagePath = myCursor
                .getString(myCursor
                        .getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DATA));
     finally 
        myCursor.close();
    

    return largeImagePath;

【讨论】:

这个答案对我有用 'documentFilePath=getRealPathFromURI(getApplicationContext(), uri, data.getDataString()); '【参考方案6】:

我无法让光标或 Exif 接口方法为我工作。我无法获得三星前后摄像头的可靠旋转数。

对于那些寻找适用于三星和其他主要制造商的前置和后置摄像头解决方案的人来说,nvhausid 的这个答案太棒了:

https://***.com/a/18915443/6080472

对于那些不想点击的人来说,相关的魔法是使用 CameraInfo 而不是依赖 EXIF。

Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);

链接中的完整代码。

【讨论】:

这个问题是关于从画廊而不是相机中选择图像。【参考方案7】:

当图像被捕获时,它会将 exif 数据存储为有关旋转类型(纵向 - 横向)的信息。所以你唯一需要检查的是exif数据:

ExifInterface exifData = new ExifInterface(uri);
        int orientation = exifData.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
        Matrix matrix;
        switch (orientation) 
        case 6:
             matrix = new Matrix();
            matrix.postRotate(90);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            break;
        case 3:
             matrix = new Matrix();
            matrix.postRotate(180);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            break;
        case 8:
            matrix = new Matrix();
            matrix.postRotate(270);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            break;
        default:
            break;

【讨论】:

【参考方案8】:

您是否已经检查过您是否在清单中设置了写入和读取权限?因为如果您没有设置它们,您将无法访问位图的 exif 数据,我说的是 android M。 这是根据 exif 数据旋转位图的 sn-p。

public static Bitmap rotateBitmap(String filePath, Bitmap bitmap) 
    ExifInterface exif;
    try 
        exif = new ExifInterface(filePath);

        int orientation = exif.getAttributeInt(
                ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
        Log.d("EXIF", "Exif: " + orientation);
        Matrix matrix = new Matrix();
        if (orientation == 6) 
            matrix.postRotate(90);
            Log.d("EXIF", "Exif: " + orientation);
         else if (orientation == 3) 
            matrix.postRotate(180);
            Log.d("EXIF", "Exif: " + orientation);
         else if (orientation == 8) 
            matrix.postRotate(270);
            Log.d("EXIF", "Exif: " + orientation);
        
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
     catch (IOException e) 
        e.printStackTrace();
        return null;
    



【讨论】:

以上是关于从图库中选择的 Android 图像方向始终为 0:Exif TAG的主要内容,如果未能解决你的问题,请参考以下文章

Android:上传到服务器的图像始终为 0 字节

Phonegap - 从图库中选择图像

Android 图库导入

Android Image Picker 从图库中选择多个图像,最大限制为 5

[Android - Kitkat ]以编程方式从 Android 的内置图库应用程序中获取/选择图像

如何从图库(Android Studio)中选择并保存图像?