1

This is pertaining the google vision API. The CameraPreview works well for full Screen. But the image is distorted when previewing the camera in a box.

This is the code I have used. My problem is that the preview fills up the box but the preview is stretched and I am not able to adjust the size of the cameraPreview. The variable CameraPreview is of type SurfaceView. I use a CameraSource to start the preview. Is there any way to change the size of the CameraPreview(SurfaceView) and make the preview crop fit in a box?

  cameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
            protected List<Camera.Size> mPreviewSizeList;
            protected List<Camera.Size> mPictureSizeList;
            protected Camera.Size mPreviewSize;
            protected Camera.Size mPictureSize;
            protected boolean mSurfaceChanged = false;
            private int mSurfaceChangedCallDepth = 0;
            private int mCenterPosX = -1;
            private int mCenterPosY = 0;
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(ClientIdScannerActivity.this,
                            new String[]{Manifest.permission.CAMERA}, RequestCameraPermissionId);
                    Toast.makeText(ClientIdScannerActivity.this, "The App requires this permission", Toast.LENGTH_SHORT).show();
                    return;
                }
                try {
                    cameraSource.start(cameraPreview.getHolder());
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
                mSurfaceChangedCallDepth++;

             /*   cameraSource.stop();

                Camera.Parameters cameraParams = mCamera.getParameters();

                if (!mSurfaceChanged) {
                    Camera.Size previewSize = determinePreviewSize(cameraWidth, cameraHight);
                    Camera.Size pictureSize = determinePictureSize(previewSize);
                    mPreviewSize = previewSize;
                    mPictureSize = pictureSize;
                    mSurfaceChanged = adjustSurfaceLayoutSize(previewSize,i1, i2);

                    if (mSurfaceChanged && (mSurfaceChangedCallDepth <= 1)) {
                        return;
                    }
                }

                cameraParams.setRotation(270);
                if (UtilFunctions.isTablet()) {
                } else {
                    mCamera.setDisplayOrientation(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? 270 : 90);
                }*/

//            cameraParams.setRotation(270);
//            mCamera.setDisplayOrientation(UtilFunctions.isTablet() ? 90 : 270);

              /*  cameraParams.set("orientation", "portrait");
                //  cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
                cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height);
                if (cameraParams.getSupportedFocusModes().contains(
                        Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                    cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                }*/

                mSurfaceChanged = false;

                try {
                    if (ActivityCompat.checkSelfPermission(ClientIdScannerActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                        // TODO: Consider calling
                        //    ActivityCompat#requestPermissions
                        // here to request the missing permissions, and then overriding
                        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                        //                                          int[] grantResults)
                        // to handle the case where the user grants the permission. See the documentation
                        // for ActivityCompat#requestPermissions for more details.
                        Toast.makeText(ClientIdScannerActivity.this, "App requires Camera permission to scan ID", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    cameraSource.start(cameraPreview.getHolder());
                } catch (Exception e) {
                    // Remove failed size

                    // Reconfigure
                    if (mPreviewSizeList.size() > 0) { // prevent infinite loop
                        surfaceChanged(null, 0, i1, i2);
                    } else {
//                Utils.showToast(CameraNewActivity.this, "Can't start preview", Toast.LENGTH_LONG);
                    }
                }

                mSurfaceChangedCallDepth--;
            }

            protected Camera.Size determinePreviewSize(int reqWidth, int reqHeight) {

                int reqPreviewWidth = 640;//reqHeight; // requested width in terms of camera hardware
                int reqPreviewHeight = 480;// reqWidth; // requested height in terms of camera hardware
                Camera.Size retSize = null;
                for (Camera.Size size : mPreviewSizeList) {
                    if (size.width == reqPreviewWidth && size.height == reqPreviewHeight) {
                        retSize = size;
                    }
                }
                //  retSize = mPreviewSizeList.get(mPreviewSizeList.size()-1);
                return retSize;
            }

            protected Camera.Size determinePictureSize(Camera.Size previewSize) {
                Camera.Size retSize = null;
                for (Camera.Size size : mPictureSizeList) {
                    if (size.equals(previewSize)) {
                        return size;
                    }
                }

                // if the preview size is not supported as a picture size
                float reqRatio = ((float) previewSize.width) / previewSize.height;
                float curRatio, deltaRatio;
                float deltaRatioMin = Float.MAX_VALUE;
                for (Camera.Size size : mPictureSizeList) {
                    curRatio = ((float) size.width) / size.height;
                    deltaRatio = Math.abs(reqRatio - curRatio);
                    if (deltaRatio < deltaRatioMin) {
                        deltaRatioMin = deltaRatio;
                        retSize = size;
                    }
                }

                return retSize;
            }

            protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize,
                                                      int availableWidth, int availableHeight) {

                float tmpLayoutHeight = previewSize.width;
                float tmpLayoutWidth = previewSize.height;

                float factH, factW, fact;
                factH = availableHeight / tmpLayoutHeight;
                factW = availableWidth / tmpLayoutWidth;

//        if (factH < factW) {
//            fact = factH;
//        } else {
                fact = factW;
                //  }

                FrameLayout.LayoutParams layoutParams =(FrameLayout.LayoutParams) cameraPreview.getLayoutParams();
                int layoutHeight = (int) (tmpLayoutHeight * fact);
                int layoutWidth = (int) (tmpLayoutWidth * fact);

                boolean layoutChanged;
                if ((layoutWidth != cameraPreview.getWidth()) || (layoutHeight != cameraPreview.getHeight())) {
                    layoutParams.height = layoutHeight;
                    layoutParams.width = layoutWidth;
                    if (mCenterPosX >= 0) {
                        layoutParams.topMargin = mCenterPosY - (layoutHeight / 2);
                        layoutParams.leftMargin = mCenterPosX - (layoutWidth / 2);
                    }
                    cameraPreview.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation.
                    layoutChanged = true;
                } else {
                    layoutChanged = false;
                }

                return layoutChanged;
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
                cameraSource.stop();
            }
        });
V.Bhat
  • 63
  • 10
  • This code runs but with no effect. I was using the Camera variable before but have commented it because it isn't required any more. Which is my understanding. – V.Bhat Dec 05 '17 at 14:43

1 Answers1

0

Note that the same problem exists for 'full screen' camera preview. There is no guarantee that the aspect ratio of your chosen preview size will be close enough to the aspect ratio of the screen. Please see more details here: Camera Preview Stretched on Few Android Devices.

You naturally must choose the optimum width and height to fit the view, but this is not enough. You must hide the 'hanging' parts of your preview surface behind some non-transparent views. See for example how you can make a circular preview.

Another important thing here is to always keep preview- and picture- sizes in sync. This does not mean that they must be the same, but the aspect ratios should. Some devices have weird effects when the aspect ratio changes to capture a photo.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307