Android从图库中获取图像会旋转
Posted
技术标签:
【中文标题】Android从图库中获取图像会旋转【英文标题】:Android getting an image from gallery comes rotated 【发布时间】:2015-11-02 17:32:19 【问题描述】:我试图让用户从图库中选择个人资料图片。我的问题是有些图片向右旋转。
我像这样启动图像选择器:
Intent photoPickerIntent = new Intent();
photoPickerIntent.setType("image/*");
photoPickerIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(photoPickerIntent, "Select profile picture"), Global.CODE_SELECT_PICTURE);
我像这样从 onActivityResult 获取图像:
Uri selectedPicture = data.getData();
profilePic = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), selectedPicture);
我怎样才能让图像不被旋转?
更新:
根据我收到的一些有用的答案,我设法提出了以下工作解决方案(这只是一个工作代码,写得不好)。我很想得到您关于如何改进它的反馈!
public void onActivityResult(int requestCode, int resultCode, Intent data)
if (resultCode == Activity.RESULT_OK && requestCode == Global.CODE_SELECT_PICTURE)
// Get selected gallery image
Uri selectedPicture = data.getData();
// Get and resize profile image
String[] filePathColumn = MediaStore.Images.Media.DATA;
Cursor cursor = activity.getContentResolver().query(selectedPicture, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Bitmap loadedBitmap = BitmapFactory.decodeFile(picturePath);
ExifInterface exif = null;
try
File pictureFile = new File(picturePath);
exif = new ExifInterface(pictureFile.getAbsolutePath());
catch (IOException e)
e.printStackTrace();
int orientation = ExifInterface.ORIENTATION_NORMAL;
if (exif != null)
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation)
case ExifInterface.ORIENTATION_ROTATE_90:
loadedBitmap = rotateBitmap(loadedBitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
loadedBitmap = rotateBitmap(loadedBitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
loadedBitmap = rotateBitmap(loadedBitmap, 270);
break;
public static Bitmap rotateBitmap(Bitmap bitmap, int degrees)
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
【问题讨论】:
您的解决方案是否适用于所有软件/设备?我也面临同样的问题... 谢谢。它就像一个魅力..下面的答案在我的情况下不起作用.. This 从 URI 中获取正确方向的位图 这不起作用我将图片文件清空 【参考方案1】:您可以使用ExifInterface 修改方向:
public static Bitmap modifyOrientation(Bitmap bitmap, String image_absolute_path) throws IOException
ExifInterface ei = new ExifInterface(image_absolute_path);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation)
case ExifInterface.ORIENTATION_ROTATE_90:
return rotate(bitmap, 90);
case ExifInterface.ORIENTATION_ROTATE_180:
return rotate(bitmap, 180);
case ExifInterface.ORIENTATION_ROTATE_270:
return rotate(bitmap, 270);
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
return flip(bitmap, true, false);
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
return flip(bitmap, false, true);
default:
return bitmap;
public static Bitmap rotate(Bitmap bitmap, float degrees)
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
public static Bitmap flip(Bitmap bitmap, boolean horizontal, boolean vertical)
Matrix matrix = new Matrix();
matrix.preScale(horizontal ? -1 : 1, vertical ? -1 : 1);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
要从它们的 uri 中获取图像的绝对路径,请检查 this answer
【讨论】:
我有 OutOfMemoryError 这个解决方案 你提到的从 uri 获取图像的绝对路径的答案是坏主意。一个人不应该那样做。请参阅 CommonsWare 对答案的评论。【参考方案2】:2 使用 Picasso 和 glide 库的一条线解决方案
在花了很多时间解决图像旋转问题后,我终于找到了两个简单的解决方案。我们不需要做任何额外的工作。
使用毕加索图书馆 https://github.com/square/picasso
Picasso.with(context).load("http url or sdcard url").into(imageView);
使用 glide 库 https://github.com/bumptech/glide
Glide.with(this).load("http url or sdcard url").into(imgageView);
Picasso 和 Glide 是一个非常强大的库,用于处理应用程序中包含的图像。它将读取图像 EXIF 数据并自动旋转图像。
【讨论】:
很好,不需要存储权限(ExifInterface
可以)
使用 Glide 获取位图:Glide.with(context).asBitmap().load(uri).into(new SimpleTarget<Bitmap>() @Override public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) /* now you have Bitmap resource */ );
从我的角度来看,如果图像被转换为位图,它就不起作用了。如果将 uri 直接传递给 Glide,它会有所帮助。感谢分享解决方案。【参考方案3】:
我使用这些静态方法。第一个确定方向,第二个根据需要旋转图像并缩小它。
public static int getOrientation(Context context, Uri photoUri)
Cursor cursor = context.getContentResolver().query(photoUri,
new String[] MediaStore.Images.ImageColumns.ORIENTATION , null, null, null);
if (cursor == null || cursor.getCount() != 1)
return 90; //Assuming it was taken portrait
cursor.moveToFirst();
return cursor.getInt(0);
/**
* Rotates and shrinks as needed
*/
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri, int maxWidth)
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)
Log.d("ImageUtil", "Will be rotated");
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
else
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
Log.d("ImageUtil", String.format("rotatedWidth=%s, rotatedHeight=%s, maxWidth=%s",
rotatedWidth, rotatedHeight, maxWidth));
if (rotatedWidth > maxWidth || rotatedHeight > maxWidth)
float widthRatio = ((float) rotatedWidth) / ((float) maxWidth);
float heightRatio = ((float) rotatedHeight) / ((float) maxWidth);
float maxRatio = Math.max(widthRatio, heightRatio);
Log.d("ImageUtil", String.format("Shrinking. maxRatio=%s",
maxRatio));
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
else
Log.d("ImageUtil", String.format("No need for Shrinking. maxRatio=%s",
1));
srcBitmap = BitmapFactory.decodeStream(is);
Log.d("ImageUtil", String.format("Decoded bitmap successful"));
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;
【讨论】:
您可能希望删除生产版本的 Log.d 调用。【参考方案4】:我是这样做的:
public void browseClick(View view)
view.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.button_animation));
Intent i = new Intent(
Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, RESULT_LOAD_IMAGE);
你最感兴趣的方向是检查的结果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data)
Uri selectedImage = data.getData();
String[] filePathColumn = MediaStore.Images.Media.DATA ;
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Bitmap loadedBitmap = BitmapFactory.decodeFile(picturePath);
Matrix matrix = new Matrix();
Bitmap scaledBitmap;
if (loadedBitmap.getWidth() >= loadedBitmap.getHeight())
matrix.setRectToRect(new RectF(0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight()), new RectF(0, 0, 400, 300), Matrix.ScaleToFit.CENTER);
scaledBitmap = Bitmap.createBitmap(loadedBitmap, 0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight(), matrix, true);
else
matrix.setRectToRect(new RectF(0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight()), new RectF(0, 0, 300, 400), Matrix.ScaleToFit.CENTER);
scaledBitmap = Bitmap.createBitmap(loadedBitmap, 0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight(), matrix, true);
File file = new File(getExternalCacheDir(), "image.jpg");
try
FileOutputStream out = new FileOutputStream(file);
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
catch (Exception e)
Log.e("Image", "Convert");
imageView.setImageBitmap(scaledBitmap);
【讨论】:
【参考方案5】:这是用 Kotlin 编写的 ExifInterface 方法:
fun modifyOrientation(bitmap: Bitmap, image_absolute_path: String): Bitmap
val ei = ExifInterface(image_absolute_path)
val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
return when (orientation)
ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(bitmap, 90f)
ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(bitmap, 180f)
ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(bitmap, 270f)
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> flipImage(bitmap, true, false)
ExifInterface.ORIENTATION_FLIP_VERTICAL -> flipImage(bitmap, false, true)
else -> bitmap
private fun rotateImage(bitmap: Bitmap, degrees: Float): Bitmap
val matrix = Matrix()
matrix.postRotate(degrees)
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
private fun flipImage(bitmap: Bitmap, horizontal: Boolean, vertical: Boolean): Bitmap
val matrix = Matrix()
matrix.preScale((if (horizontal) -1 else 1).toFloat(), (if (vertical) -1 else 1).toFloat())
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
【讨论】:
【参考方案6】:使用毕加索:
Picasso
.get()
.load("Your image path")
.into(imageView);
Picasso.with(this) 现在替换为 Picasso.get()
毕加索图书馆:https://github.com/square/picasso
在 build.gradle 文件中添加:implementation 'com.squareup.picasso:picasso:2.71828'
。
Picasso 将负责图像自动旋转。
【讨论】:
以上是关于Android从图库中获取图像会旋转的主要内容,如果未能解决你的问题,请参考以下文章
Android:从图库加载的位图在 ImageView 中旋转