为什么使用相机意图拍摄的图像在Android上的某些设备上旋转?

我正在捕捉图像并将其设置为图像视图。

public void captureImage() { Intent intentCamera = new Intent("android.media.action.IMAGE_CAPTURE"); File filePhoto = new File(Environment.getExternalStorageDirectory(), "Pic.jpg"); imageUri = Uri.fromFile(filePhoto); MyApplicationGlobal.imageUri = imageUri.getPath(); intentCamera.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intentCamera, TAKE_PICTURE); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intentFromCamera) { super.onActivityResult(requestCode, resultCode, intentFromCamera); if (resultCode == RESULT_OK && requestCode == TAKE_PICTURE) { if (intentFromCamera != null) { Bundle extras = intentFromCamera.getExtras(); if (extras.containsKey("data")) { bitmap = (Bitmap) extras.get("data"); } else { bitmap = getBitmapFromUri(); } } else { bitmap = getBitmapFromUri(); } // imageView.setImageBitmap(bitmap); imageView.setImageURI(imageUri); } else { } } public Bitmap getBitmapFromUri() { getContentResolver().notifyChange(imageUri, null); ContentResolver cr = getContentResolver(); Bitmap bitmap; try { bitmap = android.provider.MediaStore.Images.Media.getBitmap(cr, imageUri); return bitmap; } catch (Exception e) { e.printStackTrace(); return null; } } 

但问题是,每次旋转时,某些设备上的图像。 例如,在三星设备上效果不错,但在索尼Xperia上 ,图像旋转了90度, 东芝茁壮成长 (平板电脑)旋转了180度。

大多数手机相机都是风景,这意味着如果您以纵向拍摄照片,所拍摄的照片将会旋转90度。 在这种情况下,相机软件应该以照片应该被浏览的方向填充Exif数据。

请注意,下面的解决scheme取决于相机软件/设备制造商填充Exif数据,所以它将在大多数情况下工作,但它不是一个100%可靠的解决scheme。

 ExifInterface ei = new ExifInterface(photoPath); int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); Bitmap rotatedBitmap = null; switch(orientation) { case ExifInterface.ORIENTATION_ROTATE_90: rotatedBitmap = rotateImage(bitmap, 90); break; case ExifInterface.ORIENTATION_ROTATE_180: rotatedBitmap = rotateImage(bitmap, 180); break; case ExifInterface.ORIENTATION_ROTATE_270: rotatedBitmap = rotateImage(bitmap, 270); break; case ExifInterface.ORIENTATION_NORMAL: default: rotatedBitmap = bitmap; } 

这里是rotateImage方法:

 public static Bitmap rotateImage(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } 

通过结合Jason Robinson的答案和Felix的答案,并填补缺less的部分, 这里是这个问题的最终完整的解决scheme ,将在Android的Android 4.1 ( 果冻豆 ), Android 4.4 ( KitKat )和Android 5.0 ( 棒棒糖 )。

脚步

  1. 如果图像大于1024×1024,则缩小图像。

  2. 只有当旋转90度,180度或270度时, 才能将图像旋转到正确的方向。

  3. 为了记忆目的回收旋转的图像。

这里是代码部分:

使用当前Context和要修复的图像URI调用以下方法

 /** * This method is responsible for solving the rotation issue if exist. Also scale the images to * 1024x1024 resolution * * @param context The current context * @param selectedImage The Image URI * @return Bitmap image results * @throws IOException */ public static Bitmap handleSamplingAndRotationBitmap(Context context, Uri selectedImage) throws IOException { int MAX_HEIGHT = 1024; int MAX_WIDTH = 1024; // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream imageStream = context.getContentResolver().openInputStream(selectedImage); BitmapFactory.decodeStream(imageStream, null, options); imageStream.close(); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; imageStream = context.getContentResolver().openInputStream(selectedImage); Bitmap img = BitmapFactory.decodeStream(imageStream, null, options); img = rotateImageIfRequired(context, img, selectedImage); return img; } 

这里是前面提到的来源的CalculateInSampleSize方法:

 /** * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates * the closest inSampleSize that will result in the final decoded bitmap having a width and * height equal to or larger than the requested width and height. This implementation does not * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but * results in a larger bitmap which isn't as useful for caching purposes. * * @param options An options object with out* params already populated (run through a decode* * method with inJustDecodeBounds==true * @param reqWidth The requested width of the resulting bitmap * @param reqHeight The requested height of the resulting bitmap * @return The value to be used for inSampleSize */ private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // Calculate ratios of height and width to requested height and width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will guarantee a final image // with both dimensions larger than or equal to the requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; // This offers some additional logic in case the image has a strange // aspect ratio. For example, a panorama may have a much larger // width than height. In these cases the total pixels might still // end up being too large to fit comfortably in memory, so we should // be more aggressive with sample down the image (=larger inSampleSize). final float totalPixels = width * height; // Anything more than 2x the requested pixels we'll sample down further final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } } return inSampleSize; } 

然后来检查当前图像方向来决定旋转angular度的方法

  /** * Rotate an image if required. * * @param img The image bitmap * @param selectedImage Image URI * @return The resulted Bitmap after manipulation */ private static Bitmap rotateImageIfRequired(Context context, Bitmap img, Uri selectedImage) throws IOException { InputStream input = context.getContentResolver().openInputStream(selectedImage); ExifInterface ei; if (Build.VERSION.SDK_INT > 23) ei = new ExifInterface(input); else ei = new ExifInterface(selectedImage.getPath()); int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: return rotateImage(img, 90); case ExifInterface.ORIENTATION_ROTATE_180: return rotateImage(img, 180); case ExifInterface.ORIENTATION_ROTATE_270: return rotateImage(img, 270); default: return img; } } 

最后是旋转方法本身

 private static Bitmap rotateImage(Bitmap img, int degree) { Matrix matrix = new Matrix(); matrix.postRotate(degree); Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true); img.recycle(); return rotatedImg; } 

