Android: l'anteprima della fotocamera è laterale


123

Sto usando un'anteprima per visualizzare ciò che la telecamera vede sullo schermo.

Riesco a far funzionare tutto bene, la superficie creata, la superficie impostata e la superficie viene visualizzata.

Tuttavia visualizza sempre l'immagine con un angolo di 90 gradi errato in modalità verticale.

Come nella foto:

testo alternativo

Sono consapevole che l'utilizzo del seguente codice imposterà l'immagine dritta:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Tuttavia ho l'anteprima all'interno di un'attività che contiene altri elementi e non ha senso che la mia attività venga visualizzata in modalità orizzontale. (È disabilitato per impostazione predefinita)

Quindi mi chiedevo se c'è comunque da cambiare solo l'orientamento dell'anteprima? E lasciare il resto della mia attività correttamente visualizzato in modalità Ritratto?

O comunque per ruotare l'anteprima in modo che venga visualizzata correttamente?


Risposte:


145

Questo problema sembrava iniziare come un bug con alcuni hardware, vedere qui, ma può essere risolto utilizzando la chiamata a mCamera.setDisplayOrientation (gradi) disponibile nell'API 8. Quindi è così che lo implemento:

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

Questo era su un HTC Desire e inizialmente dovevo inserire le dichiarazioni di registrazione in ciascuno dei controlli di rotazione per dire quale fosse la rotazione, quindi ho eseguito il debug sul dispositivo e ho guardato l'output di logCat mentre ruotavo il dispositivo. Per l'HTC Desire, 0 era il telefono come ci si aspetterebbe (verticale), 90 gradi ruotava il telefono di 90 gradi IN SENSO ANTIORARIO (avevo pensato che sarebbe stato in senso orario). Nel codice vedrai che non avevo bisogno di ruotare il display quando il telefono era a 90 o 180 gradi: il dispositivo sembrava gestirlo da solo. Solo un punto non funziona correttamente: la rotazione di 270 gradi è quando si ruota il dispositivo di 90 gradi in senso orario e la rotazione del display contrasta che va bene, ma se si ruota il dispositivo di 270 gradi in senso antiorario, non sembra compensarlo correttamente.

PS Notare lo scambio di larghezza e altezza nelle rotazioni appropriate.


7
ma setDisplayOrientation (grado); il metodo supporta il modulo 2.2, che dire della versione inferiore ?? parameters.setRotation (90); parameters.set ("orientamento", "ritratto"); non funzionano. Se hai qualche soluzione per le versioni precedenti per favore aiutami.
Vikram

1
Ho implementato un'anteprima sulla mia app che verrà sempre mostrata in modalità verticale. Ho sempre ruotato lo schermo di 90 gradi e questo sembrava funzionare su tutti i dispositivi fino a quando non l'abbiamo testato sull'HTC Desire C.Poiché non conto sul dispositivo ora per testarlo, vorrei che tu chiarissi se questo ti risolve suggerisco finalmente ha funzionato bene sul desiderio HTC. Grazie!
argenkiwi

13
L' mCamera.setParameters(parameters);istruzione blocca la mia app, perché le dimensioni della superficie non sono una dimensione di anteprima valida per il mio telefono (forse perché tengo visibile la barra di stato?). Tuttavia, ho scoperto che anche l'uso di mCamera.setDisplayOrientation(90)allora mCamera.setPreviewDisplay(mSurfaceHolder);senza impostare i parametri ha funzionato!
nicopico

3
sarebbe più pulito con una dichiarazione di cambio
Siavash

2
Questo non presume che l'anteprima sia di lato su TUTTI i dispositivi? perché è lateralmente su alcuni dispositivi e in alto a destra su altri .... c'è un modo per verificare se un dispositivo ha l'orientamento predefinito della fotocamera in linea con il lato verticale del telefono o no?
Siavash

16

provare a impostare l'orientamento del display. Risolve il mio problema.

 mCamera.setDisplayOrientation(90);

5
al momento del salvataggio salva l'immagine ritratto in orizzontale. Qualche soluzione?
Akanksha Rathore

@ Akanksha: questo flag si applica solo alla visualizzazione dell'anteprima. Non cambia l'orientamento del buffer restituito in onPreviewFrame()oonPictureTaken()
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();
     }
}

prova questo codice


3
al momento del salvataggio salva l'immagine ritratto in orizzontale. Qualche soluzione?
Akanksha Rathore

@ Akanksha probabilmente ha a che fare con i parametri EXIF.
EpicPandaForce

4

Ho riscontrato un problema con la fotocamera anteriore (problema sottosopra). Quindi ho usato il seguente metodo documentato in 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
Questo metodo proviene dalla documentazione della fotocamera: developer.android.com/reference/android/hardware/…
VinceFior

@VinceFior Qualcosa non va se pubblica da un documento ufficiale?
Ranjith Kumar

1
@RanjithKumar Non particolarmente, volevo solo dare credito alla fonte e indirizzare le persone lì per più contesto. :)
VinceFior

3

L'ho fatto su consiglio di mCamera.setDisplayOrientation (90); ma ho anche ruotato la bitmap perché per qualche motivo gli altri approcci non funzionano per me nella versione 2.3.3.

Per ruotare la bitmap ho fatto questo:

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

Ho confrontato il mio codice con quello del tutorial e quello che alla fine l'ha risolto è stato inserire il seguente codice nel mio AndroidManifext.xml: Nel <activity>tag:

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

Penso che il valore SENSOR_ORIENTATION spiegherà quale valore usare per la rotazione invece di codificare a 90 gradi

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);
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.