Android:从图库加载的位图在 ImageView 中旋转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3647993/
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
Android: Bitmaps loaded from gallery are rotated in ImageView
提问by Manuel
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?
当我将媒体库中的图像加载到位图中时,一切正常,除了垂直拿着手机用相机拍摄的图片被旋转,这样我总是得到一张水平图片,即使它在画廊。为什么会这样,我如何才能正确加载它?
采纳答案by James
Have you looked at the EXIF data of the images? It may know the orientation of the camera when the picture was taken.
你看过图片的EXIF数据吗?它可能知道拍摄照片时相机的方向。
回答by Manuel
So, as an example...
所以,举个例子...
First you need to create an ExifInterface:
首先,您需要创建一个 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
以下是方向值的含义: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:
因此,最重要的值是 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);
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.
不过,这只是一个简单的例子。我确定还有其他方法可以执行实际轮换。但是你也会在 StackOverflow 上找到它们。
回答by Timmmm
This is a full solution (found in the Hackbook example from the Facebook SDK). It has the advantage of not needing access to the file itself. This is extremely useful if you are loading an image from the content resolver thingy (e.g. if your app is responding to a share-photo intent).
这是一个完整的解决方案(可在 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);
}
And then you can get a rotated Bitmap as follows. This code also scales down the image (badly unfortunately) to MAX_IMAGE_DIMENSION. Otherwise you may run out of memory.
然后你可以得到一个旋转的位图,如下所示。此代码还将图像(非常不幸)缩小到 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;
}
回答by Teo Inke
Solved it in my case with this code using help of this post:
在我的情况下,使用这篇文章的帮助使用此代码解决了这个问题:
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);
Hope it saves someone's time!
希望它可以节省某人的时间!
回答by Joshua Pinter
Use a Utility to do the Heavy Lifting.
使用实用程序进行重物提升。
9recreated a simple utility to handle the heavy lifting of dealing with EXIF data and rotating images to their correct orientation.
9re创建了一个简单的实用程序来处理处理 EXIF 数据和将图像旋转到正确方向的繁重工作。
You can find the utility code here: https://gist.github.com/9re/1990019
您可以在此处找到实用程序代码: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:
只需下载它,将其添加到您的项目src
目录并使用ExifUtil.rotateBitmap()
以获得正确的方向,如下所示:
String imagePath = photoFile.getAbsolutePath(); // photoFile is a File class.
Bitmap myBitmap = BitmapFactory.decodeFile(imagePath);
Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
回答by farhad.kargaran
its because gallery correct displaying rotated images but not ImageView look at here:
这是因为画廊正确显示旋转图像但不是 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);
}
and you need this:
你需要这个:
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;
}
回答by Georges
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.
Exif 似乎总是有效,难点在于获取文件路径。我发现的代码在 4.4 之前和 4.4 之后的 API 之间有所不同。基本上 4.4+ 的图片 URI 包含“com.android.providers”。对于这种类型的 URI,代码使用 DocumentsContract 获取图片 id,然后使用 ContentResolver 运行查询,而对于较旧的 SDK,代码直接使用 ContentResolver 查询 URI。
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);
}
}
回答by Mayank Saini
You can just read the path from sd card and do the following code...it'll Replace the existing photo after rotating it..
您可以从 sd 卡读取路径并执行以下代码...它会在旋转后替换现有照片..
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.
不是:Exif 不适用于大多数设备,它提供了错误的数据,因此在保存到您想要的任何角度之前对旋转进行硬编码是很好的,您只需要将 postRotate 中的角度值更改为您想要的任何值。
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();
}
}
回答by Gal Rom
The first thing you need is the real File path If you have it great, if you are using URI then use this method to get the real Path:
您需要的第一件事是真正的文件路径如果您拥有它,如果您使用的是 URI,则使用此方法获取真正的路径:
public static String getRealPathFromURI(Uri contentURI,Context context) {
String path= contentURI.getPath();
try {
Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
catch(Exception e)
{
return path;
}
return path;
}
extract your Bitmap for example:
提取您的位图,例如:
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
Log.e("IOException",e.toString());
}
you can use decodeFile() instead if you wish.
如果您愿意,您可以改用 decodeFile()。
Now that you have the Bitmap and the real Path get the Orientation of the Image:
现在你有了位图,真实的路径得到了图像的方向:
private static int getExifOrientation(String src) throws IOException {
int orientation = 1;
ExifInterface exif = new ExifInterface(src);
String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
try {
orientation = Integer.parseInt(orientationString);
}
catch(NumberFormatException e){}
return orientation;
}
and finally rotate it to the right position like so:
最后将其旋转到正确的位置,如下所示:
public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
try {
int orientation = getExifOrientation(src);
if (orientation == 1) {
return bitmap;
}
Matrix matrix = new Matrix();
switch (orientation) {
case 2:
matrix.setScale(-1, 1);
break;
case 3:
matrix.setRotate(180);
break;
case 4:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case 5:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case 6:
matrix.setRotate(90);
break;
case 7:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case 8:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try {
Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return oriented;
} catch (OutOfMemoryError e) {
e.printStackTrace();
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
That's it , you now have the bitmap rotated to the right position.
就是这样,您现在已将位图旋转到正确的位置。
cheers.
干杯。
回答by user2820531
I improved upon the answer by Teo Inke. It no longer rotates the image unless it is actually necessary. It is also easier to read, and should run faster.
我改进了 Teo Inke 的回答。除非确实有必要,否则它不再旋转图像。它也更容易阅读,并且应该运行得更快。
// Load Image
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
// Rotate Image if Needed
try
{
// Determine Orientation
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
// Determine Rotation
int rotation = 0;
if (orientation == 6) rotation = 90;
else if (orientation == 3) rotation = 180;
else if (orientation == 8) rotation = 270;
// Rotate Image if Necessary
if (rotation != 0)
{
// Create Matrix
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
// Rotate Bitmap
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Pretend none of this ever happened!
bitmap.recycle();
bitmap = rotated;
rotated = null;
}
}
catch (Exception e)
{
// TODO: Log Error Messages Here
}
// TODO: Use Result Here
xxx.setBitmap(bitmap);