首页 文章

在Android上使用Java渲染PDF文件

提问于
浏览
197

我意识到Android没有内置的显示PDF文件的方法 .

如何在Android上使用Java渲染PDF文件?

8 回答

  • 7

    无论如何都无法在Android webview中预览pdf文档 . 如果要预览base64 pdf . 它需要第三方库 .

    的build.gradle

    compile 'com.github.barteksc:android-pdf-viewer:2.7.0'
    

    dialog_pdf_viewer

    <?xml version="1.0" encoding="utf-8"?>
    
    <!--
      ~ Copyright (c) 2017.
      ~ Samet Öztoprak
      ~ All rights reserved.
      -->
    
    <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;
                }
            });
    
        }
    }
    
  • 63

    由于API Level 21(Lollipop)Android提供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();
    

    有关更多信息,请参阅sample app .

    对于较旧的API,我建议Android PdfViewer library,它非常快速且易于使用,在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();
    
  • 59

    Taken from my blog:

    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);
      }
    }
    
  • 32

    我终于能够使用 pdf.js 修改butelo's code以在Android文件系统中打开任何PDF文件 . 代码可以找到on my GitHub

    我所做的是将 pdffile.js 修改为读取HTML参数 file ,如下所示:

    var url = getURLParameter('file');
    
    function getURLParameter(name) {
    return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null}
    

    所以你需要做的就是在_106036之后追加文件路径,如下所示:

    Uri path = Uri.parse(Environment.getExternalStorageDirectory().toString() + "/data/test.pdf");
    webView.loadUrl("file:///android_asset/pdfviewer/index.html?file=" + path);
    

    更新 path 变量以指向Adroid文件系统中的有效PDF .

  • 5

    为此添加一些亮点,我将不得不使用Mozilla的pdf.js解决方案 . 以下是已经写得很好的实现的链接:https://bitbucket.org/butelo/pdfviewer/ .

    以下是我在Android Activity中添加的编辑内容:

    private String getInternalPDFURL(String interalPDFName){
        return "file:///android_asset/pdfviewer/index.html?pdf=" + interalPDFName + ".pdf";
    }
    

    以下是我在 pdffile.js 中所做的编辑:

    var url = '../' + getPDFURL();
    
    function getPDFURL(){
        var query = window.location.search.substring(1);
        var vars = query.split("=");
        var pdfPage = vars[1];
        return pdfPage;
    }
    
  • 2

    我已经从这个和其他类似帖子的一些答案中采用了混合方法:

    此解决方案检查是否安装了PDF阅读器应用程序并执行以下操作: - 如果安装了阅读器,请将PDF文件下载到设备并启动PDF阅读器应用程序 - 如果未安装阅读器,请询问用户是否要查看通过Google Cloud 端硬盘在线PDF文件

    NOTE! 此解决方案使用Android DownloadManager类,它是在API9(Android 2.3或Gingerbread)中引入的 . 这意味着它不适用于Android 2.2或更早版本 .

    我写了一篇关于它的博客文章here,但我已经提供了完整性的完整代码:

    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.
    *
    * <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; } }
  • 1

    我使用以下代码打开并使用Wi-Fi打印PDF . 我发送了我的整个代码,我希望它有用 .

    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);
            }
        };
    }
    
  • 0

    在这里下载源代码(Display PDF file inside my android application

    在您的成绩中添加此依赖项: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 + "-");
                }
            }
        }
    
    }
    

相关问题