Compare Documents on Android

Document Comparison is used to visually compare pages of different documents. It’s helpful for things such as construction plans and detailed drawings, as well as other content that requires precise placement.

This can be done in PSPDFKit using PdfProcessorTask. The process of preparing documents and comparing them involves a few steps to specify how the comparison should happen.

First, create a new PdfProcessorTask from an existing document. Then, apply the changes needed to compare documents, which are explained in the sections below. And finally, a document where all the changes and comparisons are visible will be created and saved to a specified location.

ℹ️ Note: The APIs described in this guide require the Document Comparison component to be enabled in your license.

Changing the Stroke Colors

One of the most important steps of generating a comparison document is the ability to change the stroke colors, which makes it easier to see the differences between two versions of a document.

Setting a different stroke color is usually the first step when trying to compare documents, as this will enable you to make any differences between pages more obvious. This will only affect stroke objects in the PDF, and it will leave the color of other elements, such as text or images, unchanged.

The stroke color of a page can be changed via changeStrokeColorOnPage():

val pageIndex = 0
val orange = 0xffa500
val task = PdfProcessorTask.fromDocument(document)
task.changeStrokeColorOnPage(pageIndex, orange)

PdfProcessor.processDocument(task, outputFile)
int pageIndex = 0;
int orange = 0xffa500;
PdfProcessorTask task = PdfProcessorTask.fromDocument(document);
task.changeStrokeColorOnPage(pageIndex, orange);

PdfProcessor.processDocument(task, outputFile);

The table below shows how applying an orange stroke color changes the appearance of a document.

Original Document Stroked Document
Original document Document with lines in orange

Generating the Comparison Document

Document Comparison allows you to merge the pages of two (or more) documents. You can then compare two single-page versions of a document to highlight and identify changes.

Be sure to configure the document pages by changing the stroke color and setting a blend mode accordingly. This way, it’s easier to make out differences on the pages. For example, comparing one document with a green stroke color and another one with a red stroke color and using a darkening blend mode works pretty well. Additionally, all the changes can easily be seen at a glance.

Trying out various stroke colors and blend modes will result in different-looking comparison documents, and you can make sure the final result fits your needs.

You can use mergePage(PagePdf, int, BlendMode) for merging. This method will place the given page object on top of the specified destination page of the currently processed document. Additionally, you can specify a transformation that should be applied before merging and choose the desired blend mode that should be used:

// First document for comparison with strokes colored to green.
val greenDocument: PdfDocument = ...
// Second document for comparison with strokes colored to red.
val redDocument: PdfDocument = ...

val destinationPageIndex = 0
val task = PdfProcessorTask.fromDocument(greenDocument)
task.mergePage(PagePdf(context, redDocument), destinationPageIndex, BlendMode.DARKEN)

PdfProcessor.processDocument(task, outputFile)
// First document for comparison with strokes colored to green.
PdfDocument greenDocument = ...;
// Second document for comparison with strokes colored to red.
PdfDocument redDocument = ...;

int destinationPageIndex = 0;
PdfProcessorTask task = PdfProcessorTask.fromDocument(greenDocument);
task.mergePage(new PagePdf(context, redDocument), destinationPageIndex, BlendMode.DARKEN);

PdfProcessor.processDocument(task, outputFile);

ℹ️ Note: It’s only possible to compare one page at a time.

The table below shows how a comparison document generated from two different but similar-looking documents that previously had their stroke colors changed would look.

Old Document New Document
Document with lines in green Document with lines in red
Comparison Document
Merged document

Aligning the Documents

If the two versions of the document you want to compare aren’t perfectly aligned with each other, PSPDFKit provides a way for users to visually select two corresponding sets of landmark points in both versions of the document and automatically calculates a transformation matrix based on that. The image below shows an example of a misaligned comparison document:

Misaligned comparison document

The DocumentComparisonDialog class provides the point-selection and alignment functionality for the document alignment process.

To show the dialog, call the static show() method of that class, and provide the hosting activity — a PdfActivityConfiguration instance — and the ComparisonDocument to use for comparison as arguments, along with the output file location and a ComparisonDialogListener callback interface:

val configurations: PdfActivityConfiguration = /** PdfActivity configuration to provide theme. */
val oldDocument: ComparisonDocument = /* The old version of a document. */
val newDocument: ComparisonDocument = /* The new version of a document. */
val outputFile: File = /* Output file for the comparison document. */
val listner: ComparisonDialogListener = /* The implementation for the comparison document callback. */

DocumentComparisonDialog.show(activity, configuration, oldDocument, newDocument, outputFile, listener)
PdfActivityConfiguration configurations = /** PdfActivity configuration to provide theme. */
ComparisonDocument oldDocument = /* The old version of a document. */
ComparisonDocument newDocument  = /* The new version of a document. */
ComparisonDialogListener listner = /* The implementation for the document comparison alignment callback. */
File outputFile = /* Output file for the comparison document. */