– 不要忘了投票给那些家伙的答案和Shirish Herwade谁问这个有帮助的问题。

很容易检测图像的方向,并使用以下代码replace位图:

  /** * Rotate an image if required. * @param img * @param selectedImage * @return */ private static Bitmap rotateImageIfRequired(Context context,Bitmap img, Uri selectedImage) { // Detect rotation int rotation = getRotation(context, selectedImage); if (rotation != 0) { Matrix matrix = new Matrix(); matrix.postRotate(rotation); Bitmap rotatedImg = Bitmap.createBitmap(img, 0, 0, img.getWidth(), img.getHeight(), matrix, true); img.recycle(); return rotatedImg; } else{ return img; } } /** * Get the rotation of the last image added. * @param context * @param selectedImage * @return */ private static int getRotation(Context context,Uri selectedImage) { int rotation = 0; ContentResolver content = context.getContentResolver(); Cursor mediaCursor = content.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[] { "orientation", "date_added" }, null, null, "date_added desc"); if (mediaCursor != null && mediaCursor.getCount() != 0) { while(mediaCursor.moveToNext()){ rotation = mediaCursor.getInt(0); break; } } mediaCursor.close(); return rotation; } 

为了避免出现大图片的记忆,我build议您使用以下命令重新缩放图像:

 private static final int MAX_HEIGHT = 1024; private static final int MAX_WIDTH = 1024; public static Bitmap decodeSampledBitmap(Context context, Uri selectedImage) throws IOException { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; InputStream imageStream = context.getContentResolver().openInputStream(selectedImage); BitmapFactory.decodeStream(imageStream, null, options); imageStream.close(); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, MAX_WIDTH, MAX_HEIGHT); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; imageStream = context.getContentResolver().openInputStream(selectedImage); Bitmap img = BitmapFactory.decodeStream(imageStream, null, options); img = rotateImageIfRequired(img, selectedImage); return img; } 

由于Android操作系统问题,使用ExifInterface获取方向是不正确的: https : //code.google.com/p/android/issues/detail? id = 19268

这里是calculateInSampleSize

 /** * Calculate an inSampleSize for use in a {@link BitmapFactory.Options} object when decoding * bitmaps using the decode* methods from {@link BitmapFactory}. This implementation calculates * the closest inSampleSize that will result in the final decoded bitmap having a width and * height equal to or larger than the requested width and height. This implementation does not * ensure a power of 2 is returned for inSampleSize which can be faster when decoding but * results in a larger bitmap which isn't as useful for caching purposes. * * @param options An options object with out* params already populated (run through a decode* * method with inJustDecodeBounds==true * @param reqWidth The requested width of the resulting bitmap * @param reqHeight The requested height of the resulting bitmap * @return The value to be used for inSampleSize */ public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // Calculate ratios of height and width to requested height and width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will guarantee a final image // with both dimensions larger than or equal to the requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; // This offers some additional logic in case the image has a strange // aspect ratio. For example, a panorama may have a much larger // width than height. In these cases the total pixels might still // end up being too large to fit comfortably in memory, so we should // be more aggressive with sample down the image (=larger inSampleSize). final float totalPixels = width * height; // Anything more than 2x the requested pixels we'll sample down further final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } } return inSampleSize; } 

