12

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?

genpfault
  • 51,148
  • 11
  • 85
  • 139
MrSiro
  • 281
  • 1
  • 4
  • 16

4 Answers4

24

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.

LaurentY
  • 7,495
  • 3
  • 37
  • 55
  • @MítTơLớp, Is it useful ? – LaurentY Apr 17 '15 at 08:38
  • Sorry for my slow reply. I tried your code and for some pictures, it's work greate. But some other picture, it's crashes at: int[] intArray = new int[bitmap.getWidth() * bitmap.getHeight()]; with Caused by: java.lang.OutOfMemoryError – MrSiro Apr 19 '15 at 17:44
  • How do i can fix that bugs ? Please. – MrSiro Apr 19 '15 at 17:56
  • @MítTơLớp, I think some pictures are too big. What's size of your picture when it crash ? – LaurentY Apr 20 '15 at 07:12
  • Yep. It's 3264 x 2448. I tested on galaxy s3. – MrSiro Apr 20 '15 at 11:25
  • I'm resize image bitmap after get image from gallery, and it worked. Thanks a lot. – MrSiro Apr 21 '15 at 05:45
  • Hi. I ticked your answer is useful one week ago :D – MrSiro Apr 21 '15 at 08:32
  • Hi @LaurentY I pull source code Zxing from github but it don't support on android 2.3 . I tried use a Zxing's custom at https://github.com/dm77/barcodescanner and it worked on android 2.3 . How do i can get image bitmap to display and save it in sdcard same as: https://github.com/zxing/zxing/blob/master/android/src/com/google/zxing/client/android/CaptureActivity.java#L538-L544 Do you known ? – MrSiro Apr 22 '15 at 03:54
  • I tried by that way. But on android 2.3, it display "Camera using...Please reboot." (sdk > 14 ok) I reboot but don't change. While i use above custom, it's worked. Now, I just need get image bitmap to store in sdcard. – MrSiro Apr 22 '15 at 10:18
  • Hi. I'm done. It's here: https://github.com/dm77/barcodescanner/issues/76#issuecomment-95319443 – MrSiro Apr 23 '15 at 01:41
3

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

}  
  • Adding *how* this code answers the question will help future visitors. – JAL Nov 07 '16 at 19:41
  • 1
    @LucienMendela Thank you. it work....but it only scan black and white png..how to scan qr with different color? – Abed Putra May 08 '17 at 02:15
  • And issue is same it worked for most of image but does not for same. To validate if generated QR image is right or not, I checked with **online tool** (http://qrlogo.kaarposoft.dk/qrdecode.html) and it is able to decode successfully. I have strong feeling that something missing at mobile SDK side from Zxing. – CoDe Jul 29 '19 at 11:24
1

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;
        }
    }
Raj Shah
  • 668
  • 1
  • 9
  • 23
0

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:

CoDe
  • 11,056
  • 14
  • 90
  • 197