Android:三星设备自动旋转图像
Posted
技术标签:
【中文标题】Android:三星设备自动旋转图像【英文标题】:Android: Samsung devices rotates the image automatically 【发布时间】:2018-05-26 11:40:19 【问题描述】:我创建了一个自定义相机。当我单击应用程序中的捕获按钮时,图像已被拍摄。此外,我在名为 onPictureTaken 的函数中以字节数组的形式获取数据。
我正在使用名为 Glide 的库将字节数组转换为位图。
我的问题是在三星设备中图像会自行旋转。我已经研究了很长时间。我找到了一个名为元数据提取库的库,用于从 byte[] 获取 Exif 信息并在其上旋转图像,但它不适用于三星设备。 元数据提取库每次都会返回一个值为 1 的肖像图像,这表明图像不需要旋转,但在肖像模式下拍摄的图像总是旋转 90 度。
每当以纵向模式拍摄照片时,前后摄像头都会旋转 90 度角,元提取库显示的值为 1。
除了元数据提取提取库之外,还有其他提取Exif信息流数据的东西吗?
注意: 我不能使用 ExifInterface,因为它要求最低 Api 级别为 24,而我正在测试 API 级别 22
我尝试了很多解决方案,但没有任何效果。有什么解决办法吗?
代码如下:
public void onPictureTaken(byte[] data, Camera camera)
mCamera.stopPreview();
Glide.with(this).load(data)
.asBitmap().centerCrop().animate(R.anim.abc_fade_in)
.into(new SimpleTarget<Bitmap>(width, height)
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation)
camera_view.setVisibility(View.INVISIBLE);
int w = resource.getWidth();
int h = resource.getHeight();
// Setting post rotate to 90
Matrix mtx = new Matrix();
try
InputStream is = new ByteArrayInputStream(data);
Metadata metadata = ImageMetadataReader.readMetadata(is);
final ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION))
final int exifOrientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
switch (exifOrientation)
case 6:
mtx.postRotate(90);
break; // top left
case 3:
mtx.postRotate(180);;
break; // top right
case 8:
mtx.postRotate(270);
break; // bottom right
photo = Bitmap.createBitmap(resource, 0, 0, w, h, mtx, true);
/* Work on exifOrientation */
catch (Exception e)
e.printStackTrace();
我正在使用三星 J5 进行测试。
【问题讨论】:
从我所看到的实际问题是ExifIFD0Directory
实际上并不存在于来自三星设备的元数据中。但是,我目前正在使用一个 Cordova 插件,该插件能够修复来自三星设备的图像的方向。以下是源链接:github.com/apache/cordova-plugin-camera/blob/master/src/android/…
【参考方案1】:
您不需要为此使用库。这是我写的几个方法,应该可以为您解决问题。
public static int getCapturedImageOrientation(Context context, Uri imageUri)
int rotate = 0;
try
context.getContentResolver().notifyChange(imageUri, null);
File imageFile = new File(imageUri.getPath());
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation)
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
Log.i("RotateImage", "Exif orientation: " + orientation);
Log.i("RotateImage", "Rotate value: " + rotate);
catch (Exception e)
Log.e(TAG, "Error getting rotation of image");
return rotate;
public static int GetRotateAngle(Context context, Uri imageUri)
String[] columns = MediaStore.Images.Media.DATA, MediaStore.Images.Media.ORIENTATION ;
Cursor cursor = context.getContentResolver().query(imageUri, columns, null, null, null);
if (cursor == null)
//If null, it is not in the gallery, so may be temporary image
return getCapturedImageOrientation(context, imageUri);
cursor.moveToFirst();
int orientationColumnIndex = cursor.getColumnIndex(columns[1]);
int orientation = cursor.getInt(orientationColumnIndex);
cursor.close();
return orientation;
我将它们包装在一个名为 ImageHelper 的类中。你可以这样使用它:
rotateImage(ImageHelper.GetRotateAngle(Context, mCropImageUri));
那么,rotateImage 代码当然是:
private void rotateImage(int degrees)
Matrix mat = new Matrix();
mat.postRotate(degrees);
mCropImage = Bitmap.createBitmap(mCropImage, 0, 0, mCropImage.getWidth(), mCropImage.getHeight(), mat, true);
setImageForCropping(mCropImage);
当然,我所做的一切都是为了一个照片编辑、裁剪和缩放应用程序,所以你可以忽略一些额外的东西,但这应该会照顾好你。祝你好运。
【讨论】:
谢谢。第一眼之后,我有一个问题,我将在哪里获得图像 URI?我没有将它存储到任何媒体文件中 没关系,然后跳过那段代码。注意代码说如果“cursor==null”然后调用getCapturedImageOrientation,这是当你没有将它存储在设备上的媒体存储中时。而且您已经找到了另一种获取不涉及使用文件绝对路径的 ExifInterface 的方法,因此您拥有所需的一切,只需尝试修复您的代码以匹配我提供的 getOrientation exif 处理。我不知道您的幻数是 3,6 和 8。我无法清楚地发现您的问题,但我提供的上述代码适用于在数百台设备上测试的每台设备 好的,谢谢,我会测试一下 好的,谢谢,我会测试它,但你的功能似乎和我的一样,我的功能不起作用。神奇的数字 3,6 和 8 显示了您在 switch 语句中的相同内容 哦,我刚看到你的笔记,你不能使用Exifinterface?那是在第 5 级中添加的,那为什么您不能使用它呢? developer.android.com/reference/android/media/…【参考方案2】:几乎在所有三星设备中,图像旋转问题都很常见,在我的情况下,我使用的是三星 Note 3,并且发生了同样的问题,但我使用下面的代码来解决这个问题
public static Bitmap decodeFile(String path) // this method is for avoiding the image rotation
int orientation;
try
if (path == null)
return null;
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 4;
while (true)
if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("orientation", "" + orientation);
Matrix m = new Matrix();
if ((orientation == 3))
m.postRotate(180);
m.postScale((float) bm.getWidth(), (float) bm.getHeight());
// if(m.preRotate(90))
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
else if (orientation == 6)
m.postRotate(90);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
else if (orientation == 8)
m.postRotate(270);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), m, true);
return bitmap;
return bitmap;
catch (Exception e)
return null;
这段代码对我有用,所以我希望这对你有帮助
【讨论】:
【参考方案3】:使用 Google 提供的 ExifInterface 可以轻松解决此问题。 您可以按如下方式将其添加到您的项目中:
implementation "androidx.exifinterface:exifinterface:1.1.0"
在此之后,从图像中获取旋转并将其应用到 ImageView:
// uri of the image
val inputStream = contentResolver.openInputStream(Uri.parse(uri))
val exifInterface = ExifInterface(requireNotNull(inputStream))
var rotation = 0
when (exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL))
ExifInterface.ORIENTATION_ROTATE_90 -> rotation = 90
ExifInterface.ORIENTATION_ROTATE_180 -> rotation = 180
ExifInterface.ORIENTATION_ROTATE_270 -> rotation = 270
【讨论】:
这种方法适用于三星设备;最简单和最简单的。 [请注意,自发布此答案以来,Google 已经更新了 exifinterface 依赖项的版本。]以上是关于Android:三星设备自动旋转图像的主要内容,如果未能解决你的问题,请参考以下文章