一行解决scheme:

 Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView); 

要么

 Picasso.with(context).load("file:" + photoPath).into(imageView); 

这将自动检测旋转并以正确的方向放置图像

毕加索是一个非常强大的图书馆处理您的应用程序中的图像包括: 复杂的图像转换与最小的内存使用。

 // Try this way,hope this will help you to solve your problem... 

activity_main.xml中

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center"> <ImageView android:id="@+id/imgFromCameraOrGallery" android:layout_width="wrap_content" android:layout_height="wrap_content" android:adjustViewBounds="true" android:src="@drawable/ic_launcher"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:id="@+id/btnCamera" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="Camera"/> <Button android:id="@+id/btnGallery" android:layout_width="0dp" android:layout_weight="1" android:layout_marginLeft="5dp" android:layout_height="wrap_content" android:text="Gallery"/> </LinearLayout> </LinearLayout> 

MainActivity.java

  public class MainActivity extends Activity { private ImageView imgFromCameraOrGallery; private Button btnCamera; private Button btnGallery; private String imgPath; final private int PICK_IMAGE = 1; final private int CAPTURE_IMAGE = 2; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imgFromCameraOrGallery = (ImageView) findViewById(R.id.imgFromCameraOrGallery); btnCamera = (Button) findViewById(R.id.btnCamera); btnGallery = (Button) findViewById(R.id.btnGallery); btnCamera.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, setImageUri()); startActivityForResult(intent, CAPTURE_IMAGE); } }); btnGallery.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, ""), PICK_IMAGE); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK) { if (requestCode == CAPTURE_IMAGE) { setCapturedImage(getImagePath()); } else if (requestCode == PICK_IMAGE) { imgFromCameraOrGallery.setImageBitmap(BitmapFactory.decodeFile(getAbsolutePath(data.getData()))); } } } private String getRightAngleImage(String photoPath) { try { ExifInterface ei = new ExifInterface(photoPath); int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); int degree = 0; switch (orientation) { case ExifInterface.ORIENTATION_NORMAL: degree = 0; break; case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; case ExifInterface.ORIENTATION_UNDEFINED: degree = 0; break; default: degree = 90; } return rotateImage(degree,photoPath); } catch (Exception e) { e.printStackTrace(); } return photoPath; } private String rotateImage(int degree, String imagePath){ if(degree<=0){ return imagePath; } try{ Bitmap b= BitmapFactory.decodeFile(imagePath); Matrix matrix = new Matrix(); if(b.getWidth()>b.getHeight()){ matrix.setRotate(degree); b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true); } FileOutputStream fOut = new FileOutputStream(imagePath); String imageName = imagePath.substring(imagePath.lastIndexOf("/") + 1); String imageType = imageName.substring(imageName.lastIndexOf(".") + 1); FileOutputStream out = new FileOutputStream(imagePath); if (imageType.equalsIgnoreCase("png")) { b.compress(Bitmap.CompressFormat.PNG, 100, out); }else if (imageType.equalsIgnoreCase("jpeg")|| imageType.equalsIgnoreCase("jpg")) { b.compress(Bitmap.CompressFormat.JPEG, 100, out); } fOut.flush(); fOut.close(); b.recycle(); }catch (Exception e){ e.printStackTrace(); } return imagePath; } private void setCapturedImage(final String imagePath){ new AsyncTask<Void,Void,String>(){ @Override protected String doInBackground(Void... params) { try { return getRightAngleImage(imagePath); }catch (Throwable e){ e.printStackTrace(); } return imagePath; } @Override protected void onPostExecute(String imagePath) { super.onPostExecute(imagePath); imgFromCameraOrGallery.setImageBitmap(decodeFile(imagePath)); } }.execute(); } public Bitmap decodeFile(String path) { try { // Decode deal_image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, o); // The new size we want to scale to final int REQUIRED_SIZE = 1024; // Find the correct scale value. It should be the power of 2. int scale = 1; while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE) scale *= 2; // Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; return BitmapFactory.decodeFile(path, o2); } catch (Throwable e) { e.printStackTrace(); } return null; } public String getAbsolutePath(Uri uri) { if(Build.VERSION.SDK_INT >= 19){ String id = ""; if(uri.getLastPathSegment().split(":").length > 1) id = uri.getLastPathSegment().split(":")[1]; else if(uri.getLastPathSegment().split(":").length > 0) id = uri.getLastPathSegment().split(":")[0]; if(id.length() > 0){ final String[] imageColumns = {MediaStore.Images.Media.DATA }; final String imageOrderBy = null; Uri tempUri = getUri(); Cursor imageCursor = getContentResolver().query(tempUri, imageColumns, MediaStore.Images.Media._ID + "=" + id, null, imageOrderBy); if (imageCursor.moveToFirst()) { return imageCursor.getString(imageCursor.getColumnIndex(MediaStore.Images.Media.DATA)); }else{ return null; } }else{ return null; } }else{ String[] projection = { MediaStore.MediaColumns.DATA }; Cursor cursor = getContentResolver().query(uri, projection, null, null, null); if (cursor != null) { int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA); cursor.moveToFirst(); return cursor.getString(column_index); } else return null; } } private Uri getUri() { String state = Environment.getExternalStorageState(); if(!state.equalsIgnoreCase(Environment.MEDIA_MOUNTED)) return MediaStore.Images.Media.INTERNAL_CONTENT_URI; return MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } public Uri setImageUri() { Uri imgUri; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { File file = new File(Environment.getExternalStorageDirectory() + "/DCIM/",getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis() + ".png"); imgUri = Uri.fromFile(file); imgPath = file.getAbsolutePath(); }else { File file = new File(getFilesDir() ,getString(R.string.app_name) + Calendar.getInstance().getTimeInMillis()+ ".png"); imgUri = Uri.fromFile(file); this.imgPath = file.getAbsolutePath(); } return imgUri; } public String getImagePath() { return imgPath; } } 

通常build议使用ExifInterface来解决问题,就像@Jason Robinson所build议的那样。 如果这种方法不起作用,您可以尝试查看所拍摄的最新图像的方向 。

 private int getImageOrientation(){ final String[] imageColumns = { MediaStore.Images.Media._ID, MediaStore.Images.ImageColumns.ORIENTATION }; final String imageOrderBy = MediaStore.Images.Media._ID+" DESC"; Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageColumns, null, null, imageOrderBy); if(cursor.moveToFirst()){ int orientation = cursor.getInt(cursor.getColumnIndex(MediaStore.Images.ImageColumns.ORIENTATION)); cursor.close(); return orientation; } else { return 0; } } 

您可以在文档中阅读Google所示的相机传感器的方向: https//developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html

 SENSOR_ORIENTATION Added in API level 21 Key<Integer> SENSOR_ORIENTATION Clockwise angle through which the output image needs to be rotated to be upright on the device screen in its native orientation. Also defines the direction of rolling shutter readout, which is from top to bottom in the sensor's coordinate system. Units: Degrees of clockwise rotation; always a multiple of 90 Range of valid values: 0, 90, 180, 270 This key is available on all devices. 

示例代码:

 CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); int orientation = 0; try { String cameraId = manager.getCameraIdList()[0]; CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); } catch (Exception e) { } 

