Scan barcode from an image in gallery android

我们两清 提交于 2019-12-03 03:09:44

You could use this class MultiFormatReader from ZXing library.

You have to get Gallery image in BitMap and convert it as this:

Bitmap bMap = [...];
String contents = null;

int[] intArray = new int[bMap.getWidth()*bMap.getHeight()];  
//copy pixel data from the Bitmap into the 'intArray' array  
bMap.getPixels(intArray, 0, bMap.getWidth(), 0, 0, bMap.getWidth(), bMap.getHeight());  

LuminanceSource source = new RGBLuminanceSource(bMap.getWidth(), bMap.getHeight(), intArray);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

Reader reader = new MultiFormatReader();
Result result = reader.decode(bitmap);
contents = result.getText();

UPDATE1

To manipulate big image, please have a look at :

https://developer.android.com/training/articles/memory.html

https://developer.android.com/training/displaying-bitmaps/manage-memory.html

You could use this property android:largeHeap to increase heap size.

I have a working sample on how to implement this, if you reading in 2016 here is how I did it:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    //initialize variables to make them global
    private ImageButton Scan;
    private static final int SELECT_PHOTO = 100;
  //for easy manipulation of the result
     public String barcode;

//call oncreate method
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //cast neccesary variables to their views
        Scan = (ImageButton)findViewById(R.id.ScanBut);

        //set a new custom listener
        Scan.setOnClickListener(this);
        //launch gallery via intent
        Intent photoPic = new Intent(Intent.ACTION_PICK);
        photoPic.setType("image/*");
        startActivityForResult(photoPic, SELECT_PHOTO);
    }

    //do necessary coding for each ID
    @Override
    public void onClick(View v) {
         switch (v.getId()){
             case R.id.ScanBut:
                 //launch gallery via intent
                 Intent photoPic = new Intent(Intent.ACTION_PICK);
                 photoPic.setType("image/*");
                 startActivityForResult(photoPic, SELECT_PHOTO);
                       break;
         }
    }

//call the onactivity result method
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
        super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
        switch (requestCode) {
            case SELECT_PHOTO:
                if (resultCode == RESULT_OK) {
//doing some uri parsing
                    Uri selectedImage = imageReturnedIntent.getData();
                    InputStream imageStream = null;
                    try {
                        //getting the image
                        imageStream = getContentResolver().openInputStream(selectedImage);
                    } catch (FileNotFoundException e) {
                        Toast.makeText(getApplicationContext(), "File not found", Toast.LENGTH_SHORT).show();
                        e.printStackTrace();
                    }
                    //decoding bitmap
                    Bitmap bMap = BitmapFactory.decodeStream(imageStream);
                    Scan.setImageURI(selectedImage);// To display selected image in image view
                    int[] intArray = new int[bMap.getWidth() * bMap.getHeight()];
                    // copy pixel data from the Bitmap into the 'intArray' array
                    bMap.getPixels(intArray, 0, bMap.getWidth(), 0, 0, bMap.getWidth(),
                            bMap.getHeight());

                    LuminanceSource source = new RGBLuminanceSource(bMap.getWidth(),
                            bMap.getHeight(), intArray);
                    BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));

                    Reader reader = new MultiFormatReader();// use this otherwise
                    // ChecksumException
                    try {
                        Hashtable<DecodeHintType, Object> decodeHints = new Hashtable<DecodeHintType, Object>();
                        decodeHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
                        decodeHints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);

                        Result result = reader.decode(bitmap, decodeHints);
         //*I have created a global string variable by the name of barcode to easily manipulate data across the application*//
                        barcode =  result.getText().toString();

                           //do something with the results for demo i created a popup dialog
                        if(barcode!=null){
                            AlertDialog.Builder builder = new AlertDialog.Builder(this);
                            builder.setTitle("Scan Result");
                            builder.setIcon(R.mipmap.ic_launcher);
                            builder.setMessage("" + barcode);
                            AlertDialog alert1 = builder.create();
                            alert1.setButton(DialogInterface.BUTTON_POSITIVE, "Done", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Intent i = new Intent (getBaseContext(),MainActivity.class);
                                    startActivity(i);
                                }
                            });

                            alert1.setCanceledOnTouchOutside(false);

                            alert1.show();}
                        else
                        {
                            AlertDialog.Builder builder = new AlertDialog.Builder(this);
                            builder.setTitle("Scan Result");
                            builder.setIcon(R.mipmap.ic_launcher);
                            builder.setMessage("Nothing found try a different image or try again");
                            AlertDialog alert1 = builder.create();
                            alert1.setButton(DialogInterface.BUTTON_POSITIVE, "Done", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Intent i = new Intent (getBaseContext(),MainActivity.class);
                                    startActivity(i);
                                }
                            });

                            alert1.setCanceledOnTouchOutside(false);

                            alert1.show();

                        }
                     //the end of do something with the button statement.

                    } catch (NotFoundException e) {
                        Toast.makeText(getApplicationContext(), "Nothing Found", Toast.LENGTH_SHORT).show();
                        e.printStackTrace();
                    } catch (ChecksumException e) {
                        Toast.makeText(getApplicationContext(), "Something weird happen, i was probably tired to solve this issue", Toast.LENGTH_SHORT).show();
                        e.printStackTrace();
                    } catch (FormatException e) {
                        Toast.makeText(getApplicationContext(), "Wrong Barcode/QR format", Toast.LENGTH_SHORT).show();
                        e.printStackTrace();
                    } catch (NullPointerException e) {
                        Toast.makeText(getApplicationContext(), "Something weird happen, i was probably tired to solve this issue", Toast.LENGTH_SHORT).show();
                        e.printStackTrace();
                    }
                }
        }
    }

}  

I'm in between of same scenario, where it throw NotFoundException, official doc says

Thrown when a barcode was not found in the image. It might have been partially detected but could not be confirmed.

First level solution at some extend @Laurent answer worked almost for every sample I have but failed for few.

Next level solution adding decodeHints before to reader.decode(..) suggested by @Lucien Mendela did the trick.

Hashtable<DecodeHintType, Object> decodeHints = new Hashtable<DecodeHintType, Object>();
decodeHints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); // Not required in my case
decodeHints.put(DecodeHintType.PURE_BARCODE, Boolean.TRUE);

But final things that worked for me

  • If you have big image you may have to scale down.
  • It also require a ~rectangle shape (421*402 in my case I did).

Reference Adding couple of similar issue filed across:

Tools you can use to validate image you have:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!