# Compare PDFs by overlaying PDF pages

Starting from version 9.0.0, Foxit PDF SDK for Web provides APIs to support comparing PDFs by overlaying PDF pages, and then generate a new comparison result image which can intuitively display the differences between the two PDF pages.

# A Simple Example

In this section, a simple example will be provided to show you how to compare PDFs by overlaying PDF pages. It includes: open document, create document, get PDF page, compare pages, generate result page, and export the result document.

First, initialize a blank project, and then the subsequent operations will be done based on this project.

const libPath = window.top.location.origin + '/lib';
const pdfViewer = new PDFViewCtrl.PDFViewer({
    libPath: libPath,
    jr: {
        licenseSN: licenseSN,
        licenseKey: licenseKey
    }
});
pdfViewer.init(document.body);

# Load the documents that need to be compared

async function loadFiles() {
    const sourcePDFDoc = await pdfViewer.loadPDFDocByHttpRangeRequest({
        range: {
            url: '/assets/test-doc1.pdf'
        }
    });
    const targetPDFDoc = await pdfViewer.loadPDFDocByHttpRangeRequest({
        range: {
            url: '/assets/test-doc2.pdf'
        }
    });
    return { sourcePDFDoc, targetPDFDoc };
}

Foxit PDF SDK for Web provides two ways to load documents:

  1. loadPDFDocByHttpRangeRequest (opens new window) : using this API, you can asynchronously load PDF documents as required from remote.

  2. loadPDFDocByFile (opens new window) : using this API, you can load the file stream in the memory, or select files on the hard disk via <input type="file">.

The purpose of loading documents is that you can edit and read the documents without rendering them. Here is just for demonstration, so we use this method. In an actual project, you can also do further operations by getting the current opened document (PDFViewer.getCurrentPDFDoc (opens new window)).

# Create a blank document

The blank document will be used to save the comparison result.

function createBlankDoc() {
    return pdfViewer.createNewDoc();
}

# Get the bitmaps of the pages that need to be compared

async function getPageBitmaps(loadedFiles) {
    const { sourcePDFDoc, targetPDFDoc } = loadedFiles;

    const sourcePage = await sourcePDFDoc.getPageByIndex(0);
    const sourceBitmap = await sourcePage.render(1);
    
    const targetPage = await targetPDFDoc.getPageByIndex(0);
    const targetBitmap = await targetPage.render(1);
    
    return { sourceBitmap, targetBitmap };
}

If you need to use other options (for example scale and rotation), please input parameters (scale, rotate) in the render method, and refer to the PDFPage.render (opens new window) interface in the API Reference.

# Start to compare documents

function comparePageBitmap(sourceBitmap, targetBitmap) {
    const DiffColor = PDFViewCtrl.overlayComparison.DiffColor;
    const service = pdfViewer.getOverlayComparisonService();
    const resultCanvas = service.compareImageData({
        sourceBitmap,
        targetBitmap,
        combinePixelsOptions: {
            showDiffColor: true,
            sourceDiffColor: DiffColor.RED,
            targetDiffColor: DiffColor.BLUE,
            sourceOpacity: 0xFF,
            targetOpacity: 0xFF
        },
        transformation: {
            translateX: 0,
            translateY: 0,
            rotate: 2 / 180 * Math.PI
        }
    });
    return new Promise(resolve => {
        resultCanvas.toBlob(blob => {
            const fr = new FileReader();
            fr.onloadend = () => {
                resolve({
                    buffer: fr.result,
                    width: resultCanvas.width,
                    height: resultCanvas.height
                });
            };
            fr.readAsArrayBuffer(blob);
        });
    })
}

Note:

  1. The differences between the documents will be marked only when shouldShowDiff is set to true.
  2. sourceDiffColor and targetDiffColor do not support all colors, you must select one of the colors in the DiffColor enumeration.
  3. The value range of sourceOpacity and targetOpacity is 0~0xFF.

# Insert the comparison result into the PDF page

async function insertResultIntoNewDoc(newDoc, resultImageData) {
    const page = await newDoc.getPageByIndex(0);
    
    // resultImageData is the return object of the comparePageBitmap function mentioned in the above example.
    // Convert the unit of width and height from pixel to point. 
    const newPageWidth = resultImageData.width / 4 * 3;
    const newPageHeight = resultImageData.height / 4 * 3;
    // Reset the size of PDF page to make it the same size as the comparison image.
    await page.setPageSize(newPageWidth, newPageHeight);
    // Last, insert it into the PDF page as a PDF image object.
    await page.addImage(resultImageData.buffer, {
        left: 0,
        right: newPageWidth,
        bottom:0,
        top: newPageHeight
    });
}

# Export the result document

async function exportResultPDFDocFile(newDoc) {
    return newDoc.getFile();
}

PDFDoc.getFile() (opens new window) interface will return the blob object of the document. You can use the general method to download this file stream or open the document by PDFViewer.openPDFByFile (opens new window) interface to see the effect.

# The final effect

Integrate all the above code, the final effect is as follows, please click run button to run the example:

Note:

To minimize the interference of irrelevant code and make the code more intuitive, the above example is written using ESNext syntax. Please use a modern browser to open the developer guide document and run the example. If you need to be compatible with older browsers, please use JavaScript transpiler such as babel in your project.