从画廊android中的图像扫描条形码

Posted

技术标签:

【中文标题】从画廊android中的图像扫描条形码【英文标题】:Scan barcode from an image in gallery android 【发布时间】:2015-06-21 09:09:00 【问题描述】:

我正在创建一个android项目,主要功能是扫描条形码。

我尝试将Zxing 库集成到我的项目中,并且工作正常。

但是,它似乎不支持从 android 设备库中的可用图像中扫描条形码。

我该怎么做?或与其他条形码库?

【问题讨论】:

【参考方案1】:

您可以使用 ZXing 库中的此类 MultiFormatReader。

您必须在 BitMap 中获取图库图像并将其转换为:

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

更新1

要操作大图,请看:

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

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

您可以使用此属性android:largeHeap 来增加堆大小。

【讨论】:

@MítTơLớp,有用吗? 对不起,我的回复很慢。我试过你的代码,对于一些图片,它的工作很棒。但是其他一些图片,它在以下位置崩溃: int[] intArray = new int[bitmap.getWidth() * bitmap.getHeight()];原因:java.lang.OutOfMemoryError 我该如何修复这些错误?请。 @MítTơLớp,我觉得有些图片太大了。崩溃时图片的大小是多少? 是的。它是 3264 x 2448。我在 Galaxy s3 上测试过。【参考方案2】:

我有一个关于如何实现它的工作示例,如果您在 2016 年阅读,我就是这样做的:

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

  

【讨论】:

添加如何此代码回答问题将有助于未来的访问者。 @LucienMendela 谢谢。它工作..但它只扫描黑白png..如何扫描不同颜色的qr? 而且问题是相同的,它适用于大多数图像,但不适用于相同。为了验证生成的 QR 图像是否正确,我使用 在线工具 (qrlogo.kaarposoft.dk/qrdecode.html) 进行了检查,它能够成功解码。我有强烈的感觉,Zxing 在移动 SDK 方面缺少一些东西。【参考方案3】:

我处于同一场景之间,它抛出 NotFoundException,official doc 说

在图像中未找到条形码时抛出。可能是 部分检测到但无法确认。

一级解决方案 在某种程度上,@Laurent 答案几乎适用于我拥有的每个样本,但很少失败。

下一级解决方案在@Lucien Mendela 建议的 reader.decode(..) 之前添加 decodeHints 就可以了。

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

但最后的事情对我有用

如果您的图片很大,您可能需要缩小尺寸。 它还需要一个 ~rectangle 形状(在我的例子中是 421*402)。

参考 添加几个类似的问题:

Random com.google.zxing.NotFoundException during the reading valid QRCode

您可以用来验证您拥有的图像的工具:

qrdecode(别忘了勾选“生成调试输出”以获取调试信息) Zxing Decoder online

【讨论】:

【参考方案4】:

首先,当然,从图库中读取图片(这可以在您的活动中): Help by

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

    startActivityForResult(pickIntent, 111);

之后,只需获取活动结果上的图像 uri,ZXing 就会发挥作用:

 @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;
        
    

【讨论】:

以上是关于从画廊android中的图像扫描条形码的主要内容,如果未能解决你的问题,请参考以下文章

python 使用zbar,cv2和PIL / Pillow扫描图像中的条形码。

Android:如何将通过USB连接的外部条形码扫描仪设备集成到Android应用程序[关闭]

Zebra 设备-TC75x-Android 8.1-条形码扫描问题

扫描图库中的图像时,Xamarin.Forms ZXing BarcodeReaderGeneric 返回 null

使用手电筒后无法使用条形码扫描仪

Android 系列 5 7使用Google ZXing条形码扫描器扫描条形码或QR码