From Scan to PDFA Streamlined DocumentDigitalization Flow

From Scan to PDF: A Streamlined Document Digitization Flow

May 01, 2025 |

19 minutes read

From Scan to PDFA Streamlined DocumentDigitalization Flow

Smart PDF Generator with Scan, Filter, and Custom Export Control (Kotlin)

In an era of digital-first solutions, the Android-based PDF generator stands out by offering intelligent document scanning, real-time image enhancements, and customizable PDF exports. Built with Kotlin, this mobile-first utility simplifies how users scan, modify, and store documents. As part of our Kotlin Android app development, it leverages Google ML Kit for powerful text recognition, enhancing scanned documents through filtering, cropping, and DPI adjustments, followed by seamless export into high-quality PDF files with multi-page support and custom file naming. All features are tightly integrated with Android’s permission and storage systems to ensure a secure and smooth user experience, showcasing the strength of our Kotlin development services.

Smart Scanning with Google ML Kit

Integrates Google’s advanced ML Kit to deliver highly accurate Optical Character Recognition (OCR) and intelligent edge detection. This ensures that scanned documents are properly recognized, cropped, and enhanced, resulting in clean, professional-grade outputs even from casual captures.

Filter & Crop Tools

Enhance the readability and appearance of scanned documents with built-in filter and crop options. Users can adjust brightness, contrast, sharpness, and manually crop their scanned images to remove unwanted areas before finalizing them into PDFs, ensuring documents look polished and clear.

Permission Handling

Implements seamless permission management for accessing the camera, storage, and file system. The app ensures users are informed about permission needs while maintaining a smooth experience even across different Android versions, including modern scoped storage models.

DPI Management (70, 150, 300)

Offers flexible DPI (Dots Per Inch) options, allowing users to choose between 70, 150, and 300 DPI. Lower DPI settings optimize file size for quick sharing, while higher DPI ensures superior print quality for professional and archival use, giving users full control over the output quality.

Download as PDF

Allows users to easily convert single or multiple scanned images into a professionally formatted PDF document. Whether saving a single-page form or compiling a multi-page contract, users can instantly generate and store their files with minimal steps.

Custom PDF Naming

Supports custom naming for each generated PDF, enabling users to organize their files meaningfully. Whether naming based on project, date, or content, users maintain better file management and retrieval without relying on generic or system-generated filenames.

Multi-Page Scanning

Empowers users to capture and combine multiple images into a single, unified PDF file. Ideal for scanning contracts, books, or multi-page reports, this feature ensures that users can handle large document workflows directly from their mobile devices without external tools.

Image Resolution Control

Gives users control over the final image quality, ensuring a balance between file size and visual clarity. Whether saving high-resolution scans for print or compressing for easier sharing, users can tailor the resolution settings to best fit their needs.

This powerful tool transforms scanning workflows by enabling users to create shareable, high-quality PDFs directly from their mobile devices.

From Friction to Focus: What the Problem Taught Us

1. Scanning & OCR Integration

  • Integrate Google ML Kit for reliable text recognition from captured images.
  • Handle document skew, blur, and noise to improve text extraction accuracy.

2. Image Preprocessing

  • Add filter options for clarity (e.g., grayscale, contrast boost).
  • Enable crop adjustment with flexible bounding boxes.
  • Maintain preview consistency before saving.

3. Multi-Page Capture & PDF Assembly

  • Allow continuous scanning into a session.
  • Maintain a structured order of pages.
  • Create a PDF with selectable DPI (70, 150, 300) for file-size/resolution control.

4. Permission & Storage Management

  • Request runtime permissions for the camera and file storage.
  • Handle edge cases like denied or revoked permissions gracefully.
  • Ensure file storage on both internal and external directories based on OS versions.

5. Custom Naming & Downloads

  • Support user-defined naming schemes or use timestamp-based fallbacks.
  • Save PDFs in a dedicated folder and notify users with share options post-download.

Solution Highlights

1. ML Kit OCR Integration

  • Integrated Google’s TextRecognizer for fast and accurate extraction.
  • Used Kotlin Coroutines for asynchronous scanning and image processing.

2. DPI & Resolution Control

  • Supported multiple DPI modes (70, 150, 300) using the PdfDocument APIs.
  • Dynamically adjusted bitmap scaling based on user selection.

3. Multi-Page PDF Generator

  • Maintained an in-memory list of images using Bitmap and Uri types.
  • Used PdfDocument.PageInfo to append multiple pages efficiently.
  • Added preview and page-reordering before final export.

