2

I am using camera 2. I want to customize the surface view height and width. I am using the following code.

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_blue_dark">
    <TextureView
        android:id="@+id/texture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>

Java Code:

protected void createCameraPreview() {
        try {
            SurfaceTexture texture = textureView.getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());
            Surface surface = new Surface(texture);
            captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureRequestBuilder.addTarget(surface);
            cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback(){
                @Override
                public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                    //The camera is already closed
                    if (null == cameraDevice) {
                        return;
                    }
                    // When the session is ready, we start displaying the preview.
                    cameraCaptureSessions = cameraCaptureSession;
                    updatePreview();
                }
                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(MainActivity.this, "Configuration change", Toast.LENGTH_SHORT).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

I want to show only 400dp of the surface view. But the whole height is shrinked and displaying in the surface view.

Expected OP: enter image description here

But I am getting following OP:

enter image description here

How to show only 400dp of camera view in the surface view.

I tried the Soution. But I am not getting the expected result.

private void updateTextureMatrix(int width, int height) { // 200, 200
    int previewWidth =  getScreenWidth(); //720
    int previewHeight = getScreenHeight(); // 1280

    float ratioSurface = (float) width / height; // 1.0
    float ratioPreview = (float) previewWidth / previewHeight; // 0.5625

    float scaleX; float scaleY;

    if (ratioSurface > ratioPreview) { //(0.5625 > 1.0)
        scaleX = (float) height / previewHeight; // 0.15625
        scaleY = 1; 
    } else {
        scaleX = 1;
        scaleY = (float) width / previewWidth;
    }

    Matrix matrix = new Matrix();

    matrix.setScale(scaleX, scaleY); //(0.15625 , 1.0)
    textureView.setTransform(matrix);

    float scaledWidth = width * scaleX; // 31.25
    float scaledHeight = height * scaleY; // 200.0

    float dx = (width - scaledWidth) / 2; // 84.375
    float dy = (height - scaledHeight) / 2; // 0.00
    textureView.setTranslationX(dx);
    textureView.setTranslationY(dy);
}

I am getting the following result.

enter image description here

I gave 200 width and 200 height. But not getting expected result. And also camera view also getting stretched.

  • So, you want to show only 400dp of the actual camera capture, right? But it's showing you all the capturing within 400dp. Is that what you want to say? – Dev4Life May 19 '23 at 04:20
  • @Dev4Life.. Yes.. Correct. Want to change the preview height and width and margin based on the configuration and need to capture the image based on the configuration – Vijayadhas Chandrasekaran May 19 '23 at 06:36
  • @Dev4Life.. Do you have any solution for this?? – Vijayadhas Chandrasekaran May 20 '23 at 05:30
  • Check [Crop Camera Preview for Textureview](https://stackoverflow.com/questions/17019588/crop-camera-preview-for-textureview). That solution uses matrix transforms to scale and translate the preview within the TextureView. You can also use `myTextureView.getWidth()` and `.getHeight()` and then create a cropped image based on the reported TextureView size at the time of display. – G. Putnam May 20 '23 at 23:23
  • @VijayadhasChandrasekaran I got your scenario, but I don't have a proper solution to it yet. – Dev4Life May 22 '23 at 03:40
  • @G.Putnam.. Yes. I tried that. But I am not getting the expected result. I will update the result in the original question. – Vijayadhas Chandrasekaran May 22 '23 at 17:27
  • Could you do a quick dump of width / height, previewWidth / previewHeight, scaleX / scaleY, so we have an idea of what it believes its scaling to? Also, other check, have the TextureView start with an obviously different color to see if its only filling a tiny area, or the whole TextureView is squished? Based on images from [here](https://stackoverflow.com/questions/69935627/flutter-test-driver-tap-on-camera-button-in-android-emulator) it looks like its drawing the whole scene (should be based on the code provided) and scaling it wrong. – G. Putnam May 22 '23 at 23:16
  • @G.Putnam I have modified the code with value and the screenshot with background color – Vijayadhas Chandrasekaran May 23 '23 at 06:48
  • There's a couple things weird here. (0.5625 !(is not) > 1.0) Also, you're mixing up surface and preview. The original inputs width, height are the surface you're drawing to. The preview is the camera preview. In the example reference, this was set by checking the available sizes of preview supported by the camera. Finally, your TextureView appears to be almost the full screen, not a 200 width box (or 400 like originally asked) (the reason I asked for the background color). Looking at scaleX / scaleY, it should be apparent why its drawing wrong. Fill 15.6% in width, fill 100% in height. – G. Putnam May 23 '23 at 17:08
  • @G.Putnam I explain my understanding till now. Please correct if I am wrong. TextureView the parent layout. Sufaceview is the child of TextureView. So now I gave 200 width and height for the TextureView. Now I set the surfaceView height and width with the following code. `surfaceTexture.setDefaultBufferSize(imageDimension.getWidth(), imageDimension.getHeight());`. Now we need to set the preview height and width. Here I don't know how to set the preview size. Can you help me on this? – Vijayadhas Chandrasekaran May 25 '23 at 08:36

1 Answers1

0

Finally come up with the following solution. Parent layout width and height is 400. And texture view height and with as screen height and screen width.

<FrameLayout
        android:id="@+id/parent_layout"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:background="@android:color/holo_blue_dark">
        <com.example.camerasample.AutoFitTextureView
            android:id="@+id/texture"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </FrameLayout>

Java Code:

textureView.setLayoutParams(new FrameLayout.LayoutParams(getScreenWidth(),getScreenHeight()));

And finally crop the image after taking photo using the following code.

private byte[] cropImage(Bitmap bitmap, View textureView, View parentView) {

        int heightOriginal = textureView.getHeight();
        int widthOriginal = textureView.getWidth();
        int heightFrame = parentView.getHeight();
        int widthFrame = parentView.getWidth();
        int leftFrame = parentView.getLeft();
        int topFrame = parentView.getTop();
        int heightReal = bitmap.getHeight();
        int widthReal = bitmap.getWidth();
        int widthFinal = widthFrame * widthReal / widthOriginal;
        int heightFinal = heightFrame * heightReal / heightOriginal;
        int leftFinal = leftFrame * widthReal / widthOriginal;
        int topFinal = topFrame * heightReal / heightOriginal;
        Bitmap bitmapFinal = Bitmap.createBitmap(
                bitmap,
                leftFinal, topFinal, widthFinal, heightFinal
        );
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        bitmapFinal.compress(
                Bitmap.CompressFormat.JPEG,
                100,
                stream
        );
        return stream.toByteArray();
    }