web-dev-qa-db-fra.com

Le contrôle de l'appareil photo pour prendre des photos en mode portrait ne fait pas pivoter les images finales

J'essaie de contrôler l'appareil photo Android pour prendre des photos dans une application de portrait, mais lorsque je sauvegarde l'image, elle est en mode paysage. J'ai fait pivoter l'image sur 90 niveaux avec la méthode setCameraDisplayOrientation() , mais cela ne fonctionne pas.

Ensuite, j'ai trouvé ce post mais le TAG_ORIENTATION est 0 (non défini). Si j'attrape cette valeur et applique une valeur de rotation, cela ne fonctionne pas non plus. 

Comment puis-je prendre une photo en portrait et l'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());
    }
}
57
beni

Le problème est que lorsque j'ai enregistré l'image, je ne l'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);
}
55
beni

La méthode setCameraDisplayOrientation () vous permet de modifier l'affichage de la prévisualisationsans affecter la façon dont l'image est enregistrée ( source ).

Afin de changer l'image enregistrée réelle, vous devez définir le paramètre rotation de la caméra . Vous le faites comme ça:

//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 solution de contournement puisque vous modifiez l'image APRÈS qu'elle ait déjà été enregistrée. Cette solution est plus propre et ne nécessite pas toutes ces instructions "if" avant l'enregistrement de l'image.

50
Nimrod Dayan

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

Ce code entre dans la méthode surfaceChanged de l'aperçu de votre caméra  

@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 faire pivoter l'image de cette façon. Ceci n'est utilisé que lorsque l'image est prise et que nous sommes sur le point de sauvegarder 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);
    }

La bitmapImage contient la bonne image.

23

celui-ci devrait fonctionner, ExifInterface ne fonctionnant pas avec tous les fabricants, utilisez plutôt CameraInfo, laissez simplement l'appareil capturer l'image avec sa rotation par défaut, puis faites pivoter 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);
}
6
nvhausid

Je n'ai pas le représentant pour laisser un commentaire, alors je dois laisser une autre réponse à la place, bien que la réponse à Nvhausid soit géniale et mérite le crédit. Simple, élégant et compatible avec les appareils photo avant et arrière d’un appareil Samsung, contrairement à Exif et Media Cursor. 

La seule chose qui me manquait, c’était la gestion de 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);
}
2
D. Scott

Je trouve la réponse puissante pour vous, je viens de rencontrer le même problème et le résoudre sans enregistrer le fichier. La solution consiste à enregistrer un programme OrientationEventListener pour obtenir l'orientation à chaque fois qu'il change . http://www.androidzeitgeist.com/2013/ 01/fixing-rotation-camera-image.html donnez les détails ici.Mon code est comme ci-dessous:

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

j'espère que ça aide:)

1
Yueh-Ming Chien

C'est la meilleure méthode à utiliser (Mentionnée ci-dessous) lorsque votre mise en page est corrigé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 utiliserez OrientEventListener et implémenterez cette méthode de rappel . OnOrientationChanged est appelé chaque fois qu'il y a un changement d'orientation. La rotation de votre caméra est donc définie et l'image est tournée lorsque vous l'enregistrez.

      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
KD_

J'ai utilisé le nouvel api camera2 pour obtenir l'orientation du capteur, puis 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 avec l'aide du paramètre cameraOrientation, j'ai fait pivoter ma 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
Rushi M Thakker