Barcode can be used to represent a user’s data into a visual pattern that can be scanned, interpreted, and incorporated into a database. Barcodes are useful when information needs to be easily accessible without potential data entry errors.

In this tutorial, you will learn how to generate and stamp barcodes and QR codes into a PDF then later retrieve their data. This tutorial will cover sample code for WebViewer and Android. For web, we are using open-source jsbarcode for barcode generation, javascript-barcode-reader for reading, jsqr for QR code generation and qrcode for reading. For Android, we are using open-source ZXing for QR code/barcode generation and reading. By the end of this tutorial, you will be able to build something like this:

WebViewer:

Android:

linkSetup

First, create a simple PDF document viewer with PDFTron SDK for your choice of platform:

For WebViewer, create a simple React viewer as described in the guide: Integrating React with WebViewer JavaScript PDF library.

For Android, create a simple kotlin viewer as described in the guide: Open a document with Fragment.

linkCreate a Barcode/QR Code

Next, let's create a barcode and QR code image:

linkWebViewer:

// Barcode
JsBarcode(barcodeRef.current, e.currentTarget.value, {
  format: formatRef.current.value,
});

// QR code
QRCode.toCanvas(qrRef.current, qrInput, function (error) {
  if (error) setErrQrText(error);
});

linkAndroid:

@Throws(WriterException::class)
fun createImage(message: String?, type: String?): Bitmap? {
    var bitMatrix: BitMatrix? = null
    bitMatrix = when (type) {
        "QR Code" -> MultiFormatWriter().encode(message, BarcodeFormat.QR_CODE, size, size)
        "Barcode" -> MultiFormatWriter().encode(
            message,
            BarcodeFormat.CODE_128,
            size_width,
            size_height
        )
        else -> MultiFormatWriter().encode(message, BarcodeFormat.QR_CODE, size, size)
    }
    val width = bitMatrix.width
    val height = bitMatrix.height
    val pixels = IntArray(width * height)
    for (i in 0 until height) {
        for (j in 0 until width) {
            if (bitMatrix[j, i]) {
                pixels[i * width + j] = -0x1000000
            } else {
                pixels[i * width + j] = -0x1
            }
        }
    }
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
    return bitmap
}

linkCreate a Stamp from the Barcode/QR Code

Then, let's create a PDF Stamp annotation from the barcode/QR code image, and add it to the PDF document:

linkWebViewer:

const stampBarcode = (e, type) => {
  e.preventDefault();
  const { Annotations, annotManager, docViewer } = instance;
  const stampAnnot = new Annotations.StampAnnotation();
  stampAnnot.PageNumber = docViewer.getCurrentPage();
  stampAnnot.X = 100;
  stampAnnot.Y = 250;
  stampAnnot.Width = 300;
  
  if (type === '2d') {
    stampAnnot.ImageData = barcodeRef.current.toDataURL();
    stampAnnot.Height = 200;
  } else {
    stampAnnot.ImageData = qrRef.current.toDataURL();
    stampAnnot.Height = 300;
  }

  stampAnnot.Author = annotManager.getCurrentUser();
  annotManager.addAnnotation(stampAnnot);
  annotManager.redrawAnnotation(stampAnnot);
};

linkAndroid:

private fun createBarcodeAnnot(link: String) {
    val bitmap = createImage(link, mBarcodeType)
    val file = saveBitmap(bitmap)
    if (file != null) {
        createImageStamp(Uri.fromFile(file), 0, null)
        if (mAnnot != null) {
            mAnnot.setCustomData(BARCODE_KEY, link)
        }
    }
    if (mLink != null) {
        val toolManager = mPdfViewCtrl.toolManager as ToolManager
        toolManager.tool = toolManager.createDefaultTool()
    } else {
        mNextToolMode = toolMode
    }
}

You should now see a PDF document with the barcode/QR code image stamped on the location you’ve selected. You have the option to keep them as PDF stamp annotations or flatten them so they become a part of the PDF document. Either way, it is possible to retrieve their information later.

