How to change area of scan Zbar?
Asked Answered
W

1

13

I want to change the area of camera scan. Now I take image to scan as big as screen of device. I'm trying to crop image to analyze. So just the center of preview will be source to scan. Is there any option to set captured preview to be smaller or creating Bitmap from byte[] data and crop it is the only way to get smaller area? I was trying to read something about it but documentation for Zbar Android is very poor (comparing to iOS).

Picture here: https://postimg.cc/image/4wk4u0mln/

MainActivity

public class MainActivity extends Activity
{
    private Camera mCamera;
    private Context context;
    private CameraPreview mPreview;
    private Handler autoFocusHandler;

    TextView scanText;
    Button scanButton;

    ImageScanner scanner;
    private PowerManager.WakeLock wl;

    private boolean barcodeScanned = false;
    private boolean previewing = true;

    static {
        System.loadLibrary("iconv");
    } 

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



        setContentView(R.layout.activity_main);

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        autoFocusHandler = new Handler();
        mCamera = getCameraInstance();


        context = getApplicationContext();

        /* Instance barcode scanner */
        scanner = new ImageScanner();

        scanner.setConfig(0, Config.X_DENSITY, 3);
        scanner.setConfig(0, Config.Y_DENSITY, 3);

        mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
        FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
        preview.addView(mPreview);

        scanText = (TextView)findViewById(R.id.scanText);


    }

    @Override
    public void onPause() {
        super.onPause();
        releaseCamera();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub

        onStart();
    }

    @Override
    protected void onStop() {
        // TODO Auto-generated method stub
        super.onStop();

        finish();
    }

    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open();
        } catch (Exception e){
        }
        return c;
    }

    private void releaseCamera() {
        if (mCamera != null) {
            previewing = false;
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    private Runnable doAutoFocus = new Runnable() {
            @Override
            public void run() {
                if (previewing)
                    mCamera.autoFocus(autoFocusCB);
            }
        };

    PreviewCallback previewCb = new PreviewCallback() {
            @Override
            public void onPreviewFrame(byte[] data, Camera camera) {
                Camera.Parameters parameters = camera.getParameters();
                Size size = parameters.getPreviewSize();
                //HERE we read taken picture from prieview
                Image barcode = new Image(size.width, size.height, "Y800");

                barcode.setData(data);


                int result = scanner.scanImage(barcode);

                if (result != 0) {
                    previewing = false;
                    mCamera.setPreviewCallback(null);


                    mCamera.stopPreview();



                    SymbolSet syms = scanner.getResults();
                    for (Symbol sym : syms) {

                    if (sym.getType() == Symbol.CODE128) {
                        sym.getData());
                        MediaPlayer mp = MediaPlayer.create(context, R.raw.beep_ok); 
                        mp.start();


                    } else {

                        MediaPlayer mp = MediaPlayer.create(context, R.raw.beep_wrong); 
                        mp.start();
                    }


                        mCamera.setPreviewCallback(previewCb);
                        mCamera.startPreview();
                        previewing = true;
                        mCamera.autoFocus(autoFocusCB);



                    }
                }
            }
        };

    // Mimic continuous auto-focusing
    AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                autoFocusHandler.postDelayed(doAutoFocus, 1000);
            }
        };


        //Method to crop Bitmap in case of use
        public Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
            int sourceWidth = source.getWidth();
            int sourceHeight = source.getHeight();

            float xScale = (float) newWidth / sourceWidth;
            float yScale = (float) newHeight / sourceHeight;
            float scale = Math.max(xScale, yScale);

            float scaledWidth = scale * sourceWidth;
            float scaledHeight = scale * sourceHeight;

            float left = (newWidth - scaledWidth) / 2;
            float top = (newHeight - scaledHeight) / 2;

            RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);


            Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
            Canvas canvas = new Canvas(dest);
            canvas.drawBitmap(source, null, targetRect, null);

            return dest;
        }

}

CameraPrieview.java

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private PreviewCallback previewCallback;
    private AutoFocusCallback autoFocusCallback;

    public CameraPreview(Context context, Camera camera,
                         PreviewCallback previewCb,
                         AutoFocusCallback autoFocusCb) {
        super(context);
        mCamera = camera;
        previewCallback = previewCb;
        autoFocusCallback = autoFocusCb;

        /* 
         * Set camera to continuous focus if supported, otherwise use
         * software auto-focus. Only works for API level >=9.
         */
        /*
        Camera.Parameters parameters = camera.getParameters();
        for (String f : parameters.getSupportedFocusModes()) {
            if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
                mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                autoFocusCallback = null;
                break;
            }
        }
        */

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
        } catch (IOException e) {
            Log.d("DBG", "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Camera preview released in activity
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        /*
         * If your preview can change or rotate, take care of those events here.
         * Make sure to stop the preview before resizing or reformatting it.
         */
        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        try {
            // Hard code camera surface rotation 90 degs to match Activity view in portrait
            mCamera.setDisplayOrientation(90);

            mCamera.setPreviewDisplay(mHolder);
            mCamera.setPreviewCallback(previewCallback);
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCallback);
        } catch (Exception e){
            Log.d("DBG", "Error starting camera preview: " + e.getMessage());
        }
    }
}
Weal answered 20/9, 2013 at 13:37 Comment(1)
Hi user2245026! I'm searching for the same. Did you got any possible solution for this.Belenbelesprit
B
19

In the PreviewCallback you can actually crop the scanning area. In the onPreviewFrame method, after calling barcode.setData() you can call barcode.setCrop(left,top,width,height). All measurements in pixels.
Also make sure to set the crop size with respect to the preview image size and not the device screen size.

Note: Please make sure that the x-axis is always the longest side even though you orient the phone in portrait mode. Please refer below Image for better understanding of the arguments.

This solution is specific to zbar for android.

illustration of of scanning area in zbar

Bricklayer answered 21/1, 2014 at 12:28 Comment(6)
Hi there--do you know how left/top/width/height are determined? Are they percentages of the screen size or pixels?Loaf
what is the measurment of every parameter ? Is it dpi ? or pixel ? or else ?Lament
@Lament - All measurements are in pixels. I've edited the answer with units.Bricklayer
thanks & +1 for you sir, now it makes it clear. And the measurement is based on the captured image size, not the size of preview on the screen right ?Lament
@Lament - Yes. It is based on the image size.Bricklayer
It is a good answer, but in my case all coordinates in reflection, so I spent a lot of time for understanding this.Edema

© 2022 - 2024 — McMap. All rights reserved.