控制相机以纵向拍摄照片不会旋转最终的图像

我试图控制Android相机在肖像应用程序中拍照,但是当我保存图片时,它处于横向模式。 我用setCameraDisplayOrientation()方法旋转了90个图像的等级,但是不起作用。

然后我发现这个post,但TAG_ORIENTATION0 (未定义)。 如果我抓住这个值并应用旋转值,也不起作用。

如何以肖像拍照并保存好照片?

  /** Initializes the back/front camera */ private boolean initPhotoCamera() { try { camera = getCameraInstance(selected_camera); Camera.Parameters parameters = camera.getParameters(); // parameters.setPreviewSize(width_video, height_video); // parameters.set("orientation", "portrait"); // parameters.set("rotation", 1); // camera.setParameters(parameters); checkCameraFlash(parameters); // camera.setDisplayOrientation( 0); setCameraDisplayOrientation(selected_camera, camera); surface_view.getHolder().setFixedSize(width_video, height_video); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width_video, height_video); surface_view.setLayoutParams(lp); camera.lock(); surface_holder = surface_view.getHolder(); surface_holder.addCallback(this); surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); setPreviewCamera(); } catch (Exception e) { Log.v("RecordVideo", "Could not initialize the Camera"); return false; } return true; } public void setCameraDisplayOrientation(int cameraId, Camera camera) { Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } camera.setDisplayOrientation(result); } public static Bitmap rotate(Bitmap bitmap, int degree) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix mtx = new Matrix(); // mtx.postRotate(degree); mtx.setRotate(degree); return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } @Override public void onPictureTaken(byte[] data, Camera camera) { String timeStamp = Calendar.getInstance().getTime().toString(); output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg"; File pictureFile = new File(output_file_name); if (pictureFile.exists()) { pictureFile.delete(); } try { FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(data); Bitmap realImage = BitmapFactory.decodeFile(output_file_name); ExifInterface exif=new ExifInterface(pictureFile.toString()); Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION)); if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){ realImage= rotate(realImage, 90); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){ realImage= rotate(realImage, 270); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){ realImage= rotate(realImage, 180); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){ realImage= rotate(realImage, 45); } boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.close(); Log.d("Info", bo + ""); } catch (FileNotFoundException e) { Log.d("Info", "File not found: " + e.getMessage()); } catch (IOException e) { Log.d("TAG", "Error accessing file: " + e.getMessage()); } } 

setCameraDisplayOrientation()方法允许您更改预览的显示方式, 而不会影响图像的logging方式( 源 )。

为了更改实际logging的图像,您需要设置摄像机旋转参数。 你这样做:

 //STEP #1: Get rotation degrees Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info); int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; //Natural orientation case Surface.ROTATION_90: degrees = 90; break; //Landscape left case Surface.ROTATION_180: degrees = 180; break;//Upside down case Surface.ROTATION_270: degrees = 270; break;//Landscape right } int rotate = (info.orientation - degrees + 360) % 360; //STEP #2: Set the 'rotation' parameter Camera.Parameters params = mCamera.getParameters(); params.setRotation(rotate); mCamera.setParameters(params); 

您的解决scheme是一种解决方法,因为您已经logging后修改图像。 这个解决scheme更清晰,在保存图像之前不需要所有这些'if'语句。

问题是,当我保存了我没有做好的形象。

 @Override public void onPictureTaken(byte[] data, Camera camera) { String timeStamp = new SimpleDateFormat( "yyyyMMdd_HHmmss").format( new Date( )); output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg"; File pictureFile = new File(output_file_name); if (pictureFile.exists()) { pictureFile.delete(); } try { FileOutputStream fos = new FileOutputStream(pictureFile); Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length); ExifInterface exif=new ExifInterface(pictureFile.toString()); Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION)); if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){ realImage= rotate(realImage, 90); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){ realImage= rotate(realImage, 270); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){ realImage= rotate(realImage, 180); } else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){ realImage= rotate(realImage, 90); } boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.close(); ((ImageView) findViewById(R.id.imageview)).setImageBitmap(realImage); Log.d("Info", bo + ""); } catch (FileNotFoundException e) { Log.d("Info", "File not found: " + e.getMessage()); } catch (IOException e) { Log.d("TAG", "Error accessing file: " + e.getMessage()); } } public static Bitmap rotate(Bitmap bitmap, int degree) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix mtx = new Matrix(); // mtx.postRotate(degree); mtx.setRotate(degree); return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } 

使用前置摄像头时,可以使用以下方法正确生成预览。

此代码将进入您的相机预览的surfaceChanged方法

 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { int angleToRotate=CommonMethods.getRoatationAngle(mActivity, Camera.CameraInfo.CAMERA_FACING_FRONT); mCamera.setDisplayOrientation(angleToRotate); } 

这段代码可以放在一个静态类中

  /** * Get Rotation Angle * * @param mContext * @param cameraId * probably front cam * @return angel to rotate */ public static int getRoatationAngle(Activity mContext, int cameraId) { android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(cameraId, info); int rotation = mContext.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } return result; } 

您可以用这种方式旋转图像。这仅在拍摄图像时使用,我们将要保存图像

 public static Bitmap rotate(Bitmap bitmap, int degree) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix mtx = new Matrix(); mtx.postRotate(degree); return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } 

将用于拍照的方法

  @Override public void onPictureTaken(byte[] data, Camera camera) { int angleToRotate = getRoatationAngle(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_FRONT); // Solve image inverting problem angleToRotate = angleToRotate + 180; Bitmap orignalImage = BitmapFactory.decodeByteArray(data, 0, data.length); Bitmap bitmapImage = rotate(orignalImage, angleToRotate); } 

bitmapImage包含正确的图像。

这一个应该工作,ExifInterface不适用于所有的制造商,所以使用CameraInfo来代替,只要让相机捕捉图像的默认旋转,然后旋转结果数据PictureCallback

 private PictureCallback mPicture = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { File dir = new File(Constant.SDCARD_CACHE_PREFIX); if (!dir.exists()) { dir.mkdirs(); } File pictureFile = new File(Constant.SDCARD_TAKE_PHOTO_CACHE_PREFIX); try { 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); FileOutputStream fos = new FileOutputStream(pictureFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.close(); } catch (FileNotFoundException e) { Log.d(TAG, "File not found: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error accessing file: " + e.getMessage()); } resultFileUri = Uri.fromFile(pictureFile); startEffectFragment(); } }; public static Bitmap rotate(Bitmap bitmap, int degree) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix mtx = new Matrix(); mtx.postRotate(degree); return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } 

