Search code examples
javaqr-codezxing

Decoding QR Code embedded into PDF with ZXing on Java backend


In a Java backend server application I want to decode a QR code embedded into a PDF file using the zxing library. I adapted the example from https://gist.github.com/JoelGeraci-Datalogics/dd9e214d4c584d61f5b1 to work with the pdfbox library as follows:

ReadBarcodeFromPDF.java

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

public class ReadBarcodeFromPDF {

    private static final List<String> urlList = Arrays.asList(
            "http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_QRCode.pdf",
            "http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_DataMatrix.pdf",
            "http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_PDF417.pdf"
    );

    public static void main(String[] args) throws Exception {
        for (String url : urlList) {
            readCode(url);
        }
    }

    private static String readCode(String url) throws MalformedURLException, IOException, NotFoundException {
        URLConnection connection = new URL(url).openConnection();
        connection.connect();

        try (InputStream inputStream = connection.getInputStream()) {
            try (PDDocument document = PDDocument.load(inputStream)) {
                PDFRenderer pdfRenderer = new PDFRenderer(document);
                BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300, ImageType.BINARY);
                LuminanceSource luminanceSource = new BufferedImageLuminanceSource(bufferedImage);
                HybridBinarizer hybridBinarizer = new HybridBinarizer(luminanceSource);
                BinaryBitmap bitmap = new BinaryBitmap(hybridBinarizer);
                MultiFormatReader reader = new MultiFormatReader();
                Hashtable<DecodeHintType, Object> hints = new Hashtable<>();
                hints.put(DecodeHintType.POSSIBLE_FORMATS, Arrays.asList(
                        BarcodeFormat.QR_CODE,
                        BarcodeFormat.DATA_MATRIX,
                        BarcodeFormat.PDF_417
                ));
                hints.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
                hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
                reader.setHints(hints);
                Result result = reader.decodeWithState(bitmap);
                return result.getText();
            }
        }
    }
}

The example is supposed to recognize codes from PDF documents with different code types:

  1. QR Code: http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_QRCode.pdf
  2. Data Matrix: http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_DataMatrix.pdf
  3. PDF417: http://dev.datalogics.com/cookbook/forms/ReadBarcodeImage_PDF417.pdf

But it fact it recognizes only the PDF417. The QR Code (in which I am interested) and the data matrix (in which I am not interested) are not recognized.

The output is

com.google.zxing.NotFoundException
com.google.zxing.NotFoundException
11/15/2010  Tony    Blue

I also tried

Different arguments in line

pdfRenderer.renderImageWithDPI(0, 300, ImageType.BINARY);
  • Different values for dpi (2nd argument) between 100 and 300
  • All available values for imageType (3rd argument)
  • Newest version of the library (3.5.0)

pom.xml

    <dependency>
        <groupId>org.apache.pdfbox</groupId>
        <artifactId>pdfbox</artifactId>
        <version>2.0.26</version>
    </dependency>

    <dependency>
        <groupId>com.google.zxing</groupId>
        <artifactId>javase</artifactId>
        <version>3.3.3</version>
    </dependency>

Solution

  • Your code works if one removes

    hints.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE);
    

    I suspect that ZXIng only checks whether there is an entry for the key and not its value. The javadoc mentions "Doesn't matter what it maps to; use Boolean.TRUE."