android-vision: CameraSourcePreview doesn't fill whole screen height

I’m having everything the same as in this sample except my activity layout is this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/topLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:keepScreenOn="true"
    android:weightSum="100"
    android:orientation="horizontal">

    <be.citylife.communitypurchaseapp.view.camera.CameraSourcePreview
        android:id="@+id/preview"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="60">

        <be.citylife.communitypurchaseapp.view.camera.GraphicOverlay
            android:id="@+id/overlay"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </be.citylife.communitypurchaseapp.view.camera.CameraSourcePreview>

    <FrameLayout
        android:id="@+id/sideContainer"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="40"/>

</LinearLayout>

My tablet is in landscape and I want that the cameraPreviewSource is always left and fills the whole screen in the height and then right off it I’m having a fragment that fills the rest.

This layout works except my previewsource doesn’t fill the whole height (even though it shows correct in the preview). It has a black banner on it. Even my width is actually smaller than I want you can see this on the screenshot:

http://i61.tinypic.com/vctmw0.png

I played with the CameraSourcePreview with the width and height in the onLayout function but it doesn’t help.

Anyone an idea how to solve this?

EDIT:

I think there is a problem in the onLayout method off the CameraSourcePreview. That it doesn’t calculate it right when you use maybe layout weight or something I don’t know.

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Reactions: 1
  • Comments: 41 (4 by maintainers)

Commits related to this issue

Most upvoted comments

The following works, while also preserving the aspect ratio. This will slightly oversize the camera display, requiring cropping along one dimension. Change CameraSourcePreview.onLayout to:

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int previewWidth = 320;
        int previewHeight = 240;
        if (mCameraSource != null) {
            Size size = mCameraSource.getPreviewSize();
            if (size != null) {
                previewWidth = size.getWidth();
                previewHeight = size.getHeight();
            }
        }

        // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
        if (isPortraitMode()) {
            int tmp = previewWidth;
            previewWidth = previewHeight;
            previewHeight = tmp;
        }

        final int viewWidth = right - left;
        final int viewHeight = bottom - top;

        int childWidth;
        int childHeight;
        int childXOffset = 0;
        int childYOffset = 0;
        float widthRatio = (float) viewWidth / (float) previewWidth;
        float heightRatio = (float) viewHeight / (float) previewHeight;

        // To fill the view with the camera preview, while also preserving the correct aspect ratio,
        // it is usually necessary to slightly oversize the child and to crop off portions along one
        // of the dimensions.  We scale up based on the dimension requiring the most correction, and
        // compute a crop offset for the other dimension.
        if (widthRatio > heightRatio) {
            childWidth = viewWidth;
            childHeight = (int) ((float) previewHeight * widthRatio);
            childYOffset = (childHeight - viewHeight) / 2;
        } else {
            childWidth = (int) ((float) previewWidth * heightRatio);
            childHeight = viewHeight;
            childXOffset = (childWidth - viewWidth) / 2;
        }

        for (int i = 0; i < getChildCount(); ++i) {
            // One dimension will be cropped.  We shift child over or up by this offset and adjust
            // the size to maintain the proper aspect ratio.
            getChildAt(i).layout(
                    -1 * childXOffset, -1 * childYOffset,
                    childWidth - childXOffset, childHeight - childYOffset);
        }

        try {
            startIfReady();
        } catch (IOException e) {
            Log.e(TAG, "Could not start camera source.", e);
        }
    }

This is my code, no padding in portrait and fill right in landscape.

I use layoutHeight instead of childHeight in for (int i = 0; i < getChildCount(); ++i){…}

    if (mCameraSource != null)
    {
        Size size = mCameraSource.getPreviewSize();
        if (size != null)
        {
            width = size.getWidth();
            height = size.getHeight();
        }
    }

    // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
    if (isPortraitMode())
    {
        int tmp = width;

        //noinspection SuspiciousNameCombination
        width = height;
        height = tmp;
    }

    final int layoutWidth = right - left;
    final int layoutHeight = bottom - top;

    // Computes height and width for potentially doing fit width.
    int childWidth = layoutWidth;
    int childHeight = (int) (((float) layoutWidth / (float) width) * height);

    for (int i = 0; i < getChildCount(); ++i)
    {
        getChildAt(i).layout(0, 0, childWidth, layoutHeight);
    }

    try
    {
        startIfReady();
    }
    catch (SecurityException se)
    {
        Log.e(TAG, "Do not have permission to start the camera", se);
    }
    catch (IOException e)
    {
        Log.e(TAG, "Could not start camera source.", e);
    }
}

Hi, Comment or remove below lines from CameraSourcePreview and it should be fine. I was having same issue like you and it is solved now.

