Android - L'aperçu de l'appareil photo est sur le côté


123

J'utilise un aperçu pour afficher ce que la caméra voit à l'écran.

Je peux tout faire fonctionner correctement, créer une surface, définir la surface et afficher la surface.

Cependant, il affiche toujours l'image à un angle incorrect de 90 degrés en mode portrait.

Comme dans l'image:

texte alternatif

Je suis conscient que l'utilisation du code suivant rétablira l'image:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Cependant, j'ai l'aperçu dans une activité qui contient d'autres éléments et cela n'a pas de sens que mon activité soit affichée en mode paysage. (Il est désactivé par défaut)

Alors je me demandais s'il y avait de toute façon simplement changer l'orientation de l'aperçu? Et laisser le reste de mon activité correctement affiché en mode Portrait?

Ou de toute façon faire pivoter l'aperçu pour qu'il s'affiche correctement?


Réponses:


145

Ce problème semble avoir commencé comme un bogue avec certains matériels voir ici mais peut être surmonté en utilisant l'appel à mCamera.setDisplayOrientation (degrés) disponible dans l'API 8. Voici donc comment je l'implémente:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if(display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(height, width);                           
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(width, height);                           
    }

    if(display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(height, width);               
    }

    if(display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    }

    mCamera.setParameters(parameters);
    previewCamera();                      
}

And the previewCamera method :

public void previewCamera() {        
    try {           
        mCamera.setPreviewDisplay(mSurfaceHolder);          
        mCamera.startPreview();
        isPreviewRunning = true;
    } catch(Exception e) {
        Log.d(APP_CLASS, "Cannot start preview", e);    
    }
}

C'était sur un HTC Desire et j'ai d'abord dû mettre des instructions de journalisation dans chacun des contrôles de rotation pour dire ce qu'était la rotation, puis débogué sur l'appareil et regardé la sortie logCat pendant que je faisais pivoter l'appareil. Pour le HTC Desire, 0 était le téléphone comme on pouvait s'y attendre (portrait), 90 degrés tournait le téléphone à 90 degrés dans le sens inverse des aiguilles d'une montre (j'avais supposé que cela aurait été dans le sens des aiguilles d'une montre). Dans le code, vous verrez que je n'avais pas besoin de faire de rotation d'affichage lorsque le téléphone était à 90 ou 180 degrés - l'appareil semblait gérer cela lui-même. Un seul point ne fonctionne pas correctement: la rotation de 270 degrés se produit lorsque vous tournez l'appareil de 90 degrés dans le sens des aiguilles d'une montre et que la rotation de l'affichage est correcte, mais si vous faites pivoter l'appareil de 270 degrés dans le sens inverse des aiguilles d'une montre, cela ne semble pas le compenser correctement.

PS Notez la permutation de la largeur et de la hauteur dans les rotations appropriées.


7
mais setDisplayOrientation (degré); méthode prend en charge la forme 2.2, qu'en est-il de la version inférieure? parameters.setRotation (90); parameters.set ("orientation", "portrait"); ne fonctionnent pas. Si vous avez une solution pour les versions inférieures, aidez-moi.
Vikram

1
J'ai implémenté un aperçu sur mon application qui s'affichera toujours en mode portrait. Je faisais toujours pivoter l'écran de 90 degrés et cela semblait fonctionner sur tous les appareils jusqu'à ce que nous les testions sur le HTC Desire C. Comme je ne compte pas sur l'appareil maintenant pour tester cela, j'aimerais que vous clarifiiez si cela vous corrige suggérer a finalement bien fonctionné sur le désir de HTC. Merci!
argenkiwi

