AVAILABLE NOW: Spring 2025 Release

How to Generate, Stamp, and Read Barcodes in a PDF with Apryse SDK

By Andrey Safonov, Shirley Gong | 2020 Oct 09

Sanity Image
Read time

4 min

A 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:

WebViewer barcode generator

Android:

Android barcode generator

Setup

Copied to clipboard

First, create a simple PDF document viewer with Apryse 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.

Create a Barcode/QR Code

Copied to clipboard

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

WebViewer:

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

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

Android:

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

Create a Stamp from the Barcode/QR Code

Copied to clipboard

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

WebViewer:

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

Android:

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.

Read the Barcode/QR Code from the PDF

Copied to clipboard

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

WebViewer:

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

Android:

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!

Conclusion

Copied to clipboard

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

Get started with WebViewer and Apryse 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.

Sanity Image

Andrey Safonov

Director of Product

LinkedIn link
Sanity Image

Shirley Gong

Share this post

email
linkedIn
twitter