0

I am trying to create an app which captures some x*y sized rectangular portion from the camera view. To achieve that I have been to many threads but none of them seems to be working as required.

Basically what i want to achieve is as shown:

enter image description here

My requirement is when i open camera there should be a rectangular highlighted bright part on the screen and the rest of the screen should look black translucent displaying the rest of the camera view but when user clicks the button then the camera should only click the highlighted brighten part of the screen.

I am trying thisCustom camera android thread but it is not displaying the rest of the part as translucent. It only shows whatever comes under the surfaceview.

Now what i have done is using another surface view on top of it but now it is clicking the previous portion of the surface not the current one.

So please give me some advice to achieve the same.

My Activity code:

package com.example.cameraapplication;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.IOException;

public class CameraActivity extends Activity implements Camera.PictureCallback, SurfaceHolder.Callback {

    public static final String EXTRA_CAMERA_DATA = "camera_data";

    private static final String KEY_IS_CAPTURING = "is_capturing";

    private Camera mCamera, dummyCamera;
    private ImageView mCameraImage;
    private SurfaceView mCameraPreview,s1;
    private Button mCaptureImageButton;
    private byte[] mCameraData;
    private boolean mIsCapturing;
    private View v1;

    private View.OnClickListener mCaptureImageButtonClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            try {
                mCamera.stopPreview();
                mCamera.setPreviewDisplay(mCameraPreview.getHolder());
                mCamera.startPreview();
                captureImage();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    };

