how to trim the area inside the rectangle in the preview of the camera

1

Hi, I have days trying to solve the following issue.

In the application that I am currently developing, I must cut the area inside the rectangle that I show in the perview of the camera as shown below.

What do I have?

the preview class

public class CapturePreview extends SurfaceView implements SurfaceHolder.Callback{

public static Bitmap mBitmap;
SurfaceHolder holder;
static Camera mCamera;
private final Paint paint;



public CapturePreview(Context context, AttributeSet attrs) {
    super(context, attrs);

    paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    paint.setColor(Color.WHITE);
    paint.setStyle(Paint.Style.STROKE);

    holder = getHolder();
    holder.addCallback(this);
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}


@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
    Camera.Parameters parameters = mCamera.getParameters();
    parameters.getSupportedPreviewSizes();
    mCamera.setParameters(parameters);
    mCamera.setDisplayOrientation(90);
    mCamera.startPreview();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera = Camera.open();
        mCamera.setPreviewDisplay(holder);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

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

public static void takeAPicture(){

    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {

            BitmapFactory.Options options = new BitmapFactory.Options();
            mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        }
    };
    mCamera.takePicture(null, null, mPictureCallback);
}

in my fragment tab1_framgent.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.ccsdeveloment.visitascontrol.CapturePreview
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

    <!-- overlay - customize padding and stuff  -->
    <View
        android:layout_width="600dp"
        android:layout_height="400dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="316dp"
        android:background="@drawable/rect"
        android:padding="32dp" />


</RelativeLayout>

Rect.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
    android:width="3dp"
    android:color="@color/colorPrimaryDark"
    android:dashGap="8dp"
    android:dashWidth="8dp" />
<corners android:radius="8dp" />
</shape>

What am I trying to do?

try to capture the photo either by a button or by ontouchevent only take the section inside the rectangle. I would like to know how this is possible and also if you can leave the rest of the area outside the rectangle a transparent shadow

a shading similar to this

Thanks in advance to those people who can help me I have been reading some questions in the Stackoverflow community in English I have tried some but I have not come up with a solution ... I understand or I think I understand that this is achieved with a surfaceview but not I understand its implementation well.

    
asked by carlos cupriher 14.01.2018 в 16:29
source

1 answer

0

Consider that: For this to work, you have to have the same aspect ratio of the preview, and the camera.

I'll tell you how I did it:

1 .- I do not know how this code works in the native Android API (Camera2), at least I tried it with the following library:  ( link ) It's basically the same as the google API, only at a more advanced level to simplify the use of the camera.

2 .- It is very important that you enter this line of code: cameraView.setCropOutput(true); With this you are telling the camera to cut the image to the same aspect ratio of the preview, this will will guarantee operation on any device.

The code would look something like this:

cameraView.setCropOutput(true);
    cameraView.addCameraListener(new CameraListener() {
        @Override
        public void onPictureTaken(byte[] jpeg) {
            super.onPictureTaken(jpeg);
            Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length);
            int previewWidth = cameraView.getWidth();
            int previewHeight = cameraView.getHeight();
            int sizeImgX = bitmap.getWidth();
            int sizeImgY = bitmap.getHeight();
            float scaleX = ((float) (sizeImgX) / (float) (previewWidth)); 
            float scaleY = ((float) (sizeImgY) / (float) (previewHeight));
            int width = v.getWidth();      
            int height = v.getHeight();     
            int[] location = new int[2];
            v.getLocationInWindow(location);   
            int locationAtImageX = (int) (scaleX * location[0]);
            int locationAtImageY = (int) (scaleY * location[1]);
            int widthAtImageX = (int) (scaleX * width);
            int heightAtImageY = (int) (scaleY * height);
            Bitmap imagenOriginal = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length);
            Matrix rotationMatrix = new Matrix();
            rotationMatrix.postRotate(0);
            Bitmap imagenCortada = Bitmap.createBitmap(imagenOriginal, locationAtImageX, locationAtImageY, widthAtImageX, heightAtImageY, rotationMatrix, false);
        }
    });

I'll explain: First you must convert the array of bytes to a bitmap:

bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length);

You get the dimensions of the preview:

int previewWidth = cameraView.getWidth();
int previewHeight = cameraView.getHeight();

You get the dimensions of the image:

int sizeImgX = bitmap.getWidth();
int sizeImgY = bitmap.getHeight();

Afterwards you get the scale of the image with respect to the preview:

float scaleX = ((float) (sizeImgX) / (float) (previewWidth));
float scaleY = ((float) (sizeImgY) / (float) (previewHeight));

You get the dimensions of the rectangle you want to trim:

int width = v.getWidth();       
int height = v.getHeight(); 

Where 'v' is the rectangle and it is a View type object, in the layout I have it as follows:

<View
        android:id="@+id/rectangle_focus"
        android:layout_width="200dp"
        android:layout_height="300dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="50dp"
        android:background="@drawable/camera_rectangle_preview" />

Then you get the location of the rectangle in the window:

int[] location = new int[2];
v.getLocationInWindow(location);   

And you multiply that location by the scale (this will be the starting position from where you have to start cutting the image):     int locationAtImageX = (int) (scaleX * location [0]);     int locationAtImageY = (int) (scaleY * location 1 );

You also need to get the size that should be cut in X and Y

int widthAtImageX = (int) (scaleX * width);
int heightAtImageY = (int) (scaleY * height);

Finally you are going to get the cropped image in a bitmap using the following lines:

Matrix rotationMatrix = new Matrix();
                rotationMatrix.postRotate(0);
                Bitmap imagenCortada = Bitmap.createBitmap(imagenOriginal, locationAtImageX, locationAtImageY, widthAtImageX, heightAtImageY, rotationMatrix, false);

Final result:

I hope you work, greetings!

    
answered by 16.01.2018 / 16:50
source