Welcome folks today in this blog post we will be seeing how to merge multiple pdf documents
from gallery and save the merged one inside the external storage in android using the iTextPDF
library in java. All the full source code of the application is shown below.
Get Started
In order to get started you need to make a new android
project inside the android studio and then you will see the below directory
structure as shown below at the end
of the project.
Now first of all you need to go to build.gradle
file and copy paste the below dependencies
as shown below
build.gradle
1 2 3 |
dependencies { implementation 'com.itextpdf:itextpdf:5.5.13.2' } |
Now we need to edit the AndroidManifest.xml
file and add the necessary permissions
for saving the pdf
document inside the external storage
and also we need to add the provider
tag as well as shown below
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.DriveApp" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application> </manifest> |
Here you need to replace your own package name
and structure and now we need to create this file_paths.xml
file inside the xml
directory which holds the path where we will be saving the pdf
documents.
xml/file_paths.xml
1 2 3 4 5 6 |
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="." /> </paths> |
Editing the Main Layout
Now we need to edit the activity_main.xml
file for the project where we will have two buttons
for selecting the pdf
documents and also second one to merge the pdf
documents into single one as shown below.
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/select_pdf_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Select PDF files to merge" /> <Button android:id="@+id/merge_pdf_button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Merge PDF files" /> </LinearLayout> |
And now we need to edit the MainActivity.java
file and copy paste the following code
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
package com.example.driveapp; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; import com.itextpdf.text.Document; import com.itextpdf.text.pdf.PdfCopy; import com.itextpdf.text.pdf.PdfReader; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private static final int REQUEST_PICK_PDF_FILES = 1; private List<Uri> mSelectedPdfs = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button selectPdfButton = findViewById(R.id.select_pdf_button); selectPdfButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); intent.setType("application/pdf"); intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); startActivityForResult(intent, REQUEST_PICK_PDF_FILES); } }); Button mergePdfButton = findViewById(R.id.merge_pdf_button); mergePdfButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mSelectedPdfs.isEmpty()) { Toast.makeText(MainActivity.this, "Please select at least one PDF file", Toast.LENGTH_SHORT).show(); return; } try { File mergedPdfFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "merged.pdf"); FileOutputStream outputStream = new FileOutputStream(mergedPdfFile); Document document = new Document(); PdfCopy copy = new PdfCopy(document, outputStream); document.open(); for (Uri pdfUri : mSelectedPdfs) { PdfReader reader = new PdfReader(getContentResolver().openInputStream(pdfUri)); copy.addDocument(reader); reader.close(); } document.close(); outputStream.close(); Toast.makeText(MainActivity.this, "PDF files merged successfully", Toast.LENGTH_SHORT).show(); // Open the merged PDF file using a PDF viewer app Intent intent = new Intent(Intent.ACTION_VIEW); Uri fileUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", mergedPdfFile); intent.setDataAndType(fileUri, "application/pdf"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(intent); } catch (Exception e) { Log.e(TAG, "Error while merging PDF files", e); Toast.makeText(MainActivity.this, "Error while merging PDF files", Toast.LENGTH_SHORT).show(); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_PICK_PDF_FILES && resultCode == RESULT_OK) { mSelectedPdfs.clear(); if (data.getData() != null) { mSelectedPdfs.add(data.getData()); } else if (data.getClipData() != null) { for (int i = 0; i < data.getClipData().getItemCount(); i++) { mSelectedPdfs.add(data.getClipData().getItemAt(i).getUri()); } } Toast.makeText(this, "Selected " + mSelectedPdfs.size() + " PDF files", Toast.LENGTH_SHORT).show(); } } } |
As you can see when we click the button
to select the pdf documents we are opening the gallery
of the user using the Intent
class and then after selecting multiple pdf
documents we are inserting all the pdf documents pages into one pdf document using the iTextPDF
library as shown above. And after merging the pdf documents we are saving the output file inside the external directory
called documents and then we are opening the resultant file inside the pdf viewer as shown below