Open In App

Generate PDF File in Android using Jetpack Compose

Last Updated : 10 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

There are many apps in which data from the app is provided to users in the downloadable PDF file format. So in this case we have to create a PDF file from the data present inside our app and represent that data properly inside our app. So by using this technique we can easily create a new PDF according to our requirements.

In this article, we will take a look at creating a new PDF file from the data present within our android application using Jetpack Compose in Android. 

Steps to Generate PDF File in Android

Step 1: Create a New Project in Android Studio

To create a new project in the Android Studio, please refer to How to Create a new Project in Android Studio with Jetpack Compose.

Step 2: Adding images to the drawable folder

  • Copy the image which you want to add to your PDF file.
  • Navigate to app>res>drawable.
  • Right-click on it and paste all the images into the drawable folder.


Step 3: Adding permissions in AndroidManifest.xml

Navigate to app > manifests > AndroidManifest.xml and add the below permission to it for writing in the external storage (for until Android 9 only). 

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />


Step 4: Working with the MainActivity.kt file

Go to the MainActivity.kt file and refer to the following code. Below is the code for the MainActivity.kt file. Comments are added inside the code to understand the code in more detail.

MainActivity.kt:

Kotlin
package com.geeksforgeeks.demo

import android.Manifest
import android.content.Context
import android.graphics.*
import android.graphics.pdf.PdfDocument
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
import com.geeksforgeeks.demo.ui.theme.DemoTheme
import java.io.File
import java.io.FileOutputStream

class MainActivity : ComponentActivity() {

    // Launcher for handling permission requests
    private val requestPermissionsLauncher =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            val granted = permissions.entries.all { it.value }
            if (granted) {
                Toast.makeText(this, "Permissions Granted.", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Permission Denied.", Toast.LENGTH_SHORT).show()
            }
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Check and request required permissions
        checkAndRequestPermissions()

        // Set the Jetpack Compose UI
        setContent {
            DemoTheme(dynamicColor = false, darkTheme = false) {
                Surface(color = Color.White) {
                
                    // Display the UI component
                    PdfGenerator() 
                }
            }
        }
    }

    // Function to check and request
    // necessary permissions
    private fun checkAndRequestPermissions() {
        val requiredPermissions = mutableListOf<String>()

        // Request WRITE_EXTERNAL_STORAGE only
        // for Android 9 and below
        if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q) {
            requiredPermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
        }

        // Request permissions if any are needed
        if (requiredPermissions.isNotEmpty()) {
            requestPermissionsLauncher.launch(requiredPermissions.toTypedArray())
        }
    }
}

@Composable
fun PdfGenerator() {
    val context = LocalContext.current

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // Title text
        Text(
            text = "PDF Generator",
            color = Color.Black,
            fontWeight = FontWeight.Bold,
            textAlign = TextAlign.Center,
            fontSize = 20.sp
        )

        Spacer(modifier = Modifier.height(40.dp))

        // Button to generate the PDF
        Button(
            modifier = Modifier
                .fillMaxWidth()
                .padding(20.dp),
            onClick = { generatePDF(context) }
        ) {
            Text(modifier = Modifier.padding(6.dp), text = "Generate PDF")
        }
    }
}

// Function to generate a simple PDF document
fun generatePDF(context: Context) {

    // Define the page height
    val pageHeight = 1120  
    
    // Define the page width
    val pageWidth = 792    
    
    // Create a new PDF document
    val pdfDocument = PdfDocument() 

    // Paint object for drawing
    val paint = Paint() 
    
    // Paint object for text
    val title = Paint() 

    // Load an image from resources 
    // (ensure R.drawable.gfg_logo exists)
    val bmp: Bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.gfg_logo)
    
    // Resize the image
    val scaledBitmap = Bitmap.createScaledBitmap(bmp, 140, 140, false) 

    // Create a PDF page with specified width and height
    val myPageInfo = PdfDocument.PageInfo.Builder(pageWidth, pageHeight, 1).create()
    val myPage = pdfDocument.startPage(myPageInfo)

    // Get the canvas to draw on
    val canvas: Canvas = myPage.canvas

    // Draw the image onto the PDF
    canvas.drawBitmap(scaledBitmap, 56F, 40F, paint)

    // Configure text properties
    title.apply {
        typeface = Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)
        textSize = 16F
        color = Color.Black.toArgb()
    }

    // Draw text onto the PDF
    canvas.drawText("A portal for IT professionals.", 209F, 120F, title)
    canvas.drawText("Geeks for Geeks", 209F, 100F, title)
    title.textAlign = Paint.Align.CENTER
    canvas.drawText("This is a sample document which we have created.", 396F, 560F, title)

    // Finish writing to the page
    pdfDocument.finishPage(myPage)

    // Define a file path in the app's
    // private storage (no permissions required)
    val file = File(context.getExternalFilesDir(null), "GFG.pdf")

    try {
    
        // Write the PDF to the file
        pdfDocument.writeTo(FileOutputStream(file))
        Toast.makeText(context, "PDF saved at ${file.absolutePath}", Toast.LENGTH_SHORT).show()
    } catch (e: Exception) {
        e.printStackTrace()
        Toast.makeText(context, "Failed to generate PDF", Toast.LENGTH_SHORT).show()
    }

    // Close the document
    pdfDocument.close()
}

Output:



Next Article
Article Tags :

Similar Reads