PDF Rendering in Android App — From raw/assets and Internal Storage

Yash Prakash
This Code
Published in
4 min readOct 1, 2020

Load and display PDFs in your Android app from a PDF contained in the asset/raw folder within your own app or by choosing from the internal storage.

There are so many articles around that do not explain the entire correct process of displaying a PDF in your app. I sat down one day to do the same and got myself a headache reading all those confusing StackOverflow answers.

So, here is the entire process in full with code snippets :

Bonus: I’ve made a small project, an app that implements gesture based eBook reading called: Gesty. It implements quite a few concepts described in this article, so if you want to see the code in action, visit here:

PART A: When you need to load a PDF from within the app:

Step 1: Make a ‘raw’ folder inside the main/res directory. Then, place your pdf within it and rename it to something simpler, for here we rename it to sample.pdf.

Or

Make an ‘asset’ folder inside the ‘main’ directory, and do the same.

Step 2: Inside your Activity, make a new method: openPdfFromRaw

void openPdfFromRaw(ImageView imageView, int pageNumber) throws IOException {    // Copy sample.pdf from 'res/raw' folder into cache so PdfRenderer can handle it
File fileCopy = new File(getCacheDir(), FILE_NAME);
copyToCache(fileCopy, R.raw.sample);
// We get a page from the PDF doc by calling 'open'
ParcelFileDescriptor fileDescriptor =
ParcelFileDescriptor.open(fileCopy,
ParcelFileDescriptor.MODE_READ_ONLY);
mPdfRenderer = new PdfRenderer(fileDescriptor);
mPdfPage = mPdfRenderer.openPage(pageNumber);
// Create a new bitmap and render the page contents into it
Bitmap bitmap = Bitmap.createBitmap(mPdfPage.getWidth(),
mPdfPage.getHeight(),
Bitmap.Config.ARGB_8888);
mPdfPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
// Set the bitmap in the ImageView
imageView.setImageBitmap(bitmap);
}

Note: PdfRenderer displays one page of the document at a time in an imageview. Thus the ‘pagenumber’ argument. So after understanding this tutorial, you need to add your own logic of adding page numbers and opening the next page on press of a button, etc.

In case of an asset, do this:

InputStream input = context.getAssets().open(FILENAME); FileOutputStream output = new FileOutputStream(file);// where 'file' comes from :
File file = new File(context.getCacheDir(), FILENAME);

Step 3: We made a call to ‘copyToCache’ method. We write it down here:

void copyToCache(File file, @RawRes int pdfResource) throws IOException {

if (!outputFile.exists()) {
//Get input stream object to read the pdf
InputStream input = getResources().openRawResource(pdfResource);
FileOutputStream output = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int size;
// Copy the entire contents of the file
while ((size = input.read(buffer)) != -1) {
output.write(buffer, 0, size);
}
//Close the buffer
input.close();
output.close();
}
}

Step 4: Done! Just call the openPdfFromRaw method from anywhere you want to load the pdf and display it:

openPdfFromRaw(myImageview, pageNumberIWantToDisplay);

PART 2: When you need to display a PDF from the storage:

Step 1: Add the permission to the Manifest first:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

I am not displaying the long drawn logic of checking the permission from the user here. Assuming you already know how to do it ! 😉

Step 2: Make a method named openPdfFromStorage like this:

private void openPdfFromStorage(Uri uri) throws IOException {
File fileCopy = new File(getCacheDir(), FILE_NAME);//anything as the name
copyToCache(fileCopy, uri);
// Get a page from the PDF doc by calling 'open'
ParcelFileDescriptor fileDescriptor =
ParcelFileDescriptor.open(fileCopy,
ParcelFileDescriptor.MODE_READ_ONLY);
mPdfRenderer = new PdfRenderer(fileDescriptor);
mPdfPage = mPdfRenderer.openPage(1);
// Create a new bitmap and render the page contents into it
Bitmap bitmap = Bitmap.createBitmap(mPdfPage.getWidth(),
mPdfPage.getHeight(),
Bitmap.Config.ARGB_8888);//Not RGB, but ARGB
mPdfPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
// Set the bitmap in the ImageView imageView.setImageBitmap(bitmap);}

Step 3: We already made the copyToCache method, just one line differs in this case:

In place of :

InputStream input = getResources().openRawResource(pdfResource);

Place this line:

InputStream input = getContentResolver().openInputStream(uri);
//where, the uri is the uri from onActivityResult from the picker we //make. Coming up ahead!

Step 4: Make a document picker like this:

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("application/pdf");
//since we are only dealing with pdfs here
startActivityForResult(intent, 101);

and make the onActivityResult like this:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
Uri uri = data.getData();
Log.e("URI: ", uri.toString());
try {
//call your either method here
//openPdfFromRaw(imageView, 1);
openPdfFromStorage(uri);
} catch (IOException e) {
e.printStackTrace();
}
}
}

aaaannd that’s it! 😅

There we go, we have successfully displayed a PDF in our app!

Thank you for reading, please leave a few claps to if you find it helpful!

Do you want to get one free, clean email from me every week or two weeks containing the best of my curated articles and tutorials that I publish? Join my Codecast!

Connect with me on Twitter and LinkedIn!

--

--

Yash Prakash
This Code

Software engineer → Solopreneur ⦿ Scaling my own 1-person business model ⦿ Writing for busy founders and business owners.