Android does not have PDF support in its libraries. Is there any way to render PDF files in the Android applications?
Since API Level 21 (Lollipop) Android provides a PdfRenderer class:
// create a new renderer
PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
// let us just render all pages
final int pageCount = renderer.getPageCount();
for (int i = 0; i < pageCount; i++) {
Page page = renderer.openPage(i);
// say we render for showing on the screen
page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
// do stuff with the bitmap
// close the page
page.close();
}
// close the renderer
renderer.close();
For more information see the sample app.
For older APIs I recommend Android PdfViewer library, it is very fast and easy to use, licensed under Apache License 2.0:
pdfView.fromAsset(String)
.pages(0, 2, 1, 3, 3, 3) // all pages are displayed by default
.enableSwipe(true)
.swipeHorizontal(false)
.enableDoubletap(true)
.defaultPage(0)
.onDraw(onDrawListener)
.onLoad(onLoadCompleteListener)
.onPageChange(onPageChangeListener)
.onPageScroll(onPageScrollListener)
.onError(onErrorListener)
.enableAnnotationRendering(false)
.password(null)
.scrollHandle(null)
.load();
PDFView Library
? What should we put in pdfName
? What do the functions onDraw
, onLoad
, and onPageChange
listener look like? Thanks for your help :) –
Obstipation public class MyPdfViewActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView mWebView=new WebView(MyPdfViewActivity.this);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setPluginsEnabled(true);
mWebView.loadUrl("https://docs.google.com/gview?embedded=true&url="+LinkTo);
setContentView(mWebView);
}
}
I have made a hybrid approach from some of the answers given to this and other similar posts:
This solution checks if a PDF reader app is installed and does the following: - If a reader is installed, download the PDF file to the device and start a PDF reader app - If no reader is installed, ask the user if he wants to view the PDF file online through Google Drive
NOTE! This solution uses the Android DownloadManager
class, which was introduced in API9 (Android 2.3 or Gingerbread). This means that it doesn't work on Android 2.2 or earlier.
I wrote a blog post about it here, but I've provided the full code below for completeness:
public class PDFTools {
private static final String GOOGLE_DRIVE_PDF_READER_PREFIX = "http://drive.google.com/viewer?url=";
private static final String PDF_MIME_TYPE = "application/pdf";
private static final String HTML_MIME_TYPE = "text/html";
/**
* If a PDF reader is installed, download the PDF file and open it in a reader.
* Otherwise ask the user if he/she wants to view it in the Google Drive online PDF reader.<br />
* <br />
* <b>BEWARE:</b> This method
* @param context
* @param pdfUrl
* @return
*/
public static void showPDFUrl( final Context context, final String pdfUrl ) {
if ( isPDFSupported( context ) ) {
downloadAndOpenPDF(context, pdfUrl);
} else {
askToOpenPDFThroughGoogleDrive( context, pdfUrl );
}
}
/**
* Downloads a PDF with the Android DownloadManager and opens it with an installed PDF reader app.
* @param context
* @param pdfUrl
*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static void downloadAndOpenPDF(final Context context, final String pdfUrl) {
// Get filename
final String filename = pdfUrl.substring( pdfUrl.lastIndexOf( "/" ) + 1 );
// The place where the downloaded PDF file will be put
final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), filename );
if ( tempFile.exists() ) {
// If we have downloaded the file before, just go ahead and show it.
openPDF( context, Uri.fromFile( tempFile ) );
return;
}
// Show progress dialog while downloading
final ProgressDialog progress = ProgressDialog.show( context, context.getString( R.string.pdf_show_local_progress_title ), context.getString( R.string.pdf_show_local_progress_content ), true );
// Create the download request
DownloadManager.Request r = new DownloadManager.Request( Uri.parse( pdfUrl ) );
r.setDestinationInExternalFilesDir( context, Environment.DIRECTORY_DOWNLOADS, filename );
final DownloadManager dm = (DownloadManager) context.getSystemService( Context.DOWNLOAD_SERVICE );
BroadcastReceiver onComplete = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if ( !progress.isShowing() ) {
return;
}
context.unregisterReceiver( this );
progress.dismiss();
long downloadId = intent.getLongExtra( DownloadManager.EXTRA_DOWNLOAD_ID, -1 );
Cursor c = dm.query( new DownloadManager.Query().setFilterById( downloadId ) );
if ( c.moveToFirst() ) {
int status = c.getInt( c.getColumnIndex( DownloadManager.COLUMN_STATUS ) );
if ( status == DownloadManager.STATUS_SUCCESSFUL ) {
openPDF( context, Uri.fromFile( tempFile ) );
}
}
c.close();
}
};
context.registerReceiver( onComplete, new IntentFilter( DownloadManager.ACTION_DOWNLOAD_COMPLETE ) );
// Enqueue the request
dm.enqueue( r );
}
/**
* Show a dialog asking the user if he wants to open the PDF through Google Drive
* @param context
* @param pdfUrl
*/
public static void askToOpenPDFThroughGoogleDrive( final Context context, final String pdfUrl ) {
new AlertDialog.Builder( context )
.setTitle( R.string.pdf_show_online_dialog_title )
.setMessage( R.string.pdf_show_online_dialog_question )
.setNegativeButton( R.string.pdf_show_online_dialog_button_no, null )
.setPositiveButton( R.string.pdf_show_online_dialog_button_yes, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openPDFThroughGoogleDrive(context, pdfUrl);
}
})
.show();
}
/**
* Launches a browser to view the PDF through Google Drive
* @param context
* @param pdfUrl
*/
public static void openPDFThroughGoogleDrive(final Context context, final String pdfUrl) {
Intent i = new Intent( Intent.ACTION_VIEW );
i.setDataAndType(Uri.parse(GOOGLE_DRIVE_PDF_READER_PREFIX + pdfUrl ), HTML_MIME_TYPE );
context.startActivity( i );
}
/**
* Open a local PDF file with an installed reader
* @param context
* @param localUri
*/
public static final void openPDF(Context context, Uri localUri ) {
Intent i = new Intent( Intent.ACTION_VIEW );
i.setDataAndType( localUri, PDF_MIME_TYPE );
context.startActivity( i );
}
/**
* Checks if any apps are installed that supports reading of PDF files.
* @param context
* @return
*/
public static boolean isPDFSupported( Context context ) {
Intent i = new Intent( Intent.ACTION_VIEW );
final File tempFile = new File( context.getExternalFilesDir( Environment.DIRECTORY_DOWNLOADS ), "test.pdf" );
i.setDataAndType( Uri.fromFile( tempFile ), PDF_MIME_TYPE );
return context.getPackageManager().queryIntentActivities( i, PackageManager.MATCH_DEFAULT_ONLY ).size() > 0;
}
}
Download the source code here (Display PDF file inside my android application)
Add this dependency in your Grade:
compile com.github.barteksc:android-pdf-viewer:2.0.3
activity_main.xml
<RelativeLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/colorPrimaryDark"
android:text="View PDF"
android:textColor="#ffffff"
android:id="@+id/tv_header"
android:textSize="18dp"
android:gravity="center"></TextView>
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfView"
android:layout_below="@+id/tv_header"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
MainActivity.java
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.github.barteksc.pdfviewer.PDFView;
import com.github.barteksc.pdfviewer.listener.OnLoadCompleteListener;
import com.github.barteksc.pdfviewer.listener.OnPageChangeListener;
import com.github.barteksc.pdfviewer.scroll.DefaultScrollHandle;
import com.shockwave.pdfium.PdfDocument;
import java.util.List;
public class MainActivity extends Activity implements OnPageChangeListener,OnLoadCompleteListener{
private static final String TAG = MainActivity.class.getSimpleName();
public static final String SAMPLE_FILE = "android_tutorial.pdf";
PDFView pdfView;
Integer pageNumber = 0;
String pdfFileName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pdfView= (PDFView)findViewById(R.id.pdfView);
displayFromAsset(SAMPLE_FILE);
}
private void displayFromAsset(String assetFileName) {
pdfFileName = assetFileName;
pdfView.fromAsset(SAMPLE_FILE)
.defaultPage(pageNumber)
.enableSwipe(true)
.swipeHorizontal(false)
.onPageChange(this)
.enableAnnotationRendering(true)
.onLoad(this)
.scrollHandle(new DefaultScrollHandle(this))
.load();
}
@Override
public void onPageChanged(int page, int pageCount) {
pageNumber = page;
setTitle(String.format("%s %s / %s", pdfFileName, page + 1, pageCount));
}
@Override
public void loadComplete(int nbPages) {
PdfDocument.Meta meta = pdfView.getDocumentMeta();
printBookmarksTree(pdfView.getTableOfContents(), "-");
}
public void printBookmarksTree(List<PdfDocument.Bookmark> tree, String sep) {
for (PdfDocument.Bookmark b : tree) {
Log.e(TAG, String.format("%s %s, p %d", sep, b.getTitle(), b.getPageIdx()));
if (b.hasChildren()) {
printBookmarksTree(b.getChildren(), sep + "-");
}
}
}
}
assetFileName
pdf file should exist into assets
folder –
Phyliciaphylis you can use a simple method by import
implementation 'com.github.barteksc:android-pdf-viewer:2.8.2'
and the XML code is
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfv"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.github.barteksc.pdfviewer.PDFView>
and just declare and add a file to an asset folder and just assign the name
PDFView pdfView=findViewById(R.id.pdfv);
pdfView.fromAsset("agl.pdf").load();
PdfiumAndroid
which itself is already 18.4MB –
Sabu agl.pdf
file should exist into assets
folder –
Phyliciaphylis I finally was able to modify butelo's code to open any PDF file in the Android filesystem using pdf.js
. The code can be found on my GitHub
What I did was modified the pdffile.js
to read HTML argument file
like this:
var url = getURLParameter('file');
function getURLParameter(name) {
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null}
So what you need to do is just append the file path after the index.html
like this:
Uri path = Uri.parse(Environment.getExternalStorageDirectory().toString() + "/data/test.pdf");
webView.loadUrl("file:///android_asset/pdfviewer/index.html?file=" + path);
Update the path
variable to point to a valid PDF in the Adroid filesystem.
To add a little light to this, I would have to go with the pdf.js solution from Mozilla. Here is the link to an already well written implementation of this: https://bitbucket.org/butelo/pdfviewer/.
Here are the edits that I added in my Android Activity:
private String getInternalPDFURL(String interalPDFName){
return "file:///android_asset/pdfviewer/index.html?pdf=" + interalPDFName + ".pdf";
}
Here are the edits I made in pdffile.js
:
var url = '../' + getPDFURL();
function getPDFURL(){
var query = window.location.search.substring(1);
var vars = query.split("=");
var pdfPage = vars[1];
return pdfPage;
}
Here is how you can get the thumbnail as Bitmap
from a PDF file without using any third-party library.
private fun loadThumbnailFromPdfFile(file:File, thumbnailImageView: ImageView) {
Log.d(TAG, "loadThumbnailFromPdfFile: ")
val mFileDescriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY)
// This is the PdfRenderer we use to render the PDF.
val mPdfRenderer = PdfRenderer(mFileDescriptor)
//check if pdf have no pages then we can't show pdf thumbnail
if (mPdfRenderer.pageCount <= 0) {
//No pages in pdf, can't show thumbnail
Log.d(TAG, "loadThumbnailFromPdfFile: No pages in pdf")
} else {
//There are page(s) in pdf, can show pdf thumbnail
//Use `openPage` to open a specific page in PDF.
val mCurrentPage = mPdfRenderer.openPage(0)
// Important: the destination bitmap must be ARGB (not RGB).
val bitmap = Bitmap.createBitmap(mCurrentPage.width, mCurrentPage.height, Bitmap.Config.ARGB_8888)
// Here, we render the page onto the Bitmap.
// To render a portion of the page, use the second and third parameter. Pass nulls to get
// the default result.
// Pass either RENDER_MODE_FOR_DISPLAY or RENDER_MODE_FOR_PRINT for the last parameter.
mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
// We are ready to show the Bitmap to user.
thumbnailImageView.setImageBitmap(bitmap)
}
}
I used the below code to open and print the PDF using Wi-Fi. I am sending my whole code, and I hope it is helpful.
public class MainActivity extends Activity {
int Result_code = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button mButton = (Button)findViewById(R.id.button1);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
PrintManager printManager = (PrintManager)getSystemService(Context.PRINT_SERVICE);
String jobName = " Document";
printManager.print(jobName, pda, null);
}
});
}
public void openDocument(String name) {
Intent intent = new Intent(android.content.Intent.ACTION_VIEW);
File file = new File(name);
String extension = android.webkit.MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString());
String mimetype = android.webkit.MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (extension.equalsIgnoreCase("") || mimetype == null) {
// if there is no extension or there is no definite mimetype, still try to open the file
intent.setDataAndType(Uri.fromFile(file), "text/*");
}
else {
intent.setDataAndType(Uri.fromFile(file), mimetype);
}
// custom message for the intent
startActivityForResult((Intent.createChooser(intent, "Choose an Application:")), Result_code);
//startActivityForResult(intent, Result_code);
//Toast.makeText(getApplicationContext(),"There are no email clients installed.", Toast.LENGTH_SHORT).show();
}
@SuppressLint("NewApi")
PrintDocumentAdapter pda = new PrintDocumentAdapter(){
@Override
public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback){
InputStream input = null;
OutputStream output = null;
try {
String filename = Environment.getExternalStorageDirectory() + "/" + "Holiday.pdf";
File file = new File(filename);
input = new FileInputStream(file);
output = new FileOutputStream(destination.getFileDescriptor());
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
output.write(buf, 0, bytesRead);
}
callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES});
}
catch (FileNotFoundException ee){
//Catch exception
}
catch (Exception e) {
//Catch exception
}
finally {
try {
input.close();
output.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras){
if (cancellationSignal.isCanceled()) {
callback.onLayoutCancelled();
return;
}
// int pages = computePageCount(newAttributes);
PrintDocumentInfo pdi = new PrintDocumentInfo.Builder("Name of file").setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).build();
callback.onLayoutFinished(pdi, true);
}
};
}
There is no anyway to preview pdf document in Android webview.If you want to preview base64 pdf. It requires to third-party library.
build.Gradle
compile 'com.github.barteksc:android-pdf-viewer:2.7.0'
dialog_pdf_viewer
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<ImageView
android:id="@+id/dialog_pdf_viewer_close"
style="@style/ExitButtonImageViewStyle"
android:src="@drawable/popup_exit" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/white"
android:orientation="vertical">
<com.github.barteksc.pdfviewer.PDFView
android:id="@+id/pdfView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<View style="@style/HorizontalLine" />
<com.pozitron.commons.customviews.ButtonFont
android:id="@+id/dialog_pdf_viewer_button"
style="@style/ButtonPrimary2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="15dp"
android:text="@string/agreed" />
</LinearLayout>
DailogPDFViewer.java
public class DialogPdfViewer extends Dialog {
PDFView pdfView;
byte[] decodedString;
public interface OnDialogPdfViewerListener {
void onAgreeClick(DialogPdfViewer dialogFullEula);
void onCloseClick(DialogPdfViewer dialogFullEula);
}
public DialogPdfViewer(Context context, String base64, final DialogPdfViewer.OnDialogPdfViewerListener onDialogPdfViewerListener) {
super(context);
setContentView(R.layout.dialog_pdf_viewer);
findViewById(R.id.dialog_pdf_viewer_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDialogPdfViewerListener.onCloseClick(DialogPdfViewer.this);
}
});
findViewById(R.id.dialog_pdf_viewer_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onDialogPdfViewerListener.onAgreeClick(DialogPdfViewer.this);
}
});
decodedString = Base64.decode(base64.toString(), Base64.DEFAULT);
pdfView = ((PDFView) findViewById(R.id.pdfView));
pdfView.fromBytes(decodedString).load();
setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
onDialogPdfViewerListener.onCloseClick(DialogPdfViewer.this);
}
return true;
}
});
}
}
I had problems with the GoogleDrive option, sometimes it would fail to load the document and 'com.github.barteksc:android-pdf-viewer:2.7.0', though it's documentation makes it seem very easy to load a document from a link, I failed to make it work. It was always throwing a FileNotFoundException, so upon further research I got to understand that it downloads the pdf, so you'll have to make it point to that document, which I found to be a bit tedious.
You could try using this library here. It is very easy to use and is still being maintained as of date, I don't know a few years from now if they are to stop updating it. It caches the document and you don't even need to trace it's path.
https://levelup.gitconnected.com/open-pdf-files-in-android-without-webviews-or-intents-3cc960752cca
© 2022 - 2024 — McMap. All rights reserved.