Contrôler la caméra pour prendre des photos en portrait ne fait pas tourner les images finales

j'essaie de contrôler la caméra Android pour prendre des photos dans une application portrait, mais quand je sauve la photo, c'est dans le paysage. J'ai fait tourner l'image 90 avec la méthode setCameraDisplayOrientation() , mais ça ne marche pas.

alors j'ai trouvé ce post mais le TAG_ORIENTATION est 0 (Non défini). Si j'attrape cette valeur et que j'applique une valeur de rotation, ça ne marche pas non plus.

Comment puis-je prendre un photo en portrait et enregistrer avec une bonne orientation?

    /** 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());
    }
}
54
demandé sur Community 2013-04-04 14:32:39

8 réponses

le problème est quand j'ai enregistré l'image que je n'ai pas bien fait.

@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);
}
52
répondu beni 2016-02-11 14:41:15

la méthode setCameraDisplayOrientation () vous permet de changer la façon dont preview est affiché sans affecter comment l'image est enregistrée ( source ).

pour changer l'image réelle enregistrée, vous devez définir le paramètre rotation de la Caméra . Vous faites comme ceci:

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

votre solution est une sorte de contournement puisque vous modifiez l'image après qu'elle ait été déjà enregistrée. Cette solution est plus propre et ne nécessite pas toutes ces instructions " si " avant de sauvegarder l'image.

49
répondu Nimrod Dayan 2013-09-18 14:10:40

vous pouvez utiliser la méthode ci-dessous pour générer un aperçu correctement lorsque vous utilisez une caméra frontale.

ce code va dans la méthode changée en surface de votre caméra preview

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

ce code peut être placé dans une classe statique

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

vous pouvez tourner l'image de cette façon.Il est utilisé uniquement lorsque l'image est prise et nous sommes sur le point d'enregistrer l'image

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

La Méthode qui sera utilisée pour prendre une photo

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

le bitmapImage contient l'image correcte.

21
répondu Sheraz Ahmad Khilji 2014-10-01 12:21:20

celui-ci devrait fonctionner, ExifInterface ne fonctionne pas avec tous les produits donc utilisez CameraInfo à la place, laissez la caméra capturer l'image avec sa rotation par défaut et puis tourner les données de résultat sur 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);
}
5
répondu nvhausid 2013-09-20 11:17:36

je trouve la réponse puissante pour vous, je rencontre juste le même problème et le résoudre sans enregistrer le fichier.La solution est d'enregistrer un OrientationEventListener pour obtenir l'orientation chaque fois qu'elle change. http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html ici donner les détails.Mon code est le suivant:

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

espère que cela aide:)

1
répondu Yueh-Ming Chien 2014-03-02 08:16:25

C'est la meilleure méthode à utiliser (mentionnée ci-dessous) lorsque votre mise en page est fixée en mode portrait.

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

vous allez utiliser OrientEventListener et mettre en œuvre cette méthode de rappel. onOrientationChanged est appelé chaque fois qu'il y a un changement d'orientation ainsi votre rotation de caméra sera réglée et L'image sera tournée quand vous la sauvegarderez.

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

Source ici

1
répondu KD_ 2015-05-13 14:23:03

Je n'ai pas le représentant de laisser un commentaire, donc je dois laisser une autre réponse à la place, bien que la réponse Nvhausid est génial et mérite le crédit. Simple, élégant et il fonctionne à la fois pour les caméras avant et arrière sur un appareil Samsung où Exif et Media curseur ne fonctionne pas.

la seule chose que la réponse me manquait, c'était de manipuler l'image miroir de la caméra face à l'utilisateur.

Voici les changements de code pour cela:

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

et la nouvelle méthode de rotation:

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);
}
1
répondu D. Scott 2016-10-30 03:37:15

j'ai utilisé la nouvelle api camera2 pour obtenir l'orientation du capteur et le faire pivoter en conséquence:

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

puis, à l'aide du paramètre cameraOrientation, j'ai fait tourner mon 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();
    }
  }
0
répondu Rushi M Thakker 2017-03-23 09:22:24