if (childHeight > layoutHeight) {
    childHeight = layoutHeight;
    childWidth = (int)(((float) layoutHeight / (float) height) * width);
}

This is how I fixed it. And it works perfectly in portrait and landscape modes, full screen.

@Override protected void onLayout (boolean changed, int left, int top, int right, int bottom) { int width = getWidth(); int height = getHeight();

    if (mCameraSource != null) {
        Size size = mCameraSource.getPreviewSize();
        if (size != null) {
            width = size.getWidth();
            height = size.getHeight();
        }
    }

    int layoutWidth = right - left;
    int layoutHeight = bottom - top;

    // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
    if (isPortraitMode()) {
        int tmp = width;
        //noinspection SuspiciousNameCombination
        width = height;
        height = tmp;
    }

    int childWidth = layoutWidth;
    int childHeight = (int) (((float) layoutWidth / (float) width) * height);

    if (isPortraitMode()) {
        childHeight = layoutHeight;
        childWidth = (int) (((float) layoutHeight / (float) height) * width);
    }

    for (int i = 0; i < getChildCount(); ++i) {
        getChildAt(i).layout(0, 0, childWidth, childHeight);
    }

    try {
        startIfReady();
    }
    catch (SecurityException se) {
    }
}

Hi all, this is my solution and It worked on SS Note 3, Moto G. I hope it is useful for you in BarcodeCaptureActivity.java - line 204

DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        Log.e(TAG, "widthPixels: " + metrics.widthPixels + " -- metrics: " + metrics.heightPixels);
        CameraSource.Builder builder = new CameraSource.Builder(getApplicationContext(), barcodeDetector)
                .setFacing(CameraSource.CAMERA_FACING_BACK)
                .setRequestedPreviewSize(metrics.heightPixels, metrics.widthPixels)
                .setRequestedFps(15.0f);

in CameraSourcePreview.java - replace childWidth, childHeight by width, height

for (int i = 0; i < getChildCount(); ++i) {
            getChildAt(i).layout(0, 0, width, height);
       }

The following works, while also preserving the aspect ratio. This will slightly oversize the camera display, requiring cropping along one dimension. Change CameraSourcePreview.onLayout to:

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        int previewWidth = 320;
        int previewHeight = 240;
        if (mCameraSource != null) {
            Size size = mCameraSource.getPreviewSize();
            if (size != null) {
                previewWidth = size.getWidth();
                previewHeight = size.getHeight();
            }
        }

        // Swap width and height sizes when in portrait, since it will be rotated 90 degrees
        if (isPortraitMode()) {
            int tmp = previewWidth;
            previewWidth = previewHeight;
            previewHeight = tmp;
        }

        final int viewWidth = right - left;
        final int viewHeight = bottom - top;

        int childWidth;
        int childHeight;
        int childXOffset = 0;
        int childYOffset = 0;
        float widthRatio = (float) viewWidth / (float) previewWidth;
        float heightRatio = (float) viewHeight / (float) previewHeight;

        // To fill the view with the camera preview, while also preserving the correct aspect ratio,
        // it is usually necessary to slightly oversize the child and to crop off portions along one
        // of the dimensions.  We scale up based on the dimension requiring the most correction, and
        // compute a crop offset for the other dimension.
        if (widthRatio > heightRatio) {
            childWidth = viewWidth;
            childHeight = (int) ((float) previewHeight * widthRatio);
            childYOffset = (childHeight - viewHeight) / 2;
        } else {
            childWidth = (int) ((float) previewWidth * heightRatio);
            childHeight = viewHeight;
            childXOffset = (childWidth - viewWidth) / 2;
        }

        for (int i = 0; i < getChildCount(); ++i) {
            // One dimension will be cropped.  We shift child over or up by this offset and adjust
            // the size to maintain the proper aspect ratio.
            getChildAt(i).layout(
                    -1 * childXOffset, -1 * childYOffset,
                    childWidth - childXOffset, childHeight - childYOffset);
        }

        try {
            startIfReady();
        } catch (IOException e) {
            Log.e(TAG, "Could not start camera source.", e);
        }
    }

Very nice, work perfectly, Thanks!!

This is how I fixed it .first comment this if (childHeight > layoutHeight) { childHeight = layoutHeight; childWidth = (int)(((float) layoutHeight / (float) height) * width); } Then set int childHeight=layoutHieght; Work in orientation Landscape and Portrait .

@UserSty having the preview centered on the display then cropped a little on the borders make more sense than having it “pinned” on the top left corner then loosing a bigger part on the right|bottom borders of the preview. Your users are going to point the camera onto the “object” they want the detection to happen. Naturally, they are going to place it in the middle of the screen. In that case, the @pm0733464 's solution simply makes more sense 😉