Camera preview stretched even after setting the correct dimensions

妖精的绣舞 提交于 2019-11-30 08:16:52

I was having the same problem, after some days in this puzzle, my Java class end up on this code:

So, The problem was happening because the camera display had a size (hight x width) 576x720, and my display was 1184x720. So, the camera preview (my surface view class) stretched to fill in the parent.

So, the approach that worked is to make this view bigger than my screen, and that just display the area of my screen. So, I had to use this weird frame combination (a relative layout inside a linearlayout), so that the size of the relative will be as big as I want - the surface view will fill in it -, and the linear will take just the part that I wanna display.

package com.example.frame.camera;

import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

import com.example.frame.MainActivity;

public class NativeCamera extends SurfaceView implements SurfaceHolder.Callback {

    static private NativeCamera instance;

    private LinearLayout        frame               = null;
    private RelativeLayout      innerFrame          = null;

    private Camera              camera;
    private final SurfaceHolder previewHolder;
    private static final String TAG                 = "NativeCamera.java";

    private boolean             inPreview           = false;
    private boolean             cameraConfigured    = false;
    private boolean             frontCamera         = false;

    private Camera.Size         size;

    static public NativeCamera getInstance() {
        if (NativeCamera.instance == null) {
            if (MainActivity.debug) {
                Log.d(TAG, "Creating Camera Singleton");
            }
            NativeCamera.instance = new NativeCamera(MainActivity.instance);
        }
        return NativeCamera.instance;
    }

    public void onResume() {
        if (MainActivity.debug) {
            Log.d(TAG, "onResume");
        }
        camera = Camera.open();
        if (size != null) {
            initPreview(size.width, size.height);
        }
        startPreview();
    }

    public void onPause() {
        if (MainActivity.debug) {
            Log.d(TAG, "onPause");
        }
        if (inPreview) {
            camera.stopPreview();
        }
        camera.release();
        camera = null;
        inPreview = false;
    }

    public void onDestroy() {
        if (MainActivity.debug) {
            Log.d(TAG, "onDestroy");
        }
        NativeCamera.instance = null;
    }

    public void onSwitch() {
        frontCamera = !frontCamera;
        if (inPreview) {
            camera.stopPreview();
        }
        camera.release();

        int cam = frontCamera ? 1 : 0;

        camera = Camera.open(cam);
        if (size != null) {
            initPreview(size.width, size.height);
        }
        startPreview();
    }

    private NativeCamera(Context context) {
        super(context);
        // TODO Auto-generated constructor stub

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        previewHolder = getHolder();
        previewHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        // previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        innerFrame = new RelativeLayout(MainActivity.instance);
        innerFrame.addView(this);
        frame = new LinearLayout(MainActivity.instance);
        frame.addView(innerFrame);
    }

    public LinearLayout getFrame() {
        return frame;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // TODO Auto-generated method stub
        if (MainActivity.debug) {
            Log.d(TAG, "surfaceChanged");
        }
        initPreview(width, height);
        startPreview();
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // no-op -- wait until surfaceChanged()

    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // no-op
    }

    private Camera.Size getBestPreviewSize(int width, int height,
            Camera.Parameters parameters) {
        Camera.Size result = null;

        for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
            if (size.width <= width && size.height <= height) {
                if (result == null) {
                    result = size;
                } else {
                    int resultArea = result.width * result.height;
                    int newArea = size.width * size.height;

                    if (newArea > resultArea) {
                        result = size;
                    }
                }
            }
        }

        this.size = result;
        return (result);
    }

    private void initPreview(int width, int height) {
        if (camera != null && previewHolder.getSurface() != null) {

            if (!cameraConfigured) {
                Camera.Parameters parameters = camera.getParameters();
                Camera.Size size = getBestPreviewSize(width, height, parameters);

                if (size != null) {
                    parameters.setPreviewSize(size.width, size.height);
                    camera.setParameters(parameters);
                    cameraConfigured = true;
                    // Setting up correctly the view
                    double ratio = size.height / (double) size.width;
                    LayoutParams params = innerFrame.getLayoutParams();
                    params.height = MainActivity.size.y;
                    params.width = (int) (MainActivity.size.y * ratio);
                    innerFrame.setLayoutParams(params);
                    int deslocationX = (int) (params.width / 2.0 - MainActivity.size.x / 2.0);
                    innerFrame.animate().translationX(-deslocationX);
                }
            }

            try {
                camera.setPreviewDisplay(previewHolder);
                camera.setDisplayOrientation(90);

            } catch (Throwable t) {
                Log.e(TAG, "Exception in setPreviewDisplay()", t);
                Toast.makeText(MainActivity.instance, t.getMessage(), Toast.LENGTH_LONG).show();
            }

        }
    }

    private void startPreview() {
        if (MainActivity.debug) {
            Log.d(TAG, "startPreview");
        }
        if (cameraConfigured && camera != null) {
            camera.startPreview();
            inPreview = true;
        }
    }

}
Anju

I have been trying to solve the same issue... Below code worked for me:

private void setMyPreviewSize(int width, int height) {
    // Get the set dimensions
    float newProportion = (float) width / (float) height;

    // Get the width of the screen
    int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
    int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
    float screenProportion = (float) screenWidth / (float) screenHeight;

    // Get the SurfaceView layout parameters
    android.view.ViewGroup.LayoutParams lp = surfaceView.getLayoutParams();
    if (newProportion > screenProportion) {
        lp.width = screenWidth;
        lp.height = (int) ((float) screenWidth / newProportion );
    } else {
        lp.width = (int) (newProportion * (float) screenHeight);
        lp.height = screenHeight;
    }
    // Commit the layout parameters
    surfaceView.setLayoutParams(lp);
}

You can see the thread: Resizing surface view for aspect ratio change in video display in android

Here's a solution

surfaceChanged is just to get the best preview size

@Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                Log.e("MYTAG", "surfaceChanged " );

                Camera.Parameters myParameters = camera.getParameters();
                Camera.Size myBestSize = getBestPreviewSize(width, height, myParameters);

                if(myBestSize != null){
                    myParameters.setPreviewSize(myBestSize.width, myBestSize.height);
                    camera.setParameters(myParameters);
                    camera.startPreview();


                }
            }



@Override
    public void onPictureTaken(byte[] data, Camera camera) {

        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
       imageReview.setImageBitmap(bitmap);
    }

This will set the captured image on imageReview, but you need a method to get the rotation of the bitmap

you need to set imageView scaleType attribute for stretched image issue

<ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        />
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!