13
L' mCamera.setParameters(parameters);instruction plante mon application, car les dimensions de la surface ne sont pas une taille d'aperçu valide pour mon téléphone (peut-être parce que je garde la barre d'état visible?). Cependant, je trouve que l' utilisation mCamera.setDisplayOrientation(90)puis mCamera.setPreviewDisplay(mSurfaceHolder);sans régler les paramètres travaillaient aussi!
nicopico

3
serait plus propre avec une déclaration de commutation
Siavash

2
Cela ne suppose-t-il pas que l'aperçu est latéral sur TOUS les appareils? car il est sur le côté sur certains appareils et vers le haut sur d'autres .... y a-t-il un moyen de vérifier si l'orientation de l'appareil photo par défaut d'un appareil est alignée avec le côté portrait du téléphone ou non?
Siavash

16

essayez de définir l'orientation de l'affichage. Cela résout mon problème.

 mCamera.setDisplayOrientation(90);

5
au moment de l'enregistrement, il enregistre l'image du portrait en mode paysage. Une solution?
Akanksha Rathore

@Akanksha: cet indicateur s'applique uniquement à l'affichage de l'aperçu. Cela ne change pas l'orientation du tampon retourné dans onPreviewFrame()ouonPictureTaken()
Alex Cohn

13
 public void surfaceCreated(SurfaceHolder holder) {
     mCamera = Camera.open();
     mCamera.setDisplayOrientation(90);
     try {
         mCamera.setPreviewDisplay(holder);
         mCamera.setPreviewCallback(new PreviewCallback() {

             @Override
             public void onPreviewFrame(byte[] data, Camera camera) {
             }
         });

     } catch (Exception e) {
         e.printStackTrace();
     }
}

essayez ce code


3
au moment de l'enregistrement, il enregistre l'image du portrait en mode paysage. Une solution?
Akanksha Rathore

@Akanksha c'est probablement à voir avec les paramètres EXIF.
EpicPandaForce

4

J'avais un problème avec la caméra frontale (problème à l'envers). Ensuite, j'ai utilisé la méthode suivante documentée dans Android Docs -

public void setCameraDisplayOrientation(Activity activity , int icameraId , Camera camera1s)
    {
        CameraInfo cameraInfo = new CameraInfo();

        Camera.getCameraInfo(icameraId, cameraInfo);

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int degrees = 0; // k

        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 (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
        {
            // cameraType=CAMERATYPE.FRONT;

            result = (cameraInfo.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror

        }
        else
        { // back-facing

            result = (cameraInfo.orientation - degrees + 360) % 360;

        }
        // displayRotate=result;
        camera.setDisplayOrientation(result);


    }

3
Cette méthode provient de la documentation de l'appareil photo: developer.android.com/reference/android/hardware/…
VinceFior

@VinceFior Quelque chose ne va pas s'il publie à partir d'un document officiel?
Ranjith Kumar

1
@RanjithKumar Pas particulièrement, je voulais juste rendre hommage à la source et diriger les gens là-bas pour plus de contexte. :)
VinceFior

3

Je l'ai fait en suivant les conseils de mCamera.setDisplayOrientation (90); mais aussi fait pivoter le bitmap parce que pour une raison quelconque, les autres approches ne fonctionnent pas pour moi dans la version 2.3.3.

Pour faire pivoter le bitmap, j'ai fait ceci:

Matrix matrix = new Matrix();
matrix.postRotate(90);
imageView1 = new ImageView(this);
Bitmap bitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath());
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(rotatedBitmap, 80, 80, true);
imageView1.setImageBitmap(scaledBitmap);

0

J'ai comparé mon code à celui du didacticiel et ce qui a finalement résolu le problème a été de mettre le code suivant dans mon AndroidManifext.xml <activity>:

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

0
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (mHolder.getSurface() == null) {
        // preview surface does not exist
        return;
    }

    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        e.printStackTrace();
    }

    Camera.Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) getContext().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(90);
    }

    if (display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(0);
    }

    if (display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(270);
    }

    if (display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(180);
    }

    previewCamera();
}

public void previewCamera() {
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        //Log.d(APP_CLASS, "Cannot start preview", e);
        e.printStackTrace();
    }
}

0

Je pense que la valeur SENSOR_ORIENTATION expliquera la valeur à utiliser pour la rotation au lieu du codage en dur à 90 degrés

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        if (manager == null) {
            Log.i(TAG, "camera manager is null");
            return;
        }
        for (String id: manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
            Integer orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            Log.i(TAG, "camera sensor orientation is " + orientation);
        }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.