Search code examples
javaqr-codezxing

zxing is unable to find a QR code from an image


When scanning for a QR code like this: sample image no results are found with zxing. With my phone, there is no problem to scan it. I'm using latest Java zwing 3.5.2.

Here is the used algorithm (the hard work is done by zxing):

    class Results {
        public final double rotation;
        public final List<Result> results;

        Results(double rotation, List<Result> results) {
            this.rotation = rotation;
            this.results = results;
        }
    }

    protected Results getResults(BufferedImage image) {
        LuminanceSource source = new BufferedImageLuminanceSource(image);
        Reader reader = new MultiFormatReader();
        for (int i=0; i<2; ++i) {
            BinaryBitmap bitmap;
            if (i == 0) {
                bitmap = new BinaryBitmap(new GlobalHistogramBinarizer(source));
            } else {
                bitmap = new BinaryBitmap(new HybridBinarizer(source));
            }
            for (int r=0; r<4; ++r) {
                if (r > 0) {
                    bitmap = bitmap.rotateCounterClockwise();
                }

                List<Result> results = tryDetect(reader, bitmap);
                if (results != null) {
                    return new Results(r*90, results);
                }
            }
        }
        return null;
    }

    protected List<Result> tryDetect(Reader reader, BinaryBitmap bitmap) {
        // We should just be catching ReaderException in here but we discovered
        // an ArrayIndexOutOfBoundsException in the zxing library which prevents
        // us from continuing. So we catch everything.

        try {
            // Look for multiple barcodes
            MultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader(reader);
            Result[] theResults = multiReader.decodeMultiple(bitmap, HINTS);
            if (theResults != null) {
                return Arrays.asList(theResults);
            }
        } catch (Exception re) {
        }
        try {
            // Look for multiple barcodes by quadrant
            MultipleBarcodeReader multiReader = new GenericMultipleBarcodeReader(new ByQuadrantReader(reader));
            Result[] theResults = multiReader.decodeMultiple(bitmap, HINTS);
            if (theResults != null) {
                return Arrays.asList(theResults);
            }
        } catch (Exception re) {
        }
        try {
            // Look for pure barcode
            Result theResult = reader.decode(bitmap, HINTS_PURE);
            if (theResult != null) {
                return Arrays.asList(theResult);
            }
        } catch (Exception re) {
        }
        try {
            // Look for normal barcode in photo
            Result theResult = reader.decode(bitmap, HINTS);
            if (theResult != null) {
                return Arrays.asList(theResult);
            }
        } catch (Exception re) {
        }
        return null;
    }
}

Nearly all uses of zxing I've seen are quite similar.

I could be a bug in zwing or in my code. How to overcome this limitation?

I've tried to increase the resolution of the image, by interpolating, with no success.


Solution

  • Had the same issue, was able to fix it by adding white borders to the qrCode image before decoding

            int borderSize = 50;
    
            BufferedImage borderedImage = new BufferedImage(
                    resizedQrCodeImage.getWidth() + 2 * borderSize,
                    resizedQrCodeImage.getHeight() + 2 * borderSize,
                    resizedQrCodeImage.getType());
    
            Graphics2D g2d = borderedImage.createGraphics();
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, borderedImage.getWidth(), borderedImage.getHeight());
            g2d.drawImage(resizedQrCodeImage, borderSize, borderSize, null);
            g2d.dispose();
    

    and then simply:

            try {
                LuminanceSource source = new BufferedImageLuminanceSource(borderedImage);
                BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    
                Result result = new MultiFormatReader().decode(bitmap);
                return Ezvcard.parse(result.getText()).first(); //do not pay attention, simply parsing to the VCard object for my needs
            } catch (NotFoundException e) {
                throw new RuntimeException("Error - qr code can not be decoded.", e);
            }