我find了强大的答案,我只是遇到同样的问题,解决它而不保存文件。解决scheme是注册一个OrientationEventListener获取方向,只要它改变。 http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html这里给出details.My代码如下:;

 private CameraOrientationListener myOrientationListener; private int rotation; protected void onCreate(Bundle savedInstanceState) { setListeners(); rotation = setCameraDisplayOrientation(CameraActivity.this, Camera.getNumberOfCameras()-1, mCamera); } public void setListeners(){ myOrientationListener = new CameraOrientationListener(this); if(myOrientationListener.canDetectOrientation()) myOrientationListener.enable(); } public static int setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(cameraId, info); int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } int result; if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { result = (info.orientation + degrees) % 360; result = (360 - result) % 360; // compensate the mirror } else { // back-facing result = (info.orientation - degrees + 360) % 360; } camera.setDisplayOrientation(result); return result; } /* * record the rotation when take photo */ public void takePhoto(){ myOrientationListener.rememberOrientation(); rotation += myOrientationListener.getRememberedOrientation(); rotation = rotation % 360; mCamera.takePicture(null, null, mPicture); } class CameraOrientationListener extends OrientationEventListener { private int currentNormalizedOrientation; private int rememberedNormalizedOrientation; public CameraOrientationListener(Context context) { super(context, SensorManager.SENSOR_DELAY_NORMAL); } @Override public void onOrientationChanged(int orientation) { // TODO Auto-generated method stub if (orientation != ORIENTATION_UNKNOWN) { currentNormalizedOrientation = normalize(orientation); } } private int normalize(int degrees) { if (degrees > 315 || degrees <= 45) { return 0; } if (degrees > 45 && degrees <= 135) { return 90; } if (degrees > 135 && degrees <= 225) { return 180; } if (degrees > 225 && degrees <= 315) { return 270; } throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies."); } public void rememberOrientation() { rememberedNormalizedOrientation = currentNormalizedOrientation; } public int getRememberedOrientation() { return rememberedNormalizedOrientation; } } 

希望它有助于:)

当您的布局在纵向模式下修复时,这是最好的方法(下文中提到)。

 @Override protected void onResume() { super.onResume(); if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) { alertCameraDialog(); } if (cOrientationEventListener == null) { cOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) { public void onOrientationChanged(int orientation) { // determine our orientation based on sensor response int lastOrientation = mOrientation; if (orientation == ORIENTATION_UNKNOWN) return; Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); android.hardware.Camera.getCameraInfo(cameraId, info); orientation = (orientation + 45) / 90 * 90; int rotation = 0; if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { rotation = (info.orientation - orientation + 360) % 360; } else { // back-facing camera rotation = (info.orientation + orientation) % 360; } Parameters params = camera.getParameters(); params.setRotation(rotation); camera.setParameters(params); } }; } if (cOrientationEventListener.canDetectOrientation()) { cOrientationEventListener.enable(); } } 

您将使用OrientEventListener并实现此callback方法。 onOrientationChanged在方向发生改变时被调用,因此您的相机旋转将被设置并且图片在您保存时将被旋转。

  private PictureCallback myPictureCallback_JPG = new PictureCallback() { @Override public void onPictureTaken(byte[] arg0, Camera arg1) { try { File pictureFile = getOutputMediaFile(); if (pictureFile == null) { return; } FileOutputStream fos = new FileOutputStream(pictureFile); fos.write(arg0); fos.close(); camera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } }; 

getOutputMediaFile

  private static File getOutputMediaFile() { File mediaStorageDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp"); if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("MyCameraApp", "failed to create directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); File mediaFile; mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); return mediaFile; } 

来源于此

我没有代表发表评论,所以我不得不留下另一个答案,虽然Nvhausid的答案是真棒,值得信贷。 简单,优雅,适用于Exif和Media Cursor不支持的三星设备的前置和后置摄像头。

唯一没有答案的是我处理来自面向用户的相机的镜像。

这里是代码的变化:

 Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT); 

而新的旋转方法:

 public static Bitmap rotate(Bitmap bitmap, int degree, boolean mirror) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix mtx = new Matrix(); if(mirror)mtx.setScale(1,-1); mtx.postRotate(degree); return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } 

我用新的camera2 api来获取传感器的方向,然后相应地旋转它:

  private void detectSensorOrientation() { CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE); try { for (String cameraId : manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); // We don't use a front facing camera in this sample. Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { continue; } cameraOrientaion = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); } } catch (CameraAccessException e) { e.printStackTrace(); } } 

然后在cameraOrientation参数的帮助下,我旋转了我的cameraPhoto:

  private void generateRotatedBitmap() { if (cameraOrientaion != 0) { Matrix matrix = new Matrix(); matrix.postRotate(cameraOrientaion); rotatedPhoto = Bitmap.createBitmap(cameraPhoto, 0, 0, cameraPhoto.getWidth(), cameraPhoto.getHeight(), matrix, true); cameraPhoto.recycle(); } }