可悲的是,@ jason-robinson上面的回答并不适合我。

虽然旋转function完美地工作:

 public static Bitmap rotateImage(Bitmap source, float angle) { Matrix matrix = new Matrix(); matrix.postRotate(angle); return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true); } 

我不得不做下面的方向,因为Exif方向总是为0

 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode,resultCode,data); if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && data != null) { Uri selectedImage = data.getData(); String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION}; Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null); int orientation = -1; if (cur != null && cur.moveToFirst()) { orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0])); } InputStream imageStream = getContentResolver().openInputStream(selectedImage); Bitmap bitmap = BitmapFactory.decodeStream(imageStream); switch(orientation) { case 90: bitmap = rotateImage(chosen_image_bitmap, 90); break; case 180: bitmap = rotateImage(chosen_image_bitmap, 180); break; case 270: bitmap = rotateImage(chosen_image_bitmap, 270); break; default: break; } imageView.setImageBitmap(bitmap ); 

如果有人遇到与Android 4.4 (KitKat)上的ExifInterface问题,可能是因为从URI获得了错误的path 。 在Stack Overflow问题中查看propoer getPath的解决scheme从URI,Android KitKat新的存储访问框架获取真正的path

我花了很多时间寻找解决scheme。 最后设法做到这一点。 不要忘记提高@Jason Robinson的回答,因为我是基于他的。

