MrSiro
MrSiro

Reputation: 291

Scan barcode from an image in gallery android

I'm creating a android project, main feature is scan barcode.

I'm tried integrate with Zxing library into my project, and it's work fine.

However, it's seems not support scan barcode from an available image in gallery of android devices.

How i can do it? or with other barcode library?

Upvotes: 13

Views: 25220

Answers (4)

Raj Shah
Raj Shah

Reputation: 738

First, of course, read the image from the gallery (this can be in your activity): Help by

Intent pickIntent = new Intent(Intent.ACTION_PICK);
    pickIntent.setDataAndType( android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");

    startActivityForResult(pickIntent, 111);

After that, just get the image uri on the activity result and then ZXing will do the magic:

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch (requestCode) {
            //the case is because you might be handling multiple request codes here
            case 111:
                if(data == null || data.getData()==null) {
                    Log.e("TAG", "The uri is null, probably the user cancelled the image selection process using the back button.");
                    return;
                }
                Uri uri = data.getData();
                try
                {
                    InputStream inputStream = getContentResolver().openInputStream(uri);
                    Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    if (bitmap == null)
                    {
                        Log.e("TAG", "uri is not a bitmap," + uri.toString());
                        return;
                    }
                    int width = bitmap.getWidth(), height = bitmap.getHeight();
                    int[] pixels = new int[width * height];
                    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
                    bitmap.recycle();
                    bitmap = null;
                    RGBLuminanceSource source = new RGBLuminanceSource(width, height, pixels);
                    BinaryBitmap bBitmap = new BinaryBitmap(new HybridBinarizer(source));
                    MultiFormatReader reader = new MultiFormatReader();
                    try
                    {
                        Result result = reader.decode(bBitmap);
                        Toast.makeText(this, "The content of the QR image is: " + result.getText(), Toast.LENGTH_SHORT).show();
                    }
                    catch (NotFoundException e)
                    {
                        Log.e("TAG", "decode exception", e);
                    }
                }
                catch (FileNotFoundException e)
                {
                    Log.e("TAG", "can not open file" + uri.toString(), e);
                }
                break;
        }
    }

Upvotes: 1

CoDe
CoDe

Reputation: 11146

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:

Upvotes: 0

Lucien Mendela
Lucien Mendela

Reputation: 134

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();
                    }
                }
        }
    }

}  

Upvotes: 3

LaurentY
LaurentY

Reputation: 7653

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.

Upvotes: 24

Related Questions