0

I have searched about fitting camera preview and surface view but I couldn't find about not stretching image while saving it in android studio.

The camera works well on showing on the surface view of the devices. The ratios of the supported screen sizes and surface view are ok.

The problem is that after capturing the image it takes more from all sides of the surface view of the screen. It just does not take the view that is shown on the surface view but more in all sides of the devices while saving the image.

The problem is only solved when height of the surface view and supported screen sizes are equal. Such as: Supported size is: 1280/720 Surface view is: 405/720 But this leads to a problem which limits the height and width of the surface view. I want height of surface view to be longer and width to be match parent.

So, the problem is not solved without having the heights equal. I want height of the surface view to be longer and width to be match parent.

Can anyone help me with this, Thanks everyone,

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private static final String TAG = "CameraPreview";

private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;

public int measurewidth, measureheigh;


public CameraPreview(Context context, Camera camera) {
    super(context);
    mContext = context;
    mCamera = camera;

    // supported preview sizes
    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    for(Camera.Size str: mSupportedPreviewSizes)
        Log.e(TAG, str.width + "/" + str.height);

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    // empty. surfaceChanged will take care of stuff
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.

}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    Log.e(TAG, "surfaceChanged => w=" + w + ", h=" + 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;
    }

    // stop preview before making changes
    try {
        mCamera.stopPreview();
    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
    }

    // set preview size and make any resize, rotate or reformatting changes here
    // start preview with new settings
    try {
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width  ,mPreviewSize.height); //B
        // parameters.setPreviewSize(1280,720 );
        mCamera.setParameters(parameters);
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();


    } catch (Exception e){
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);

    Log.e(TAG, "REAL SCREEN SIZE  => w=" + width + ", h=" + height);


    if (mSupportedPreviewSizes != null) {
        mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
    }
    Log.e(TAG, "MPREVIEW SIZE OPTIMAL  => w=" + mPreviewSize.width + ", h=" + mPreviewSize.height);

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

    Log.e(TAG, "Ration  => R=" + ratio);

    // One of these methods should be used, second method squishes preview slightly
    //setMeasuredDimension(1080, 1200);
    //setMeasuredDimension(mPreviewSize.height, mPreviewSize.width); //B

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


    // setMeasuredDimension(720, 1280);


    // setMeasuredDimension((int) (width ), height);

    measurewidth = width ; // this is for bitmap width   
    measureheigh = (int)(width*ratio); // this is for bitmap height


}

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { // long screen
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio=(double)h / w;

    if (sizes == null) return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) {
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
        if (Math.abs(size.width - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.width - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.width - targetHeight) < minDiff) {// size.height was changed with size.width
                optimalSize = size;
                minDiff = Math.abs(size.width - targetHeight); // size.height was changed with size.width
            }
        }
    }
    return optimalSize;
}

}

fadden
  • 51,356
  • 5
  • 116
  • 166
AndroidApp
  • 1
  • 1
  • 2

1 Answers1

1

After checking through your code (and the problem you are facing), I have decided to not focus on the coding part. Instead, I will give you an overview of what's happening between a preview and a snap (take picture).

Overview

In legacy camera API, there are 2 very important Camera.Size that you would need to take care - preview size and picture size.

From Camera.Parameters API, you are able to get 2 separate list of supported sizes by calling Parameters.getSupportedPreviewSizes() and Parameters.getSupportedPicturSizes().

As the names imply, each size list is dedicated for different purpose - preview and take picture.

Sample case

Imagine you have the list like this:

  • Preview size: 1920x1080 (16:9), 1280x960 (4:3)
  • Picture size: 3840x2160 (16:9), 1920x1440 (4:3)

Say, you want to take a picture in 3840x2160 (16:9), you call Parameters.setPictureSize(3840, 2160) to tell the camera you want to take a picture in this resolution when you call takePicture(...).

Solve equation

Now, how are you going to show a preview with the same resolution on the screen (or viewfinder)?

Yes, you guessed it - a preview size with the same aspect ratio (AR).

We need to find out the AR of the (target) picture size and find a matching preview size with the same AR and call Parameters.setPreviewSize(width, height) when we are ready.

In our case, we will select the preview size 1920x1080 as it has the same AR (16:9) as the picture size.

Different AR?

What happened if you want to take a picture of 16:9 but is setting the preview size to 4:3?

The answer is obvious, user will not be able to snap a picture in WYSIWYG style.

Points to note

Selecting a picture size and deciding on the preview size is not really difficult. Still, there are more you need to take care of to use the camera properly.

  • The orientation of the camera (CameraInfo.orientation) as opposed to the device natural orientation. Remember to call `Parameters.setRotation(rotation) when necessary.
  • In cases where the camera supports the same resolution in different orientation (eg. 1920x1080 and 1080x1920), call `Parameters.setPreviewSize(width, height) with the orientation you wish to take the picture in.

Hope this helps.

LightYearsBehind
  • 1,686
  • 18
  • 24