4. Filters & Cropping

  • Applied basic filters using ColorMatrix and Canvas.
  • Implemented cropping via touch-based UI using GestureDetector and Matrix.

5. Custom Naming and Export

  • Integrated dialog prompts for filename input.
  • Fallback to datetime-based names when left blank.
  • Saved to app-specific storage directories for Android 11+ compatibility.

Future-Ready Solutions: Beyond Ideas, Beyond Limits

1. Modular Image Processing Pipeline

  • Built a modular architecture separating scanning, filtering, and PDF generation to maintain a clean code structure.
  • Enabled independent upgrades to OCR, image enhancements, and export features without breaking the full workflow.
  • Simplified testing and debugging with isolated, well-scoped modules for scanning, editing, and file management.

2. Adaptive Permission Management

  • Developed a context-aware permission handler that adapts to different Android SDK versions and permission models.
  • Minimized user friction by requesting permissions only when necessary, improving acceptance rates.
  • Safeguarded the app flow by implementing fallback strategies when permissions are denied, keeping users engaged without crashes.

3. Dynamic DPI and Resolution Control

  • Introduced a flexible resolution engine allowing users to select 70, 150, or 300 DPI dynamically before final PDF generation.
  • Balanced quality and file size to suit diverse user needs, like quick sharing vs professional-grade printing.
  • Optimized memory and storage usage by adjusting image compression and resolution settings in real-time.

4. Efficient Multi-Page Capture and Assembly

  • Designed an optimized image caching mechanism to handle multiple high-resolution captures without memory leaks.
  • Streamlined the process of stitching multiple images into a coherent, properly ordered multi-page PDF.
  • Reduced processing time and ensured smooth navigation even with large multi-page documents.

5. Resilient Error Handling and Recovery

  • Implemented graceful error recovery strategies during scan capture, filter application, and PDF generation stages.
  • Added informative user prompts and fallback options, ensuring that minor failures do not interrupt the entire session.
  • Logged critical failures internally to aid in post-release debugging and updates.

A) Manage the internet connection and custom message

fun showSnackBar(view: View?, strMessage: String?) {
        try {
            val snackbar = Snackbar.make(view!!, strMessage!!, Snackbar.LENGTH_LONG)
            val snackbarView = snackbar.view
            snackbarView.setBackgroundColor(Color.BLACK)
            val textView =
                snackbarView.findViewById<View>(com.google.android.material.R.id.snackbar_text) as TextView
            textView.setTextColor(Color.WHITE)
            textView.maxLines = 5
            snackbar.show()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    //- Check network connectivity
    fun isInternetAvail(context: Context): Boolean {
        val connectivity = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        if (connectivity != null) {
            val info = connectivity.allNetworkInfo
            if (info != null) for (i in info.indices) if (info[i].state == NetworkInfo.State.CONNECTED) {
                return true
            }
        }
        return false
    }

B). Manage to store the PDF in the desired locations

. private fun savePdfToUserSelectedLocation(pdfData: ByteArray) {
        contentResolver.openOutputStream(imageUri!!)?.use { outputStream ->
            outputStream.write(pdfData)
            globalApplication.showSnackBar(
                homeScreenBinding.btnScan,
                getString(R.string.validate_pdf_download_process)
            )
        } ?: run {
            globalApplication.showSnackBar(
                homeScreenBinding.btnScan,
                getString(R.string.validate_pdf_download_process_failed)
            )
        }
    }
    private fun promptUserForPdfSaveLocation(pdfData: ByteArray?) {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = “application/pdf”
            putExtra(Intent.EXTRA_TITLE, “scannedDocument.pdf”)
        }
        startActivityForResult(intent, 333)
    }

C) Custom PDF creation