linkRead the Barcode/QR Code from the PDF

Finally, it is time to retrieve information from the barcode/QR code that was stamped on the document:

linkWebViewer:

const pageIndex = annotation.PageNumber;
// get the canvas for the page
const iframeDocument = iframeWindow.document;
const canvasMultiplier = iframeWindow.utils.getCanvasMultiplier();
const pageContainer = iframeDocument.getElementById(
    'pageContainer' + pageIndex,
);
const pageCanvas = pageContainer.querySelector('.canvas' + pageIndex);
const topOffset = parseFloat(pageContainer.style.top) || 0;
const leftOffset = parseFloat(pageContainer.style.left) || 0;

const zoom = docViewer.getZoom();
const x = annotation.X * zoom - leftOffset;
const y = annotation.Y * zoom - topOffset;
const width = annotation.Width * zoom * canvasMultiplier;
const height = annotation.Height * zoom * canvasMultiplier;

const copyCanvas = document.createElement('canvas');
copyCanvas.width = width;
copyCanvas.height = height;
const ctx = copyCanvas.getContext('2d');
// copy the image data from the page to a new canvas so we can get the data URL
ctx.drawImage(pageCanvas, x, y, width, height, 0, 0, width, height);
const imageData = ctx.getImageData(0,0, width, height);
const code = jsQR(imageData.data, imageData.width, imageData.height);

if (code) {
    alert(`QR Code: ${code.data}`);
} else {
    javascriptBarcodeReader({
    image: copyCanvas,
    barcode: 'code-128',
    })
    .then(result => {
        alert(`Barcode: ${result}`);
    })
    .catch(console.log);
}

linkAndroid:

val pts1 = mPdfViewCtrl.convScreenPtToPagePt(mMinX.toDouble(), mMaxY.toDouble(), mPageNum)
val pts2 = mPdfViewCtrl.convScreenPtToPagePt(mMaxX.toDouble(), mMinY.toDouble(), mPageNum)

val cropRect = Rect(pts1[0], pts1[1], pts2[0], pts2[1])
val page: Page = mPdfViewCtrl.doc.getPage(mPageNum)
val draw = PDFDraw()
draw.setClipRect(cropRect)
val bMap = draw.getBitmap(page)

val intArray = IntArray(bMap.width * bMap.height)
//copy pixel data from the Bitmap into the 'intArray' array
bMap.getPixels(intArray, 0, bMap.width, 0, 0, bMap.width, bMap.height)
val source: LuminanceSource =
    RGBLuminanceSource(bMap.width, bMap.height, intArray)
val bitmap = BinaryBitmap(HybridBinarizer(source))

val reader: Reader = MultiFormatReader()
val tmpHintsMap: MutableMap<DecodeHintType, Any> = EnumMap(
    DecodeHintType::class.java
)
tmpHintsMap[DecodeHintType.TRY_HARDER] = java.lang.Boolean.TRUE
tmpHintsMap[DecodeHintType.POSSIBLE_FORMATS] = EnumSet.allOf(BarcodeFormat::class.java)

try {
    val result: Result = reader.decode(bitmap, tmpHintsMap)
    val contents = result.text

    Log.d("barcode", "link:$contents")

    Utils.safeShowAlertDialog(mPdfViewCtrl.context, contents, "Content")

} catch (e: Exception) {
    Log.e("QrTest", "Error decoding barcode", e)
}

That's it!

You can find full source code from https://github.com/PDFTron/webviewer-barcode and https://github.com/PDFTron/pdftron-android-barcode.

linkConclusion

As you can see, generating, stamping and reading barcodes and QR codes from PDFs using PDFTron SDK isn’t too complicated when using WebViewer or native SDK and an open source toolkit similar to the ones used here.

Get started with WebViewer and PDFTron for Android and let us know what you build!

We hope you found this article helpful! If you have any questions or comments, don’t hesitate to contact us.