Android:从图库加载的位图在ImageView中旋转

Man*_*uel 132 android bitmap rotation gallery

当我将媒体库中的图像加载到位图时,一切都运行正常,除了在垂直拿着手机时用相机拍摄的图片被旋转,以便我总是得到水平图片,即使它在画廊.为什么这样,我怎么能正确加载它?

Man*_*uel 178

所以,作为一个例子......

首先,您需要创建ExifInterface:

ExifInterface exif = new ExifInterface(filename);
Run Code Online (Sandbox Code Playgroud)

然后,您可以获取图像的方向:

orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Run Code Online (Sandbox Code Playgroud)

以下是方向值的含义:http: //sylvana.net/jpegcrop/exif_orientation.html

因此,最重要的值是3,6和8.例如,如果方向为6,则可以像这样旋转图像:

Matrix matrix = new Matrix();
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);
Run Code Online (Sandbox Code Playgroud)

不过,这只是一个简单的例子.我确信还有其他方法可以执行实际旋转.但是你也可以在StackOverflow上找到它们.

  • 当您可以使用命名常量时,请不要使用幻数:ExifInterface.ORIENTATION_NORMAL,ExifInterface.ORIENTATION_ROTATE_90,ExifInterface.ORIENTATION_ROTATE_180,ExifInterface.ORIENTATION_ROTATE_270. (100认同)
  • 使用此方法时请注意"OutOfMemoryError",因为您同时在内存中保存两个位图. (29认同)
  • 以下是不同方向的所有旋转值:3:180,6:90,8:270 (5认同)

Tim*_*mmm 63

这是一个完整的解决方案(在Facebook SDK的Hackbook示例中找到).它的优点是不需要访问文件本身.如果您从内容解析器中加载图像,这非常有用(例如,如果您的应用正在响应共享照片意图).

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);
}
Run Code Online (Sandbox Code Playgroud)

然后您可以按如下方式获得旋转的位图.此代码还会将图像(非常不幸地)缩小到MAX_IMAGE_DIMENSION.否则你可能会耗尽内存.

public static Bitmap getCorrectlyOrientedImage(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);
    }

    return srcBitmap;
}
Run Code Online (Sandbox Code Playgroud)

  • cursor为null. (5认同)
  • 它是您获得的图像的最大宽度或高度.也就是说你只需要一个512x512的图像,如果你打开一个2400万像素的图像,打开已经二次采样的效率比打开整个事物然后缩小它更有效 - 这可能会耗尽你所有的记忆. (3认同)

Teo*_*nke 59

在这个帖子的帮助下,使用此代码解决了我的问题:

            Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());

            try {
                ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                Log.d("EXIF", "Exif: " + orientation);
                Matrix matrix = new Matrix();
                if (orientation == 6) {
                    matrix.postRotate(90);
                }
                else if (orientation == 3) {
                    matrix.postRotate(180);
                }
                else if (orientation == 8) {
                    matrix.postRotate(270);
                }
                myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
            }
            catch (Exception e) {

            }
            ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
            img.setImageBitmap(myBitmap);
Run Code Online (Sandbox Code Playgroud)

希望它能节省一些人的时间!

  • 为我工作出色.谢谢! (4认同)

Jam*_*mes 40

你看过图像的EXIF数据了吗?拍摄照片时,它可能知道相机的方向.

  • 你是对的,这当然是解决方案.我将在稍后的单独答案中将我的代码作为示例发布,但我将此标记为已接受,因为它让我走上了正确的轨道. (2认同)

Jos*_*ter 39

使用Utility来进行重物提升.

9re创建了一个简单的实用程序来处理繁重处理EXIF数据和将图像旋转到正确的方向.

您可以在此处找到实用程序代码:https://gist.github.com/9re/1990019

只需下载它,将其添加到项目的src目录并使用ExifUtil.rotateBitmap()以获得正确的方向,如下所示:

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

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
Run Code Online (Sandbox Code Playgroud)

  • 你是英雄我的朋友:) (3认同)
  • 适合我!我只是将位图重新调整为HD格式,然后将其传递给ExifUtil.rotateBitmap()以避免出现类似OutOfMemoryError:Bitmap resized = Bitmap.createScaledBitmap(myBitmap,720,1280,true); photo = ExifUtil.rotateBitmap(picturePath,resized); (2认同)

far*_*ran 8

因为图库正确显示旋转图像而不是ImageView在这里看:

                    myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
                    ExifInterface exif = new ExifInterface(selectedImagePath);
                    int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                    int rotationInDegrees = exifToDegrees(rotation);
                    deg = rotationInDegrees;
                    Matrix matrix = new Matrix();
                    if (rotation != 0f) {
                        matrix.preRotate(rotationInDegrees);
                        myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
                    }
Run Code Online (Sandbox Code Playgroud)

你需要这个:

private 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;    
} 
Run Code Online (Sandbox Code Playgroud)


Rah*_*tri 8

科特林代码:

if (file.exists()){
    val bitmap = BitmapFactory.decodeFile(file.absolutePath)

    val exif = ExifInterface(file.absoluteFile.toString())
    val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
    val matrix = Matrix()

    when(orientation){
        ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
        ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
        ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
    }

    val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
    bitmap.recycle()
    iv_capture.setImageBitmap(rotatedBitmap)
}
Run Code Online (Sandbox Code Playgroud)


Geo*_*ges 5

经过多次尝试得到了它,感谢我找不到的帖子:-(

Exif似乎总是工作,困难在于获取文件路径.我发现的代码在早于4.4和4.4之后的API之间有所不同.基本上4.4+的图片URI包含"com.android.providers".对于这种类型的URI,代码使用DocumentsContract获取图片ID,然后使用ContentResolver运行查询,而对于较旧的SDK,代码直接使用ContentResolver查询URI.

这是代码(对不起,我不能相信谁发布了它):

/**
 * 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);
        }
}
Run Code Online (Sandbox Code Playgroud)