DocumentComparisonDialog.show(activity, configuration, oldDocument, newDocument, outputFile, listener)

❗ Important: Make sure to call DocumentComparisonDialog.restore() inside your activity’s onCreate() method to properly handle configuration changes.

class MyActivity : FragmentActivity(), ComparisonDialogListener {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       if(savedInstanceState != null) {
           // If this activity is recreated after a configuration change, calling `restore()` ensures the document will have the
           // correct callback (this activity) if it was shown before the configuration change. If no dialog was shown, this call is a
           // no-op.
           DocumentComparisonDialog.restore(this, this)
       }
   }
//........
class MayActivity extends FragmentActivity implements ComparisonDialogListener {

        override
        public void onCreate(Bundle savedInstanceState ) {
            super.onCreate(savedInstanceState)
            if(savedInstanceState != null) {
                // If this activity is recreated after a configuration change, calling `restore()` ensures the document will have the
                // correct callback (this activity) if it was shown before the configuration change. If no dialog was shown, this call is a
                // no-op.
                DocumentComparisonDialog.restore(this, this)
            }
        }

    //...

The document alignment process begins in the old version of the document, and then it automatically moves on to the new version once the user selects all three points in the old one.

It’s crucial to select the same three landmark points, in the same order. The points should be chosen such that they don’t move relative to each other. Selecting a point that changes position will result in misaligned comparison documents. The table below shows the recommended landmark points.

Points in the Old Document Points in the New Document
Document with A points Document with B points

Once all six points are selected, the document comparison dialog will automatically calculate a transformation matrix, try to generate a comparison document, and call one of its callback methods, depending on whether or not the generation succeeded:

override fun onComparisonSuccessful(alignedDocument: DocumentSource) {
    // Handle comparison document.
}

override fun onError(error: Throwable) {
    // Comparison has failed — show an error message here.
}
override
 void onComparisonSuccessful(DocumentSource comparisonDocument) {
    // Handle comparison document.
}

override
void onError(Throwable error) {
    // Comparison has failed — show an error message here.
}

The image below shows a comparison document aligned based on the two sets of three landmark points shown above.

Aligned document comparison

Full Code Example

class MyActivity : FragmentActivity(), ComparisonDialogListener {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if(savedInstanceState != null) {
            // If this activity is recreated after a configuration change, calling `restore()` ensures the document will have the
            // correct callback (this activity) if it was shown before the configuration change. If no dialog was shown, this call is a
            // no-op.
            DocumentComparisonDialog.restore(this, this)
        }
    }

    fun showComparisonDialog() {
        val configurations: PdfActivityConfiguration = /** PdfActivity configuration to provide theme. */
        val outputFile = /* Output file for the comparison document. */
        val oldDocument = ComparisonDocument(oldDocumentSource, 0, Color.GREEN)
        val newDocument = ComparisonDocument(newDocumentSource, 0, Color.RED)

        DocumentComparisonDialog.show(this, configuration, oldDocument, newDocument, outputFile, this)
    }

    override fun onComparisonSuccessful(alignedDocument: DocumentSource) {
    // Handle comparison document.
    }

    override fun onError(error: Throwable) {
        // Comparison has failed — show an error message here.
    }

}
class MayActivity extends FragmentActivity implements ComparisonDialogListener {

        override
        public void onCreate(Bundle savedInstanceState ) {
            super.onCreate(savedInstanceState)
            if(savedInstanceState != null) {
                // If this activity is recreated after a configuration change, calling `restore()` ensures the document will have the
                // correct callback (this activity) if it was shown before the configuration change. If no dialog was shown, this call is a
                // no-op.
                DocumentComparisonDialog.restore(this, this)
            }
        }

        private void showComparisonDialog {
            PdfActivityConfiguration configurations = /** PdfActivity configuration to provide theme. */
            File outputFile = /* Output file for the comparison document. */
            ComparisonDocument oldDocument = new ComparisonDocument(oldDocumentSource, 0, Color.GREEN)
            ComparisonDocument newDocument  = new ComparisonDocument(newDocumentSource, 0, Color.RED)

            DocumentComparisonDialog.show(this, configuration, oldDocument, newDocument, outputFile, this)
        }

        override
        void onComparisonSuccessful(DocumentSource comparisonDocument) {
            // Handle comparison document.
        }

        override
        void onError(Throwable error) {
            // Comparison has failed — show an error message here.
        }

    }

Example

There are a few runnable examples in our example projects that show the available document comparison API in action. These examples can be found in DocumentComparisonExample.kt in the Catalog app.