Android: Bitmaps loaded from gallery are rotated i

2019-01-02 19:51发布

When I load an image from the media gallery into a Bitmap, everything is working fine, except that pictures that were shot with the camera while holding the phone vertically, are rotated so that I always get a horizontal picture even though it appears vertical in the gallery. Why is that and how can I load it correctly?

18条回答
裙下三千臣
2楼-- · 2019-01-02 19:55

Improving on the solution above by Timmmm to add some extra scaling at the end to ensure that the image fits within the bounds:

public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
    Bitmap bitmap = null;
    try {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Adjust extents
        int sourceWidth, sourceHeight;
        if (orientation == 90 || orientation == 270) {
            sourceWidth = options.outHeight;
            sourceHeight = options.outWidth;
        } else {
            sourceWidth = options.outWidth;
            sourceHeight = options.outHeight;
        }

        // Calculate the maximum required scaling ratio if required and load the bitmap
        if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            options.inJustDecodeBounds = false;
            options.inSampleSize = (int)maxRatio;
            bitmap = BitmapFactory.decodeFile(path, options);
        } else {
            bitmap = BitmapFactory.decodeFile(path);
        }

        // Rotate the bitmap if required
        if (orientation > 0) {
            Matrix matrix = new Matrix();
            matrix.postRotate(orientation);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }

        // Re-scale the bitmap if necessary
        sourceWidth = bitmap.getWidth();
        sourceHeight = bitmap.getHeight();
        if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            sourceWidth = (int)((float)sourceWidth / maxRatio);
            sourceHeight = (int)((float)sourceHeight / maxRatio);
            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
        }
    } catch (Exception e) {
    }
    return bitmap;
}
查看更多
残风、尘缘若梦
3楼-- · 2019-01-02 20:00

You can just read the path from sd card and do the following code...it'll Replace the existing photo after rotating it..

Not: Exif doesnt work on most of the devices, it gives the wrong data so it's good to hard code the rotating before saving to any degree you want to,You just have to change the angle value in postRotate to any you want to.

    String photopath = tempphoto.getPath().toString();
    Bitmap bmp = BitmapFactory.decodeFile(photopath);

    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);

    FileOutputStream fOut;
    try {
        fOut = new FileOutputStream(tempphoto);
        bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
        fOut.flush();
        fOut.close();

    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
查看更多
与风俱净
4楼-- · 2019-01-02 20:01

maybe this will help (rotate 90 degree)(this worked for me)

private Bitmap rotateBitmap(Bitmap image){
        int width=image.getHeight();
        int height=image.getWidth();

        Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());

        for (int y=width-1;y>=0;y--)
            for(int x=0;x<height;x++)
                srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
        return srcBitmap;

    }
查看更多
无与为乐者.
5楼-- · 2019-01-02 20:02

So, as an example...

First you need to create an ExifInterface:

ExifInterface exif = new ExifInterface(filename);

You can then grab the orientation of the image:

orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

Here's what the orientation values mean: http://sylvana.net/jpegcrop/exif_orientation.html

So, the most important values are 3, 6 and 8. If the orientation is 6, for example, you can rotate the image like this:

Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);

That's just a quick example, though. I'm sure there are other ways of performing the actual rotation. But you will find those on StackOverflow as well.

查看更多
看淡一切
6楼-- · 2019-01-02 20:05

Got it to work after many attempts thanks to a post I can no longer find :-(

Exif seems to work always, the difficulty was to get the filepath. The code I found makes a different between API older than 4.4 and after 4.4. Basically the picture URI for 4.4+ contains "com.android.providers". For this type of URI, the code uses DocumentsContract to get the picture id and then runs a query using the ContentResolver, while for older SDK, the code goes straight to query the URI with the ContentResolver.

Here is the code (sorry I cannot credit who posted it):

/**
 * Handles pre V19 uri's
 * @param context
 * @param contentUri
 * @return
 */
public static String getPathForPreV19(Context context, Uri contentUri) {
    String res = null;

    String[] proj = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
    if(cursor.moveToFirst()){;
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        res = cursor.getString(column_index);
    }
    cursor.close();

    return res;
}

/**
 * Handles V19 and up uri's
 * @param context
 * @param contentUri
 * @return path
 */
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPathForV19AndUp(Context context, Uri contentUri) {
    String wholeID = DocumentsContract.getDocumentId(contentUri);

    // Split at colon, use second item in the array
    String id = wholeID.split(":")[1];
    String[] column = { MediaStore.Images.Media.DATA };

    // where id is equal to
    String sel = MediaStore.Images.Media._ID + "=?";
    Cursor cursor = context.getContentResolver().
            query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{ id }, null);

    String filePath = "";
    int columnIndex = cursor.getColumnIndex(column[0]);
    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }

    cursor.close();
    return filePath;
}

public static String getRealPathFromURI(Context context,
        Uri contentUri) {
    String uriString = String.valueOf(contentUri);
    boolean goForKitKat= uriString.contains("com.android.providers");

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
            Log.i("KIKAT","YES");
            return getPathForV19AndUp(context, contentUri);
        } else {

            return getPathForPreV19(context, contentUri);
        }
}
查看更多
春风洒进眼中
7楼-- · 2019-01-02 20:06

Use a Utility to do the Heavy Lifting.

9re created a simple utility to handle the heavy lifting of dealing with EXIF data and rotating images to their correct orientation.

You can find the utility code here: https://gist.github.com/9re/1990019

Simply download this, add it to your project's src directory and use ExifUtil.rotateBitmap() to get the correct orientation, like so:

String imagePath = photoFile.getAbsolutePath();             // photoFile is a File class.
Bitmap myBitmap  = BitmapFactory.decodeFile(imagePath);

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
查看更多
登录 后发表回答