所以首先,你知道,自从Android 7.0以来,我们不得不使用FileProvider和一些名为ContentUri东西,否则你会遇到一个恼人的错误,试图调用你的Intent 。 这是示例代码:

 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, getUriFromPath(context, "[Your path to save image]")); startActivityForResult(intent, CAPTURE_IMAGE_RESULT); 

方法getUriFromPath(Context, String)基于Android的用户版本创buildFileUri (file://...)ContentUri (content://...) ,它是:

 public Uri getUriFromPath(Context context, String destination) { File file = new File(destination); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", file); } else { return Uri.fromFile(file); } } 

onActivityResult之后,你可以捕捉到相机所保存的图像,但现在你必须检测相机的旋转,在这里我们将使用mod_Jason Robinson的答案:

首先,我们需要基于Uri创buildExifInterface

 @Nullable public ExifInterface getExifInterface(Context context, Uri uri) { try { String path = uri.toString(); if (path.startsWith("file://")) { return new ExifInterface(path); } if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (path.startsWith("content://")) { InputStream inputStream = context.getContentResolver().openInputStream(uri); return new ExifInterface(inputStream); } } } catch (IOException e) { e.printStackTrace(); } return null; } 

上面的代码可以简化,但我想显示的一切。 所以从FileUri我们可以创build基于String path ContentUri ,但是从ContentUri我们不能,Android不支持。

在这种情况下,我们必须使用基于InputStream其他构造函数。 记住这个构造函数默认是不可用的,你必须添加额外的库:

 compile "com.android.support:exifinterface:XX.XX" 

现在我们可以使用getExifInterface方法来获得我们的angular度:

 public float getExifAngle(Context context, Uri uri) { try { ExifInterface exifInterface = getExifInterface(context, uri); if(exifInterface == null) { return -1f; } int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: return 90f; case ExifInterface.ORIENTATION_ROTATE_180: return 180f; case ExifInterface.ORIENTATION_ROTATE_270: return 270f; case ExifInterface.ORIENTATION_NORMAL: return 0f; case ExifInterface.ORIENTATION_UNDEFINED: return -1f; default: return -1f; } } catch (Exception e) { e.printStackTrace(); return -1f; } } 

现在你有angular度正确旋转你的形象:)。

选定的答案使用最常见的方法回答这个和类似的问题。 但是,它不适用于三星的正面和背面相机。 对于那些寻找三星和其他主要制造商的正面和背面相机的解决scheme,nvhausid的这个答案是非常棒的:

https://stackoverflow.com/a/18915443/6080472

对于那些不想点击的人来说,相关的魔术就是使用CameraInfo而不是依靠EXIF。

 Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length); android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(mCurrentCameraId, info); Bitmap bitmap = rotate(realImage, info.orientation); 

完整的代码在链接中。

最好尝试以特定的方向拍摄照片。

 android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden" 

为了获得最佳效果,请在摄影机视图中指定横向。

这可能不用说,但请记住,您可以在服务器上处理这些image processing问题。 我使用了包含在这个线程中的响应来处理图像的即时显示。 然而,我的应用程序需要将图像存储在服务器上(如果您希望图像在用户切换手机时持续存在,则这可能是常见的要求)。

包含在许多关于这个主题的线程中的解决scheme并没有讨论缺乏EXIF数据的持久性,这些数据在Bitmap的图像压缩中没有生存,这意味着每次服务器加载时都需要旋转图像。 或者,您可以将EXIF方向数据发送到您的服务器,然后根据需要旋转图像。

我更容易在服务器上创build一个永久的解决scheme,因为我不必担心Android的秘密文件path。

有一个更简单的命令来解决这个错误。

只需在yourImageView.setBitmap(bitmap)后添加即可; 这yourImageView.setRotation(90);

这个固定的矿。 希望它有帮助!

如果您遇到S4问题,请尝试以下操作。

 android:configChanges="locale|touchscreen|orientation|screenLayout|screenSize|keyboardHidden|uiMode" 

这个问题的最简单的解决scheme:

 captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)); 

我正在保存图像的JPG格式。