---
title: "Document Comparison"
canonical_url: "https://www.nutrient.io/guides/android/samples/document-comparison-kotlin/"
md_url: "https://www.nutrient.io/guides/android/samples/document-comparison-kotlin.md"
last_updated: "2026-05-15T19:10:04.916Z"
description: "Compare two PDFs side-by-side with different stroke colors for each document."
---

# Document Comparison

Compare two PDFs side-by-side with different stroke colors for each document.

[Get Started](https://www.nutrient.io/sdk/android/getting-started.md)

[All Samples](https://www.nutrient.io/guides/android/samples.md)

[Download](https://www.nutrient.io/guides/android/downloads.md)

[Launch Demo](https://www.nutrient.io/demo/)

---

```kotlin

/*
 *   Copyright © 2018-2026 PSPDFKit GmbH. All rights reserved.
 *
 *   The PSPDFKit Sample applications are licensed with a modified BSD license.
 *   Please see License for details. This notice may not be removed from this file.
 */

// We're temporarily suppressing the ProgressDialog being deprecated warning.
// Issue: https://github.com/PSPDFKit/PSPDFKit/issues/32215
@file:Suppress("DEPRECATION")

package com.pspdfkit.catalog.examples.kotlin

import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.content.Context
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.WindowInsets
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.core.graphics.toColorInt
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.pspdfkit.annotations.BlendMode
import com.pspdfkit.catalog.R
import com.pspdfkit.catalog.SdkExample
import com.pspdfkit.configuration.activity.PdfActivityConfiguration
import com.pspdfkit.configuration.activity.ThumbnailBarMode
import com.pspdfkit.configuration.sharing.ShareFeatures
import com.pspdfkit.document.DocumentSource
import com.pspdfkit.document.PdfDocument
import com.pspdfkit.document.PdfDocumentLoader
import com.pspdfkit.document.processor.ComparisonDialogListener
import com.pspdfkit.document.processor.ComparisonDocument
import com.pspdfkit.document.processor.DocumentComparisonDialog
import com.pspdfkit.document.processor.PagePdf
import com.pspdfkit.document.processor.PdfProcessor
import com.pspdfkit.document.processor.PdfProcessorTask
import com.pspdfkit.document.providers.AssetDataProvider
import com.pspdfkit.ui.DocumentDescriptor
import com.pspdfkit.ui.PdfActivity
import com.pspdfkit.ui.PdfActivityIntentBuilder
import com.pspdfkit.ui.tabs.PdfTabBarCloseMode
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.functions.Consumer
import io.reactivex.rxjava3.schedulers.Schedulers
import java.io.File
import java.util.EnumSet

/**
 * This example shows how to use [PdfProcessor] for comparing PDF pages using a different
 * stroke color for each and blending these colored pages into a single document. Furthermore, it shows how to integrate the
 * {@link com.pspdfkit.document.processor.DocumentComparisonDialog} to align two documents for better comparison results.
 */
class DocumentComparisonExample(context: Context) :
    SdkExample(context, R.string.documentComparisonExampleTitle, R.string.documentComparisonExampleDescription) {
    private val documentAIndex = 0 // Destination page index
    private val documentBIndex = 0 // Source page index

    @SuppressLint("CheckResult")
    override fun launchExample(context: Context, configuration: PdfActivityConfiguration.Builder) {
        // We'll show progress dialog while processing documents with PdfProcessor.
        val progressDialog = createProgressDialog(context)
        progressDialog.show()

        configuration.apply {
            // The example uses a custom activity with a floating action button to start document alignment.
            layout(R.layout.activity_document_comparison)
            // Disable features that are not important for this example.
            setThumbnailBarMode(ThumbnailBarMode.THUMBNAIL_BAR_MODE_NONE)
            annotationEditingEnabled(false)
            outlineEnabled(false)
            settingsMenuEnabled(false)
            bookmarkListEnabled(false)
            thumbnailGridEnabled(false)
            annotationListEnabled(false)
            documentInfoViewEnabled(false)
            searchEnabled(false)
            printingEnabled(false)
            contentEditingEnabled(false)
            setEnabledShareFeatures(EnumSet.noneOf(ShareFeatures::class.java))
            invertColors(false)
        }

        // Comparison process consists from 2 steps:
        // 1. Color strokes from both documents in different colors.
        // 2. Merge 2 pages from these documents with colored strokes together.
        val processDocumentsForComparison =
            Single.defer {
                // Color strokes in the old document to GREEN.
                val greenDocumentUri =
                    changeStrokeColorForDocumentFromAssets(
                        context,
                        "comparison/Document-A.pdf",
                        oldDocumentColor,
                        "Document-A",
                        documentAIndex,
                    )

                // Color strokes in the new document to RED.
                val redDocumentUri =
                    changeStrokeColorForDocumentFromAssets(
                        context,
                        "comparison/Document-B.pdf",
                        newDocumentColor,
                        "Document-B",
                        documentBIndex,
                    )

                // Now generate document by merging both colored pages.
                val mergedDocumentUri = generateComparisonDocument(context, greenDocumentUri, redDocumentUri, "Comparison")

                // Return Single emitting triple of red, green and merged documents.
                return@defer Single.just(Triple(greenDocumentUri, redDocumentUri, mergedDocumentUri))
            }

        processDocumentsForComparison.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).doFinally {
                // Hide the progress dialog when processing finishes.
                progressDialog.hide()
            }.subscribe(
                Consumer {
                    // Start the PdfActivity with all 3 documents loaded in tabs. This will show documents A and B, as well as the
                    // comparison result.
                    val documentTabs =
                        arrayOf(
                            DocumentDescriptor.fromUri(it.first),
                            DocumentDescriptor.fromUri(it.second),
                            DocumentDescriptor.fromUri(it.third).apply {
                                setTitle("Comparison")
                            },
                        )
                    val intent =
                        PdfActivityIntentBuilder.fromDocumentDescriptor(context, *documentTabs).configuration(configuration.build())
                            // Make the tab with comparison document visible after starting the activity..visibleDocument(2).activityClass(DocumentComparisonActivity::class.java).build()
                    context.startActivity(intent)
                },
            )
    }

    private fun changeStrokeColorForDocumentFromAssets(
        context: Context,
        documentAsset: String,
        color: Int,
        outputFileName: String,
        pageIndex: Int,
    ): Uri {
        val outputFile = File(context.filesDir, "$outputFileName.pdf")

        val sourceDocument = PdfDocumentLoader.openDocument(context, DocumentSource(AssetDataProvider(documentAsset)))
        val task = PdfProcessorTask.fromDocument(sourceDocument).changeStrokeColorOnPage(pageIndex, color)
        PdfProcessor.processDocument(task, outputFile)

        return Uri.fromFile(outputFile)
    }

    private fun generateComparisonDocument(context: Context, oldDocumentUri: Uri, newDocumentUri: Uri, outputFileName: String): Uri {
        val outputFile = File(context.filesDir, "$outputFileName.pdf")

        val oldDocument = PdfDocumentLoader.openDocument(context, oldDocumentUri)
        val task =
            PdfProcessorTask.fromDocument(oldDocument).mergePage(PagePdf(context, newDocumentUri, documentBIndex), documentAIndex, BlendMode.DARKEN)
        PdfProcessor.processDocument(task, outputFile)

        return Uri.fromFile(outputFile)
    }

    private fun createProgressDialog(context: Context): ProgressDialog {
        val progressDialog = ProgressDialog(context)
        progressDialog.setTitle("Comparing documents")
        progressDialog.setProgressNumberFormat(null)
        progressDialog.setProgressPercentFormat(null)
        progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL)
        progressDialog.isIndeterminate = true
        progressDialog.setCancelable(false)
        return progressDialog
    }

    companion object {
        /** Tint color used for the old document. */
        val oldDocumentColor = "#F5281B".toColorInt()

        /** Tint color used for the new document. */
        val newDocumentColor = "#31C1FF".toColorInt()

    }
}

/**
 * This activity displays two documents to compare and the merged document.
 * It receives the selected points to updates the aligned comparison document.
 */
class DocumentComparisonActivity :
    PdfActivity(),
    ComparisonDialogListener {
    private lateinit var oldDocumentSource: DocumentSource
    private lateinit var newDocumentSource: DocumentSource

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (documentCoordinator.documents.size!= 3) {
            error("This example is built to be launched with exactly 3 documents only (document A, B, and comparison result).")
        }

        // This example assumes that the first two documents are the original documents A and B.
        oldDocumentSource = documentCoordinator.documents[0].documentSource
        newDocumentSource = documentCoordinator.documents[1].documentSource
        initViews()

        if (savedInstanceState!= null) {
            // If this activity is recreated after a configuration change, calling restore() ensures that 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 fun initViews() {
        pspdfKitViews.tabBar?.apply {
            setCloseMode(PdfTabBarCloseMode.CLOSE_DISABLED)
            // Center the tabs.
            gravity = Gravity.CENTER_HORIZONTAL
        }
        val alignDocumentsButton = findViewById<ExtendedFloatingActionButton>(R.id.pspdf_fab_align)

        // Make sure the floating action button is not hidden behind the navigation bar (neither in normal mode nor in immersive mode).
        alignDocumentsButton.setOnApplyWindowInsetsListener { _, insets ->
            alignDocumentsButton.layoutParams =
                (alignDocumentsButton.layoutParams as RelativeLayout.LayoutParams).apply {
                    val margin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, resources.displayMetrics).toInt()

                    bottomMargin =
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                            margin + insets.getInsets(WindowInsets.Type.systemBars()).bottom
                        } else {
                            @Suppress("DEPRECATION")
                            margin + insets.systemWindowInsetBottom
                        }
                }
            insets
        }

        alignDocumentsButton.setOnClickListener {
            val outputFile = filesDir.resolve("comparison-result.pdf")
            val oldDocument = ComparisonDocument(oldDocumentSource, 0, DocumentComparisonExample.oldDocumentColor)
            val newDocument = ComparisonDocument(newDocumentSource, 0, DocumentComparisonExample.newDocumentColor)
            DocumentComparisonDialog.show(this, configuration, oldDocument, newDocument, outputFile, this)
        }
    }

    override fun onSetActivityTitle(configuration: PdfActivityConfiguration, document: PdfDocument?) {
        super.onSetActivityTitle(configuration, document)
        supportActionBar?.title = "Compare Documents"
    }

    override fun onComparisonSuccessful(alignedDocument: DocumentSource) {
        // Amit note: not sure if this code needs to handle non-file sources, but it doesn't, so return if not.
        val fileUri = alignedDocument.fileUri?: return
        // Try to replace comparison document.
        try {
            documentCoordinator.removeDocument(documentCoordinator.documents[2])
            documentCoordinator.addDocument(DocumentDescriptor.fromUri(fileUri), 2)
            documentCoordinator.documents[2].setTitle("Comparison")
            documentCoordinator.setVisibleDocument(documentCoordinator.documents[2])
        } catch (e: IndexOutOfBoundsException) {
            e.printStackTrace()
        }
    }

    override fun onError(error: Throwable) {
        Log.e("Example", "An error happened while comparing the documents.", error)
        Toast.makeText(this, "There was a comparison error. Check logcat for details.", Toast.LENGTH_LONG).show()
    }
}

```

This code sample is an example that illustrates how to use our SDK. Please adapt it to your specific use case.

---

## Related pages

- [Application Policy](/guides/android/samples/application-policy-kotlin.md)
- [Custom Form Highlight Color](/guides/android/samples/custom-form-highlight-color-java.md)
- [Custom Page Templates](/guides/android/samples/custom-page-templates-java.md)
- [Digital Signature (Basic)](/guides/android/samples/digital-signature-basic-kotlin.md)
- [Disabled Annotation Property](/guides/android/samples/disabled-annotation-property-java.md)
- [Image Document](/guides/android/samples/image-document-kotlin.md)
- [Compose Image Document](/guides/android/samples/compose-image-document-kotlin.md)
- [Inline Multimedia](/guides/android/samples/inline-multimedia-kotlin.md)
- [JavaScript Form Filling](/guides/android/samples/javascript-form-filling-kotlin.md)
- [Overlay Visibility](/guides/android/samples/overlay-visibility-kotlin.md)
- [PdfFragment](/guides/android/samples/pdffragment-kotlin.md)
- [Reader View](/guides/android/samples/reader-view-kotlin.md)
- [Playground](/guides/android/samples/playground-kotlin.md)
- [JavaScript Calculator](/guides/android/samples/javascript-calculator-kotlin.md)
- [Text Field Suggestions](/guides/android/samples/text-field-suggestions-kotlin.md)
- [Thumbnail Bar Modes](/guides/android/samples/thumbnail-bar-modes-kotlin.md)
- [Signature Storage Database](/guides/android/samples/signature-storage-database-kotlin.md)
- [Selection Customization](/guides/android/samples/selection-customization-java.md)
- [Password Protected PDF](/guides/android/samples/password-protected-pdf-kotlin.md)
- [Scientific Paper](/guides/android/samples/scientific-paper-kotlin.md)
- [Try Instant](/guides/android/samples/try-instant-kotlin.md)
- [Merge Documents](/guides/android/samples/merge-documents-kotlin.md)
- [Annotation Rendering](/guides/android/samples/annotation-rendering-kotlin.md)
- [Custom Data Provider](/guides/android/samples/custom-data-provider-kotlin.md)
- [Annotations with Transparency](/guides/android/samples/annotations-with-transparency-kotlin.md)
- [Annotation Flags](/guides/android/samples/annotation-flags-kotlin.md)
- [AI Assistant (Multiple Documents, ViewPager)](/guides/android/samples/ai-assistant-multiple-documents-viewpager-kotlin.md)
- [Custom Sharing Menu](/guides/android/samples/custom-sharing-menu-java.md)
- [Add LTV to Existing Signature](/guides/android/samples/add-ltv-to-existing-signature-kotlin.md)
- [Custom Toolbar Grouping](/guides/android/samples/custom-toolbar-grouping-java.md)
- [Custom Layout](/guides/android/samples/custom-layout-kotlin.md)
- [Custom ActionBar Actions](/guides/android/samples/custom-actionbar-actions-kotlin.md)
- [Custom Activity Toolbars](/guides/android/samples/custom-activity-toolbars-java.md)
- [Custom Note Hinter](/guides/android/samples/custom-note-hinter-kotlin.md)
- [Custom Main Toolbar](/guides/android/samples/custom-main-toolbar-kotlin.md)
- [Annotation Configuration](/guides/android/samples/annotation-configuration-kotlin.md)
- [Annotation Selection Styling](/guides/android/samples/annotation-selection-styling-kotlin.md)
- [Custom Search UI (Compose)](/guides/android/samples/custom-search-ui-compose-kotlin.md)
- [Document Switcher](/guides/android/samples/document-switcher-java.md)
- [File Annotation Creation](/guides/android/samples/file-annotation-creation-kotlin.md)
- [Dynamic Pages on Scroll](/guides/android/samples/dynamic-pages-on-scroll-kotlin.md)
- [Custom Activity Form Editing](/guides/android/samples/custom-activity-form-editing-java.md)
- [Custom Stamp Annotations](/guides/android/samples/custom-stamp-annotations-java.md)
- [Custom Outline Provider](/guides/android/samples/custom-outline-provider-kotlin.md)
- [Compose Navigation](/guides/android/samples/compose-navigation-kotlin.md)
- [Fragment Runtime Configuration](/guides/android/samples/fragment-runtime-configuration-kotlin.md)
- [Annotation Overlay](/guides/android/samples/annotation-overlay-java.md)
- [Instant Document JSON](/guides/android/samples/instant-document-json-kotlin.md)
- [DocumentView Composable](/guides/android/samples/documentview-composable-kotlin.md)
- [Form Creation](/guides/android/samples/form-creation-kotlin.md)
- [Document Download](/guides/android/samples/document-download-kotlin.md)
- [JavaScript Actions](/guides/android/samples/javascript-actions-kotlin.md)
- [Instant JSON Attachment](/guides/android/samples/instant-json-attachment-kotlin.md)
- [Digital Signature (Manual)](/guides/android/samples/digital-signature-manual-kotlin.md)
- [Digital Signature (Third-Party)](/guides/android/samples/digital-signature-third-party-kotlin.md)
- [Inline Search](/guides/android/samples/inline-search-java.md)
- [Form Filling](/guides/android/samples/form-filling-kotlin.md)
- [Form Click Intercept (Compose)](/guides/android/samples/form-click-intercept-compose-kotlin.md)
- [Document Sharing](/guides/android/samples/document-sharing-java.md)
- [Custom Download Dialog](/guides/android/samples/custom-download-dialog-java.md)
- [Download Progress](/guides/android/samples/download-progress-kotlin.md)
- [Popup Toolbar Customization](/guides/android/samples/popup-toolbar-customization-kotlin.md)
- [Custom Sharing Dialog](/guides/android/samples/custom-sharing-dialog-java.md)
- [PDF from Image](/guides/android/samples/pdf-from-image-kotlin.md)
- [Digital Signature (Two-Step)](/guides/android/samples/digital-signature-two-step-kotlin.md)
- [Remote URL](/guides/android/samples/remote-url-kotlin.md)
- [PdfUiFragment](/guides/android/samples/pdfuifragment-kotlin.md)
- [Runtime Configuration](/guides/android/samples/runtime-configuration-kotlin.md)
- [Sound Extraction](/guides/android/samples/sound-extraction-kotlin.md)
- [Document from Canvas](/guides/android/samples/document-from-canvas-kotlin.md)
- [Tabbed Documents](/guides/android/samples/tabbed-documents-kotlin.md)
- [Watermarks](/guides/android/samples/watermarks-kotlin.md)
- [Programmatic Zoom](/guides/android/samples/programmatic-zoom-kotlin.md)
- [Signature Parcelize](/guides/android/samples/signature-parcelize-kotlin.md)
- [OCR](/guides/android/samples/ocr-kotlin.md)
- [Vertical Scrollbar](/guides/android/samples/vertical-scrollbar-java.md)
- [Split View](/guides/android/samples/split-view-java.md)
- [XFDF Import/Export](/guides/android/samples/xfdf-import-export-kotlin.md)
- [UI View Modes](/guides/android/samples/ui-view-modes-kotlin.md)
- [LTV Signature](/guides/android/samples/ltv-signature-kotlin.md)
- [Bookmark Highlighting](/guides/android/samples/bookmark-highlighting-kotlin.md)
- [Custom Annotation Inspector](/guides/android/samples/custom-annotation-inspector-java.md)
- [Annotation Sidebar](/guides/android/samples/annotation-sidebar-kotlin.md)
- [AI Assistant (Single Document)](/guides/android/samples/ai-assistant-single-document-kotlin.md)
- [AI Assistant (Multiple Documents, Compose)](/guides/android/samples/ai-assistant-multiple-documents-compose-kotlin.md)
- [Document Processing](/guides/android/samples/document-processing-kotlin.md)
- [Custom Annotation Creation Toolbar](/guides/android/samples/custom-annotation-creation-toolbar-java.md)
- [Custom Electronic Signature](/guides/android/samples/custom-electronic-signature-java.md)
- [E-Learning](/guides/android/samples/e-learning-kotlin.md)
- [Electronic + Digital Signing](/guides/android/samples/electronic-digital-signing-kotlin.md)
- [Generate PDF Report](/guides/android/samples/generate-pdf-report-kotlin.md)
- [Multimedia Annotations](/guides/android/samples/multimedia-annotations-kotlin.md)
- [Forms with JavaScript](/guides/android/samples/forms-with-javascript-kotlin.md)
- [External Document](/guides/android/samples/external-document-kotlin.md)
- [Overlay Views](/guides/android/samples/overlay-views-kotlin.md)
- [Kiosk Grid](/guides/android/samples/kiosk-grid-kotlin.md)
- [Search Indexing](/guides/android/samples/search-indexing-kotlin.md)
- [Annotation Creation](/guides/android/samples/annotation-creation-kotlin.md)
- [Filterable Thumbnail Grid](/guides/android/samples/filterable-thumbnail-grid-kotlin.md)
- [Tabbed Documents (Persistent)](/guides/android/samples/tabbed-documents-persistent-kotlin.md)
- [Measurement Tools](/guides/android/samples/measurement-tools-kotlin.md)
- [HTML-to-PDF Conversion](/guides/android/samples/html-to-pdf-conversion-kotlin.md)
- [AES Encrypted File](/guides/android/samples/aes-encrypted-file-java.md)
- [Construction Floor Plan](/guides/android/samples/construction-floor-plan-kotlin.md)
- [Hide and Reveal Areas](/guides/android/samples/hide-and-reveal-areas-kotlin.md)
- [Multiple Documents (Compose Pager)](/guides/android/samples/multiple-documents-compose-pager-kotlin.md)
- [Screen Reader](/guides/android/samples/screen-reader-java.md)
- [Custom Search UI (Views)](/guides/android/samples/custom-search-ui-views-java.md)

