Click here to Skip to main content
15,886,199 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am building a Barcode scanner app & the issue I am facing is that I have drawn a rectangle on the camera preview and I want to crop the rectangle from the bitmap.But the thing is whenever I do that I get an error saying : x+width < btmp.width

I have marked the point where I am getting the error,can you please see what is wrong here.

Below is my code :

<pre><?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


   <androidx.camera.view.PreviewView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/previewView_main">
   </androidx.camera.view.PreviewView>


</FrameLayout>



MainActivity.java


package com.deepesh.testapp;

import static android.content.ContentValues.TAG;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.media.Image;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.util.Size;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.vision.barcode.Barcode;
import com.google.mlkit.vision.barcode.BarcodeScanner;
import com.google.mlkit.vision.barcode.BarcodeScanning;
import com.google.mlkit.vision.common.InputImage;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    PreviewView previewView_main;
    ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    CameraSelector cameraSelector;
    Preview preview;
    ProcessCameraProvider cameraProvider;
    ExecutorService cameraExecutor;
    private final int CAMERA_REQUEST_CODE = 101;

    // Coordinates of rectangular box,these will be
    // used to crop the scanning region.
    public static int LEFT, TOP, RIGHT, BOTTOM;

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        previewView_main = findViewById(R.id.previewView_main);
        cameraExecutor = Executors.newSingleThreadExecutor();
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();
        preview = new Preview.Builder().build();

        try {
            cameraProvider = cameraProviderFuture.get();
        } catch (ExecutionException | InterruptedException e) {
            // This should never be reached.
        }

        ask_permissions();

    }


    //=============================================================================

    private void load_camera_preview() {

        cameraProviderFuture.addListener(() -> {
            bindPreview(cameraProvider);
        }, ContextCompat.getMainExecutor(this));

        draw_preview_rectangle();

    }

    private void bindPreview(ProcessCameraProvider cameraProvider) {

        preview.setSurfaceProvider(previewView_main.getSurfaceProvider());

        // ImageAnalysis for processing camera preview frames
        ImageAnalysis imageAnalysis =
                new ImageAnalysis.Builder()
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                        //.setTargetResolution(new Size(1280, 720))
                        .build();

        imageAnalysis.setAnalyzer(cameraExecutor, new ImageAnalysis.Analyzer() {
            @Override
            public void analyze(@NonNull ImageProxy image) {

                // preparing input image
                @SuppressLint("UnsafeOptInUsageError")
                Image mediaImage = image.getImage();

                if (mediaImage != null) {

                    // convert Image to Bitmap
                    Bitmap bmp = ImageToBitmap(mediaImage);
                    Log.d(TAG, "LEFT : " + LEFT);
                    Log.d(TAG, "TOP : " + TOP);
                    Log.d(TAG, "RIGHT : " + RIGHT);
                    Log.d(TAG, "BOTTOM : " + BOTTOM);
                    Log.d(TAG, "Btmp Height : " + bmp.getHeight());
                    Log.d(TAG, "Btmp Width : " + bmp.getWidth());

                    // Cropping Bitmap image so that we scan only the
                    // image inside the rectangular box

                    /**  GETTING AN ERROR ON THIS STEP

                     bmp = Bitmap.createBitmap(bmp,LEFT,TOP,RIGHT,BOTTOM);

                     **/


                    // convert Bitmap to InputImage since API takes only InputImage type.
                    InputImage inputImage = InputImage.fromBitmap(bmp, image.getImageInfo().getRotationDegrees());
                    scan_barcode(inputImage);
                }

                image.close();
            }
        });


        cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);

    }


    // Scans input image for barcode and does required actions
    private void scan_barcode(InputImage inputImage) {



    }


    private void ask_permissions() {

        // asks camera permission to the user.
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) !=
                PackageManager.PERMISSION_GRANTED) {
            String[] permissions = {Manifest.permission.CAMERA};
            ActivityCompat.requestPermissions(this, permissions, CAMERA_REQUEST_CODE);
        }

        // if permission already granted then load camera preview
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
                PackageManager.PERMISSION_GRANTED) {
            load_camera_preview();
        }

    }

    // Called when a request permission is denied or accepted.
    // Load camera preview in both cases
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == CAMERA_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            load_camera_preview();
        } else {
            load_camera_preview();
        }
    }


    //=============================================================================

    public class Box extends View {
        private Paint paint = new Paint();

        Box(Context context) {
            super(context);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            // Override the onDraw() Method
            super.onDraw(canvas);

            paint.setStyle(Paint.Style.STROKE);
            paint.setColor(Color.GREEN);
            paint.setStrokeWidth(2);

            // center coordinates of canvas
            int x = getWidth()/2;
            int y = getHeight()/2;

            // Top left and Bottom right coordinates of rectangle
            int x_topLeft = x-(getWidth()/4);
            int y_topLeft = y-(getHeight()/4);
            int x_bottomRight = x+(getWidth()/4);
            int y_bottomRight = y+(getHeight()/10);

            LEFT = x_topLeft;
            RIGHT = x_bottomRight;
            TOP = y_topLeft;
            BOTTOM = y_bottomRight;

            //draw guide box
            canvas.drawRect(LEFT, TOP, RIGHT, BOTTOM, paint);

        }
    }


    private void draw_preview_rectangle() {

        Box box = new Box(this);
        addContentView(box, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));

    }

    //===========================================================================

    private void vibrate_device() {

        final VibrationEffect vibrationEffect1;
        // get the VIBRATOR_SERVICE system service
        final Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

        // this is the only type of the vibration which requires system version Oreo (API 26)
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

            // this effect creates the vibration
            vibrationEffect1 = VibrationEffect.createOneShot(300, VibrationEffect.DEFAULT_AMPLITUDE);

            // it is safe to cancel other vibrations currently taking place
            vibrator.cancel();
            vibrator.vibrate(vibrationEffect1);
        }
    }

    // Converts Image to Bitmap
    private Bitmap ImageToBitmap(Image image) {
        Image.Plane[] planes = image.getPlanes();
        ByteBuffer yBuffer = planes[0].getBuffer();
        ByteBuffer uBuffer = planes[1].getBuffer();
        ByteBuffer vBuffer = planes[2].getBuffer();

        int ySize = yBuffer.remaining();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();

        byte[] nv21 = new byte[ySize + uSize + vSize];
        //U and V are swapped
        yBuffer.get(nv21, 0, ySize);
        vBuffer.get(nv21, ySize, vSize);
        uBuffer.get(nv21, ySize + vSize, uSize);

        YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 75, out);

        byte[] imageBytes = out.toByteArray();
        return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    }

}


What I have tried:

i tried implementing it using other methods but this is the most efficient way i found.
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900