Управление камерой для съемки в портрете не приводит к повороту окончательных изображений

Я пытаюсь контролировать камеру Android, чтобы делать снимки в приложении для портрета, но когда я сохраняю изображение, он находится в ландшафте. Я повернул изображение 90 classов с setCameraDisplayOrientation() метода setCameraDisplayOrientation() , но не работает.

Затем я нашел этот пост, но TAG_ORIENTATION равен 0 (undefined). Если я поймаю это значение и применим значение поворота, он тоже не работает.

Как я могу сделать фотографию на портрете и сохранить ее с хорошей ориентацией?

  /** 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()); } } 

Проблема в том, что когда я сохранил изображение, у меня не получилось.

 @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); } 

Метод setCameraDisplayOrientation () позволяет изменить способ отображения предварительного просмотра, не влияя на то, как изображение записывается ( источник ).

Чтобы изменить фактическое записанное изображение, вам необходимо установить параметр вращения камеры . Вы делаете это так:

 //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); 

Ваше решение – это обходное решение, так как вы изменяете изображение ПОСЛЕ того, как оно уже было записано. Это решение является более чистым и не требует всех этих инструкций if, прежде чем сохранять изображение.

Вы можете использовать приведенный ниже метод, чтобы правильно генерировать предварительный просмотр при использовании фронтальной камеры.

Этот код попадает в метод 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); } 

Этот код можно поместить в статический class

  /** * 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); } 

Я нахожу для вас мощный ответ, я просто отвечаю на ту же проблему и решая ее без сохранения файла. Решением является регистрация OrientationEventListener, чтобы получить ориентацию всякий раз, когда она изменяется. http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html здесь приводят подробности. Мой код выглядит следующим образом:

 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 и реализовать этот метод обратного вызова. onOrientationChanged вызывается всякий раз, когда происходит изменение ориентации, таким образом rotation камеры будет установлено, и изображение будет повернуто, когда вы его сохраните.

  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 является потрясающим и заслуживает кредита. Простой, элегантный и он работает как для передней, так и для задней камеры на устройстве Samsung, где Exif и Media Cursor этого не делают.

Единственное, что мне не хватило, это обработать зеркальное изображение с камеры, обращенной к пользователю.

Вот код для этого:

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

И новый метод rotate:

 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); } 

Я использовал новую камеру2 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 я повернул свою камеру. Фото:

  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(); } } 
  • Неисправность работы с камерой в onActivityResult
  • Предварительный просмотр камеры для Android
  • широковещательный приемник не получит событие камеры
  • Назначение камеры Android
  • Активность kill / onCreate вызвана после съемки с помощью намерения
  • Давайте будем гением компьютера.