144 votes

Aperçu de la caméra Android étiré

J'ai travaillé sur la création de mon activité de caméra personnalisée sur Android, mais lorsque je tourne la caméra, le rapport hauteur/largeur de la vue surface est perturbé.

Dans mon onCreate pour l'activité, j'ai défini le framelayout qui contient la vue surface qui affiche les paramètres de la caméra.

//FrameLayout qui contiendra l'aperçu de la caméra
        FrameLayout previewHolder = (FrameLayout) findViewById(R.id.camerapreview);

        //Définition de la taille de l'aperçu de la caméra pour la meilleure taille d'aperçu
        Size optimalSize = null;
        camera = getCameraInstance();
        double aspectRatio = 0;
        if(camera != null){
            //Définition du rapport hauteur/largeur de la caméra
            Camera.Parameters parameters = camera.getParameters();
            List sizes = parameters.getSupportedPreviewSizes();
            optimalSize = CameraPreview.getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
            aspectRatio = (float)optimalSize.width/optimalSize.height;
        }

        if(optimalSize!= null){
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            previewHolder.setLayoutParams(params);
            LayoutParams surfaceParams = new LayoutParams(LayoutParams.MATCH_PARENT, (int)(getResources().getDisplayMetrics().widthPixels*aspectRatio));
            cameraPreview.setLayoutParams(surfaceParams);

        }

        cameraPreview.setCamera(camera);

        //Ajout de l'aperçu au conteneur
        previewHolder.addView(cameraPreview);

Ensuite, dans la vue de surface, je définis les paramètres de la caméra à afficher

public void setCamera(Camera camera) {
        if (mCamera == camera) { return; }

        mCamera = camera;

        if (mCamera != null) {
            requestLayout();

            try {
                mCamera.setPreviewDisplay(mHolder);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if(mCamera != null){
                //Définition du rapport hauteur/largeur de la caméra
                Camera.Parameters parameters = mCamera.getParameters();
                List sizes = parameters.getSupportedPreviewSizes();
                Size optimalSize = getOptimalPreviewSize(sizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);

                parameters.setPreviewSize(optimalSize.width, optimalSize.height);
                mCamera.setParameters(parameters);
            }

            /*
              Important : Appelez startPreview() pour commencer à mettre à jour la surface de prévisualisation. La prévisualisation doit 
              être démarrée avant de pouvoir prendre une photo.
              */
            mCamera.startPreview();
        }

    }

entrez la description de l'image ici

Vous pouvez voir que l'homme LEGO devient plus grand et plus mince lorsque le téléphone est tourné :

Comment puis-je m'assurer que le rapport hauteur/largeur de ma vue de caméra est correct ?

0voto

Raul Lucaciu Points 64

Un peu tard pour vous mais espérons que ce ne soit pas le cas pour tout le monde.

Ce que vous pouvez utiliser pour garantir un ratio spécifique est l'attribut :

layout_constraintDimensionRatio="ration_a:ratio_b"

Cela a résolu mes problèmes.

0voto

touhid udoy Points 3443

La solution ci-dessous est une mise à jour de la réponse de @Hesam à cette question, qui aborde les points suivants :

  1. La vue finale est déformée sur quelques écrans

  2. L'aperçu est placé tout en haut de l'écran, pas centré, ce qui semble très étrange.


Il vous suffit de mettre à jour la méthode onMeasure de cette façon, tout le reste reste inchangé.

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    //centraliser l'aperçu
    FrameLayout.LayoutParams surfaceParams = new FrameLayout.LayoutParams(width, (int) height);
    surfaceParams.gravity = Gravity.CENTER;
    this.setLayoutParams(surfaceParams);

    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }

    if (mPreviewSize != null) {
        float ratio;
        if (mPreviewSize.height >= mPreviewSize.width)
            ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
        else
            ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

        setMeasuredDimension(width, (int) (width * ratio));

        //corriger la distorsion, basé sur cette réponse https://stackoverflow.com/a/30634009/6688493
        float camHeight = (int) (width * ratio);
        float newCamHeight;
        float newHeightRatio;

        if (camHeight < height) {
            newHeightRatio = (float) height / (float) mPreviewSize.height;
            newCamHeight = (newHeightRatio * camHeight);
            Log.e(TAG, camHeight + " " + height + " " + mPreviewSize.height + " " + newHeightRatio + " " + newCamHeight);
            setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
            Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | H_ratio - " + newHeightRatio + " | A_width - " + (width * newHeightRatio) + " | A_height - " + newCamHeight);
        } else {
            newCamHeight = camHeight;
            setMeasuredDimension(width, (int) newCamHeight);
            Log.e(TAG, mPreviewSize.width + " | " + mPreviewSize.height + " | ratio - " + ratio + " | A_width - " + (width) + " | A_height - " + newCamHeight);
        }
    }
}

-1voto

user2919210 Points 1

Vous devez définir cameraView.getLayoutParams().height et cameraView.getLayoutParams().width en fonction du rapport hauteur/largeur que vous désirez.

-2voto

Martin Šuráb Points 167

J'ai abandonné les calculs et simplement obtenu la taille de la vue où je veux afficher l'aperçu de la caméra et j'ai défini la taille de l'aperçu de la caméra de la même manière (juste en inversant largeur/hauteur en raison de la rotation) dans mon implémentation personnalisée de SurfaceView :

@Override // CameraPreview étend SurfaceView implémente SurfaceHolder.Callback { 
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    Display display = ((WindowManager) getContext().getSystemService(
            Context.WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        final Camera.Parameters params = camera.getParameters();
        // viewParams provient de la vue où l'aperçu est affiché
        params.setPreviewSize(viewParams.height, viewParams.width);
        camera.setDisplayOrientation(90);
        requestLayout();
        camera.setParameters(params);
    }
    // Je ne permets pas la rotation, donc cela peut rester tel quel
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X