2

This is the result I get when I make the SurfaceView smaller. How do I fix this so that it shows correct aspect ratio? I don't want to use the whole image I get from the camera, only a part of it.

Think of it like the Facebook messenger app, when you want to take an instant photo from the app, a small camera window appears. I want the same result. Here is my code:

import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;
import java.util.List;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    public static final String TAG = "AKSQS";
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        //Take care of rotation and resizing here.

        mCamera.stopPreview();
        mCamera.setDisplayOrientation(90);

        Camera.Parameters parameters = mCamera.getParameters();
        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
        for (Camera.Size sizesl : sizes) {
            //This is just to see the supported preview sizes.
            Log.d(TAG, "Width: " + String.valueOf(sizesl.width));
            Log.d(TAG, "Height: " + String.valueOf(sizesl.height));
            Log.d(TAG, "--------");
        }
//        parameters.setPreviewSize(1080,288);

        mCamera.setParameters(parameters);

        mCamera.startPreview();

        if (mHolder.getSurface() == null) {
            return;
        }

        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            Log.d(TAG, "Tried to stop a non-existing preview. Message: " + e.getMessage());
        }

        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
        } catch (Exception e) {
            Log.d(TAG, "Error starting camra preview: " + e.getMessage());
        }

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }

}

Here is my xml file:

<RelativeLayout ...>

<FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="250dp"
        android:id="@+id/camera_preview"
        android:layout_alignParentBottom="true">
    </FrameLayout>

</RelativeLayout>

Here is the result I get:

https://i.stack.imgur.com/AEx2C.jpg

A. Savva
  • 632
  • 10
  • 30

2 Answers2

2

This has been bothering me for a month. I finally figured out the answer here:

https://stackoverflow.com/a/22758359/5273230

Here's the final result:

https://i.stack.imgur.com/kA7CP.jpg

Community
  • 1
  • 1
A. Savva
  • 632
  • 10
  • 30
  • You can also do it with a FrameLayout; see e.g. Grafika's [AspectFrameLayout](https://github.com/google/grafika/blob/master/src/com/android/grafika/AspectFrameLayout.java) and the way it's used in the PlayMovieSurfaceActivity class. – fadden Aug 30 '15 at 05:15
0

Already found a solution.

First of all we know that every device have different preview size and picture size.

Related from this post we know how to get correct aspect ratio. See my code

    private void searchRatio(Camera.Size size, float ratio) {
        float count1;
//        float ratio = (float) 1.7777778; // 9:16
//        float ratio = (float) 1.0; // 1:1
        if (size.width > size.height) {
            count1 = (float) size.width / (float) size.height;
        } else {
            count1 = (float) size.height / (float) size.width;
        }
        if (count1 == ratio) {
            width.add(size.width);
            height.add(size.height);
        }
    }

Here how I use that function

        List<Camera.Size> previewSizes = param.getSupportedPreviewSizes();

        // set preview size
        for (Camera.Size size : previewSizes) {
            if (ratioPreview != null) {
                ConstraintSet set = new ConstraintSet();
                set.clone(binding.getRoot());
                set.setDimensionRatio(binding.surfaceView.getId(), ratioPreview);
                set.applyTo(binding.getRoot());

                if (ratioPreview.equals("9:16")) {
                    searchRatio(size, (float) 1.7777778);
                } else if (ratioPreview.equals("1:1")) {
                    searchRatio(size, (float) 1.0);
                }
            } else {
                searchRatio(size, (float) 1.7777778);
            }
        }
        if (width.size() != 0) {
            param.setPreviewSize(width.get(0), height.get(0));
        }

In this case your preview will still stretched. You must set you SurfaceView dimension. This is only simple example, for me I just need 9:16 so I set dimension from xml

<SurfaceView
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:id="@+id/surface_view"
        app:layout_constraintDimensionRatio="9:16"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

After that, my preview is not stretched again.