private fun createPdf(
        format: PdfFormat,
        bitmaps: MutableList<Uri>,
        selectedDpi: Int
    ): ByteArray {
        val document = PdfDocument()
        val baseDpi = 72f
        val dpiFactor = selectedDpi / baseDpi
        bitmaps.forEachIndexed { index, bitmapUri ->
            val brightnessValue = 70f // Brightness adjustment
            val newBitmap = uriToBitmap(context = this, bitmapUri)
            val adjustedBitmap =
                newBitmap?.let { adjustBrightnessAndApplyGrayscale(it, brightnessValue) }
            val (pageWidth, pageHeight) = when (format) {
                PdfFormat.A4 -> Pair(595, 842)  // DIN A4 dimensions in points
                PdfFormat.A5 -> Pair(420, 595)  // DIN A5 dimensions in points
            }
           val scaledPageWidth = (pageWidth * dpiFactor).toInt()
            val scaledPageHeight = (pageHeight * dpiFactor).toInt()
            val pageInfo =
                PdfDocument.PageInfo.Builder(scaledPageWidth, scaledPageHeight, index + 1).create()
            val page = document.startPage(pageInfo)
            val canvas = page.canvas
            val paint = Paint().apply {
                color = Color.WHITE
                style = Paint.Style.FILL
            }
            canvas.drawRect(0f, 0f, scaledPageWidth.toFloat(), scaledPageHeight.toFloat(), paint)
            val resizedBitmap = adjustedBitmap?.let {
                Bitmap.createScaledBitmap(it, scaledPageWidth, scaledPageHeight, false)
            }
  if (resizedBitmap != null) {
                canvas.drawBitmap(resizedBitmap, 0f, 0f, null)
            }
            document.finishPage(page)
        }
        val outputStream = ByteArrayOutputStream()
        document.writeTo(outputStream)
        document.close()
        return outputStream.toByteArray()
    }

D) Managed to scan the desired image or documents

 private fun scanDocument() {
        scanner?.getStartScanIntent(this)?.addOnSuccessListener { intentSender ->
            scannerLauncher?.launch(IntentSenderRequest.Builder(intentSender).build())
        }?.addOnFailureListener {
            globalApplication.showSnackBar(
                homeScreenBinding.btnScan,
                getString(R.string.validate_no_scanner)
            )
        }
    }

E) Visual representation on the real Android devices

 IAP integration example

A) Managed the network states and custom messages through the application.

B) Managed to store the PDF in the desired location.

C) Managed to create the custom PDFs with multiple page support.

D) Managed to scan any documents or images to generate the PDF.

E) Visual representation of the PDF Generator for Android devices.

Performance & User Experience Optimization

Bitmap Memory Management

Implemented proactive bitmap scaling techniques to reduce image dimensions before intensive operations like PDF conversion, significantly lowering RAM usage.

Used efficient BitmapFactory.Options during image decoding to load scaled versions instead of full-resolution originals.

Ensured proper recycling of bitmap resources immediately after use to prevent memory leaks and minimize the risk of OutOfMemoryError, especially when handling multiple high-DPI scanned images.

Integrated dynamic memory monitoring to adapt bitmap size based on available system memory, ensuring smoother processing on mid- and low-end devices.

Robust Error Handling and User Recovery

Implemented comprehensive permission checks before attempting sensitive operations like camera access, file writes, and storage retrieval, reducing crash risks.

Designed fallback user prompts and clear permission rationales to improve permission acceptance rates and guide users when manual intervention was needed.

Encapsulated all file I/O and critical scan-related operations within structured try-catch blocks to gracefully manage unexpected errors, such as missing storage paths or write failures.

Delivered user-friendly error dialogs and safe exit strategies, maintaining application stability even under abnormal conditions like permission denial or corrupted files.

Hardware Adaptability

Optimized scanning, camera capture, and processing workflows to work efficiently across a wide range of hardware, from high-end flagship devices to low-memory budget phones.

Utilized Android’s hardware capability checks (CameraManager, PackageManager) to dynamically adjust scanning options, image resolutions, and DPI output based on the device’s capabilities.

Scan, Edit & Export PDFs Seamlessly on Android

The Way Forward

Leveraging the Kotlin programming language for Android applications enables faster development, cleaner code, and improved performance. With its modern syntax and full interoperability with Java, Kotlin is now the preferred choice for building robust, scalable mobile apps. As a company specializing in Kotlin Android app development, we deliver high-quality solutions tailored to user needs, from seamless UI to secure backend integration. Whether you’re starting a new project or optimizing an existing one, our expert Android app development team ensures efficiency and innovation at every step. Explore our Kotlin development services to turn your app idea into a powerful Android solution.

Free Consultation

    Lopa Das

    With over 13 years of experience, Lopa Das is a seasoned professional at iFlair Web Technologies Pvt Ltd, specializing in web and mobile app development. Her technical expertise spans across Laravel, PHP, CodeIgniter, CakePHP, React, Vue.js, Nuxt.js, iOS, Android, Flutter, and React Native. Known for her exceptional skills in team handling, client communication, presales, and risk analysis, Lopa ensures seamless project execution from start to finish. Her proficiency in Laravel CRM, Next.js, and mobile app development makes her a valuable asset in delivering robust, scalable solutions.



    MAP_New

    Global Footprints

    Served clients across the globe from38+ countries