Enhance Your Mobile Apps With Document Scanning In Lightning Web Components


Utilize the Document Scanner API within LWCs to streamline workflows and enhance efficiency in your Salesforce mobile applications.

Lightning Web Component - Document Scanner

Introduction :

In the realm of Salesforce development, the Lightning Web Component (LWC) framework has become the go-to choice for building dynamic and responsive user interfaces within the Salesforce ecosystem. Salesforce has introduced the Lightning Web Component Document Scanner API, a powerful tool that empowers developers to integrate document scanning functionality directly into their Salesforce applications. In this blog post, we’ll explore into Lightning Web Component Document Scanner API.

What is Document Scanner API ?

The Lightning Web Component Document Scanner API is a feature-rich tool designed to simplify the process of capturing documents within Salesforce applications. It leverages the capabilities of modern web browsers to enable users to scan documents using their device’s camera directly from within Salesforce. It utilizes the device’s camera and Optical Character Recognition (OCR) technology to transform physical documents into digital data within your LWC.

Benefits of using the Document Scanner API :

  • Enhance User Experience : Scanning documents directly on a mobile device streamlines the data collection process, saving time and effort for your users.
  • Improve Efficiency : Automating data entry through scanned documents translates to faster processing and improved overall workflow efficiency.
  • Improve Data Accuracy : With Optical Character Recognition (OCR) technology, the Document Scanner API ensures captured information is highly accurate, minimizing the risk of mistakes and saving time spent on corrections.

Getting Started :

Here’s a glimpse of how to incorporate the DocumentScanner API into your LWC:

  • Import the API : import import { getDocumentScanner } from 'lightning/mobileCapabilities'; in your component javascript file.
  • Check availability : Ensure the API is available before using it with getDocumentScanner().isAvailable()
  • Scan a Document : Scanning documents with DocumentScanner is straightforward.
    • Start a scan with scan(options)
    • Process the scan results. The scan() function returns a promise that resolves to an object containing the scanned document’s image and extracted text. You can then use this data within your LWC for further processing.

Document Scanner API Example :

<!--documentScannerCmp.html-->
<template>
    <table class="rootTable">
        <tbody>
            <!-- Document scanning controls -->
            <tr>
                <td style="height: 1px;">
                    // Choose source of the document to be scanned
                    <lightning-card title="Document Scanner" icon-name="custom:display_text">
                        <div class="slds-var-p-around_medium">
                            Select source of document to be scanned:
                            <br/><br/>
                            <lightning-button 
                                variant="brand" 
                                label="Camera" 
                                title="Capture document with camera" 
                                onclick={handleScanFromCameraClick}>
                            </lightning-button>

                            <lightning-button
                                variant="brand"
                                label="Photo Library"
                                title="Scan document from photo library"
                                onclick={handleScanFromPhotoLibraryClick}
                                class="slds-var-m-left_x-small">
                            </lightning-button>
                        </div>

                        <!-- Display errors, if any -->
                        <template lwc:if={scannerError}>
                            <lightning-formatted-text value={scannerError}></lightning-formatted-text>
                        </template>

                        <!-- Display text of scanned document, if any -->
                        <template lwc:if={scannedDocument}>
                            // results of the scan are displayed here
                            <div class="slds-var-p-around_medium">
                                Text Recognition Result: <br/><br/>
                                {scannedDocument.text}
                            </div>
                        </template>
                    </lightning-card>
                </td>
            </tr>

            <!-- If there is a scanned document, display a preview -->
            <tr>
                <td>
                    <template lwc:if={scannedDocument}>
                        <div class="previewDiv">
                            <!-- document image -->
                            <div class="divContentCentered">
                                <img class="previewImage" src={scannedDocument.imageBytes} onload={addImageHighlights} />
                            </div>

                            <!-- highlights overlay; note use of manual DOM rendering -->
                            <div class="divContentCentered">
                                <div class="contour" lwc:dom="manual"></div>
                            </div>
                        </div>
                    </template>
                </td>
            </tr>
        </tbody>
    </table>
</template>
import { LightningElement } from 'lwc';
import { getDocumentScanner } from "lightning/mobileCapabilities";

export default class DocumentScannerCmp extends LightningElement {
    // Scan results (if any)
    scannerError;
    scannedDocument;

    handleScanFromCameraClick() {
        this.scanDocument("DEVICE_CAMERA");
    }

    handleScanFromPhotoLibraryClick() {
        this.scanDocument("PHOTO_LIBRARY");
    }

    scanDocument(imageSource) {
        // Clear previous results / errors
        this.resetScanResults();

        // Main document scan cycle
        const myScanner = getDocumentScanner();
        if (myScanner.isAvailable()) {
        // Configure the scan
        const options = {
            imageSource: imageSource,
            scriptHint: "LATIN",
            returnImageBytes: true,
        };

        // Perform document scan
        myScanner
            .scan(options)
            .then((results) => {
            // Do something with the results
            this.processScannedDocuments(results);
            })
            .catch((error) => {
            // Handle errors
            this.scannerError =
                "Error code: " + error.code + "\nError message: " + error.message;
            });
        } else {
        // Scanner not available
        this.scannerError =
            "Problem initiating scan. Are you using a mobile device?";
        }
    }

    resetScanResults() {
        this.scannedDocument = null;
        this.scannerError = null;
    }

    processScannedDocuments(documents) {
        // DocumentScanner only processes the first scanned document in an array
        this.scannedDocument = documents[0];
        // And this is where you take over; process results as desired
    }

    // Build an annotation overlay graphic, to display on top of the scanned image
    addImageHighlights(event) {
        const textBlocks = this.scannedDocument?.blocks;
        if (!textBlocks) {
        return;
        }

        const img = event.srcElement;
        const cWidth = img.clientWidth;
        const cHeight = img.clientHeight;
        const nWidth = img.naturalWidth;
        const nHeight = img.naturalHeight;
        const width = Math.min(cWidth, nWidth);
        const height = Math.min(cHeight, nHeight);

        let svg =
        `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ` +
        `xmlns:xlink="http://www.w3.org/1999/xlink" ` +
        `width="${width}" height="${height}" viewBox="0, 0, ${nWidth}, ${nHeight}">`;
        textBlocks.forEach((block) =>
        block.lines.forEach((line) =>
            line.elements.forEach((element) => {
            const frame = element.frame;
            svg +=
                `<rect x="${frame.x}" y="${frame.y}" width="${frame.width}" ` +
                `height="${frame.height}" style="fill:green;fill-opacity:0.5" />`;
            })
        )
        );
        svg += "</svg>";

        // Manually attach the overlay SVG to the LWC DOM to render it
        this.template.querySelector(".contour").innerHTML = svg;
    }
}

Considerations and Limitations :

  • Document Scanner API is accessible when it runs within a compatible Salesforce mobile app.
    • Salesforce Mobile app
    • Mobile Publisher for Experience Cloud
  • To scan documents using a mobile device’s camera, DocumentScanner requires permission to use the camera.
  • To scan documents stored in the device photo library, DocumentScanner requires permission to access the photo library.

References :

Read More :