    private View.OnClickListener mRecaptureImageButtonClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            setupImageCapture();
        }
    };

    private View.OnClickListener mDoneButtonClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (mCameraData != null) {
                Intent intent = new Intent();
                intent.putExtra(EXTRA_CAMERA_DATA, mCameraData);
                setResult(RESULT_OK, intent);
            } else {
                setResult(RESULT_CANCELED);
            }
            finish();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_camera);

        mCameraImage = (ImageView) findViewById(R.id.camera_image_view);
        mCameraImage.setVisibility(View.INVISIBLE);
        v1 = findViewById(R.id.v1);

        mCameraPreview = (SurfaceView) findViewById(R.id.preview_view);
        s1 = (SurfaceView) findViewById(R.id.preview_view_1);
        final SurfaceHolder surfaceHolder = mCameraPreview.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        mCaptureImageButton = (Button) findViewById(R.id.capture_image_button);
        mCaptureImageButton.setOnClickListener(mCaptureImageButtonClickListener);

        final Button doneButton = (Button) findViewById(R.id.done_button);
        doneButton.setOnClickListener(mDoneButtonClickListener);

        mIsCapturing = true;
    }

    @Override
    protected void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);

        savedInstanceState.putBoolean(KEY_IS_CAPTURING, mIsCapturing);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        mIsCapturing = savedInstanceState.getBoolean(KEY_IS_CAPTURING, mCameraData == null);
        if (mCameraData != null) {
            setupImageDisplay();
        } else {
            setupImageCapture();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (mCamera == null) {
            try {
                mCamera = Camera.open();
//                dummyCamera = mCamera;
                mCamera.setPreviewDisplay(s1.getHolder());
//                dummyCamera.setPreviewDisplay(s1.getHolder());
                if (mIsCapturing) {
//                    dummyCamera.startPreview();
                    mCamera.startPreview();
                }
            } catch (Exception e) {
                e.printStackTrace();
                Toast.makeText(CameraActivity.this, "Unable to open camera.", Toast.LENGTH_LONG)
                        .show();
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        mCameraData = data;
        setupImageDisplay();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mCamera != null) {
            try {
                mCamera.setPreviewDisplay(mCameraPreview.getHolder());
//                dummyCamera.setPreviewDisplay(s1.getHolder());
                if (mIsCapturing) {
                    mCamera.startPreview();
//                    dummyCamera.startPreview();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(CameraActivity.this, "Unable to start camera preview.", Toast.LENGTH_LONG).show();
            }
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

    private void captureImage() {
        mCamera.takePicture(null, null, this);
    }

    private void setupImageCapture() {
        try {
            mCameraImage.setVisibility(View.INVISIBLE);
            mCameraPreview.setVisibility(View.VISIBLE);
            s1.setVisibility(View.VISIBLE);
            v1.setVisibility(View.VISIBLE);
            mCamera.setPreviewDisplay(s1.getHolder());
            mCamera.startPreview();
            mCaptureImageButton.setText(R.string.capture_image);
            mCaptureImageButton.setOnClickListener(mCaptureImageButtonClickListener);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void setupImageDisplay() {
        Bitmap bitmap = BitmapFactory.decodeByteArray(mCameraData, 0, mCameraData.length);
        mCameraImage.setImageBitmap(bitmap);
        mCamera.stopPreview();
        mCameraPreview.setVisibility(View.INVISIBLE);
        s1.setVisibility(View.INVISIBLE);
        v1.setVisibility(View.INVISIBLE);
        mCameraImage.setVisibility(View.VISIBLE);
        mCaptureImageButton.setText(R.string.recapture_image);
        mCaptureImageButton.setOnClickListener(mRecaptureImageButtonClickListener);
    }
}

Layout file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:background="@android:color/transparent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/capturing_image" />

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

        <com.edmodo.cropper.CropImageView
            android:id="@+id/camera_image_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />

        <!--        <ImageView-->
        <!--            android:id="@+id/camera_image_view"-->
        <!--            android:layout_width="match_parent"-->
        <!--            android:layout_height="match_parent" />-->

        <SurfaceView
            android:id="@+id/preview_view_1"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <View
            android:id="@+id/v1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#CCFFFFFF"/>

        <SurfaceView
            android:id="@+id/preview_view"
            android:layout_margin="80dp"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

<!--        <com.example.cameraapplication.CropOverlayNew-->
<!--            android:id="@+id/cropper"-->
<!--            android:layout_width="match_parent"-->
<!--            android:layout_height="match_parent"/>-->

        <!--        <LinearLayout-->
        <!--            android:layout_width="match_parent"-->
        <!--            android:background="@android:color/transparent"-->
        <!--            android:layout_height="match_parent">-->
        <!--            -->
        <!--        </LinearLayout>-->


    </FrameLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/capture_image_button"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:text="@string/capture_image" />

        <Button
            android:id="@+id/done_button"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:text="@string/done" />
    </LinearLayout>

</LinearLayout>
Cosmic Dev
  • 522
  • 6
  • 20
  • Your layout shows two SurfaceView instances. What's the purpose? – Alex Cohn May 13 '20 at 12:22
  • @AlexCohn The purpose is to capture the view inside "preview_view" but display the view inside "preview_view_1" to user. Basically "preview_view_1" covers whole width of the screen and "preview_view" covers a rectangular part of the screen. – Cosmic Dev May 14 '20 at 03:56
  • This cannot work as you wish it. But first, let me understand why you are using the old, deprecated Camera API? I would strongly recommend to move to the new [cameraX API](https://developer.android.com/training/camerax) which is an easiest and cleanest way to work with Android camera these days. – Alex Cohn May 14 '20 at 09:26
  • So with this new camera API can work according to my requirement? – Cosmic Dev May 15 '20 at 07:22
  • I don't really understand what your requirement is, but the question should read "how can I do *{whatever you need to do}* with the new camera API". The old camera API is relevant only for apps that must run solely (or mostly) on old devices, and cannot use the compatibility wrappers. – Alex Cohn May 15 '20 at 11:17
  • The preview part is possible with any camera API, but with the old API it's better to use `setPreviewTexture()`. Now you can overlay a partially transparent PNG over the camera preview surface, and leave a fully transparent rectangular hole where you need the bright highlight. This is how I answered a similar question some while ago: https://stackoverflow.com/a/47240902/192373. – Alex Cohn May 15 '20 at 11:45
  • that's not what i mean, I had to display input from camera to full screen but i have to capture only some part of the screen say a rectangular box in center of the screen – Cosmic Dev May 15 '20 at 11:49
  • To crop the picture (taken with `takePicture()` or her modern equivalents), you don't have support of the camera API. As I explained [once](https://stackoverflow.com/a/47963776/192373), this can be done either though manipulation of a Jpeg image, or by grabbing the (lower resolution) preview frame. A longer description of a similar task can be found [here](https://dropbox.tech/machine-learning/augmented-camera-previews-for-the-dropbox-android-document-scanner). – Alex Cohn May 15 '20 at 11:53

0 Answers0