【问题标题】:Convert a Pdf page into Bitmap in Android Java在 Android Java 中将 Pdf 页面转换为位图
【发布时间】:2012-02-07 13:01:14
【问题描述】:

我需要在 Android 中将 PDF 文件(PDF 页面)转换为位图(或图像文件)。

1.使用 Apache 的 Pdfbox jar。但它使用了一些 android 不支持的 java 类。 2.尝试了将图像转换为pdf的Itext jar(我需要它的反向操作) 像这样,我尝试了很多罐子。但没有阳性结果。

byte[] bytes;
    try {

        File file = new File(this.getFilesDir().getAbsolutePath()+"/2010Q2_SDK_Overview.pdf");
        FileInputStream is = new FileInputStream(file);

        // Get the size of the file
        long length = file.length();
        bytes = new byte[(int) length];
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
            offset += numRead;
        }


        ByteBuffer buffer = ByteBuffer.NEW(bytes);
        String data = Base64.encodeToString(bytes, Base64.DEFAULT);
        PDFFile pdf_file = new PDFFile(buffer);
        PDFPage page = pdf_file.getPage(2);

        RectF rect = new RectF(0, 0, (int) page.getBBox().width(),
                (int) page.getBBox().height());
      //  Bitmap bufferedImage = Bitmap.createBitmap((int)rect.width(), (int)rect.height(),
         //        Bitmap.Config.ARGB_8888);

        Bitmap image = page.getImage((int)rect.width(), (int)rect.height(), rect);
        FileOutputStream os = new FileOutputStream(this.getFilesDir().getAbsolutePath()+"/pdf.jpg");
        image.compress(Bitmap.CompressFormat.JPEG, 80, os);

       // ((ImageView) findViewById(R.id.testView)).setImageBitmap(image);

我正在获取图像文件,

而不是,

package com.test123;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import net.sf.andpdf.nio.ByteBuffer;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Base64;

public class Test123Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        byte[] bytes;
        try {

            File file = new File(this.getFilesDir().getAbsolutePath()+"/2010Q2_SDK_Overview.pdf");
            FileInputStream is = new FileInputStream(file);

            // Get the size of the file
            long length = file.length();
            bytes = new byte[(int) length];
            int offset = 0;
            int numRead = 0;
            while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                offset += numRead;
            }


            ByteBuffer buffer = ByteBuffer.NEW(bytes);
            String data = Base64.encodeToString(bytes, Base64.DEFAULT);
            PDFFile pdf_file = new PDFFile(buffer);
            PDFPage page = pdf_file.getPage(2);

            RectF rect = new RectF(0, 0, (int) page.getBBox().width(),
                    (int) page.getBBox().height());
          //  Bitmap bufferedImage = Bitmap.createBitmap((int)rect.width(), (int)rect.height(),
             //        Bitmap.Config.ARGB_8888);

            Bitmap image = page.getImage((int)rect.width(), (int)rect.height(), rect);
            FileOutputStream os = new FileOutputStream(this.getFilesDir().getAbsolutePath()+"/pdf.jpg");
            image.compress(Bitmap.CompressFormat.JPEG, 80, os);

            //((ImageView) findViewById(R.id.testView)).setImageBitmap(image);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

另外,还有其他方法可以使用应用程序内置的功能在 android 中显示 pdf 文件吗?

【问题讨论】:

  • 我们可以使用java中的awt工具将pdf转换为图像。但是android不支持awt。我也在使用itext..如果你知道python你可以使用ghostscript将pdf转换为位图。
  • 我不知道 python.. 有没有办法在 java 中做到这一点?
  • 请看上面的代码。我已经使用了链接中的 jar,github.com/jblough/Android-Pdf-Viewer-Library/blob/master/… 我可以将 PDFpage 转换为 jpg 文件。但是转换后的图像是部分转换的。我不知道我错在哪里?
  • 你给出的代码是什么?这行得通吗?
  • 它在某种意义上是有效的,我得到的是第一张图片而不是第二张。

标签: android pdf


【解决方案1】:

我解决了这个问题。就像让设备有时间渲染每个页面一样简单。

要解决这个问题,你所要做的就是改变

PDFPage page = pdf_file.getPage(2);

PDFPage page = pdf_file.getPage(2, true);

首先要在 Android 中查看 PDF,您必须将 PDF 转换为图像,然后将它们显示给用户。 (我将使用 webview)

因此,我们需要这个library。这是我编辑的这个git

将库导入项目后,您需要创建活动。

XML:

<?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">

    <WebView
            android:id="@+id/webView1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

</LinearLayout>

java:

//Imports:
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.webkit.WebView;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFImage;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFPaint;
import net.sf.andpdf.nio.ByteBuffer;
import net.sf.andpdf.refs.HardReference;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;

//Globals:
private WebView wv;
private int ViewSize = 0;

//OnCreate Method:
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //Settings
    PDFImage.sShowImages = true; // show images
    PDFPaint.s_doAntiAlias = true; // make text smooth
    HardReference.sKeepCaches = true; // save images in cache

    //Setup webview
    wv = (WebView)findViewById(R.id.webView1);
    wv.getSettings().setBuiltInZoomControls(true);//show zoom buttons
    wv.getSettings().setSupportZoom(true);//allow zoom
    //get the width of the webview
    wv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
    {
        @Override
        public void onGlobalLayout()
        {
            ViewSize = wv.getWidth();
            wv.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    });

    try
    {
        File file = new File(Environment.getExternalStorageDirectory().getPath() + "/randompdf.pdf");
        RandomAccessFile f = new RandomAccessFile(file, "r");
        byte[] data = new byte[(int)f.length()];
        f.readFully(data);
        pdfLoadImages(data);
    }
    catch(Exception ignored)
    {
    }
}

//Load Images:
private void pdfLoadImages(final byte[] data)
{
    try
    {
        // run async
        new AsyncTask<Void, Void, String>()
        {
            // create and show a progress dialog
            ProgressDialog progressDialog = ProgressDialog.show(MainActivity.this, "", "Opening...");

            @Override
            protected void onPostExecute(String html)
            {
                //after async close progress dialog
                progressDialog.dismiss();
                //load the html in the webview
                wv.loadDataWithBaseURL("", html, "text/html","UTF-8", "");
            }

            @Override
            protected String doInBackground(Void... params)
            {
                try
                {
                    //create pdf document object from bytes
                    ByteBuffer bb = ByteBuffer.NEW(data);
                    PDFFile pdf = new PDFFile(bb);
                    //Get the first page from the pdf doc
                    PDFPage PDFpage = pdf.getPage(1, true);
                    //create a scaling value according to the WebView Width
                    final float scale = ViewSize / PDFpage.getWidth() * 0.95f;
                    //convert the page into a bitmap with a scaling value
                    Bitmap page = PDFpage.getImage((int)(PDFpage.getWidth() * scale), (int)(PDFpage.getHeight() * scale), null, true, true);
                    //save the bitmap to a byte array
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    page.compress(Bitmap.CompressFormat.PNG, 100, stream);
                    byte[] byteArray = stream.toByteArray();
                    stream.reset();
                    //convert the byte array to a base64 string
                    String base64 = Base64.encodeToString(byteArray, Base64.NO_WRAP);
                    //create the html + add the first image to the html
                    String html = "<!DOCTYPE html><html><body bgcolor=\"#b4b4b4\"><img src=\"data:image/png;base64,"+base64+"\" hspace=10 vspace=10><br>";
                    //loop though the rest of the pages and repeat the above
                    for(int i = 2; i <= pdf.getNumPages(); i++)
                    {
                        PDFpage = pdf.getPage(i, true);
                        page = PDFpage.getImage((int)(PDFpage.getWidth() * scale), (int)(PDFpage.getHeight() * scale), null, true, true);
                        page.compress(Bitmap.CompressFormat.PNG, 100, stream);
                        byteArray = stream.toByteArray();
                        stream.reset();
                        base64 = Base64.encodeToString(byteArray, Base64.NO_WRAP);
                        html += "<img src=\"data:image/png;base64,"+base64+"\" hspace=10 vspace=10><br>";
                    }
                    stream.close();
                    html += "</body></html>";
                    return html;
                }
                catch (Exception e)
                {
                    Log.d("error", e.toString());
                }
                return null;
            }
        }.execute();
        System.gc();// run GC
    }
    catch (Exception e)
    {
        Log.d("error", e.toString());
    }
}

【讨论】:

  • 此解决方案有效,但图像不会在位图中绘制,即使 .sShowImagesset 为 true 和您的库版本也是如此。您知道为什么会发生这种情况吗?
  • 我已经下载了你的库,现在请告诉我,你使用什么导入?
  • 为什么不直接使用 IDE 附带的添加缺失导入功能?
  • PDFFile pdf = new PDFFile(bb);在 E/CounterA 行中:java.lang.NullPointerException。如何解决这个问题?
  • @NicolasTyler 我知道在上面的例子中图像没有存储请告诉我我在哪里显示转换后的位图,因为在活动中这只显示空白布局。我必须将 PDF 文件放在资产文件夹或其他地方吗?请提出建议。
【解决方案2】:

我知道这个问题很老,但上周我遇到了这个问题,没有一个答案真的对我有用。

以下是我在不使用第三方库的情况下解决此问题的方法。

基于android开发者site使用android的PDFRenderer类(API 21+)的代码,我写了如下方法:

private  ArrayList<Bitmap> pdfToBitmap(File pdfFile) {
    ArrayList<Bitmap> bitmaps = new ArrayList<>();

    try {
        PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_ONLY));

        Bitmap bitmap;
        final int pageCount = renderer.getPageCount();
        for (int i = 0; i < pageCount; i++) {
            PdfRenderer.Page page = renderer.openPage(i);

            int width = getResources().getDisplayMetrics().densityDpi / 72 * page.getWidth();
            int height = getResources().getDisplayMetrics().densityDpi / 72 * page.getHeight();
            bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

            page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

            bitmaps.add(bitmap);

            // close the page
            page.close();

        }

        // close the renderer
        renderer.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return bitmaps;

}

该方法返回一个位图数组,pdf文件中的每一页都有一个位图。

高度和宽度基于this answer 计算,以创建质量更好的图像。

【讨论】:

  • 这会导致OOM异常。
  • 您可以尝试使用 ARGB_4444,它占用的内存要少得多
  • 像魅力一样工作!!!我浪费了一天时间来实施其他解决方案,最后,这就像魅力:)
  • 为位图添加背景添加此代码stackoverflow.com/a/45297757/8258305
【解决方案3】:

这个问题有点老了,但我今天也必须这样做,所以这是我的解决方案:

/**
 * Use this to load a pdf file from your assets and render it to a Bitmap.
 * 
 * @param context
 *            current context.
 * @param filePath
 *            of the pdf file in the assets.
 * @return a bitmap.
 */
@Nullable
public static Bitmap renderToBitmap(Context context, String filePath) {
    Bitmap bi = null;
    InputStream inStream = null;
    try {
        AssetManager assetManager = context.getAssets();
        Log.d(TAG, "Attempting to copy this file: " + filePath);
        inStream = assetManager.open(filePath);
        bi = renderToBitmap(context, inStream);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inStream.close();
        } catch (IOException e) {
            // do nothing because the stream has already been closed
        }
    }
    return bi;
}

/**
 * Use this to render a pdf file given as InputStream to a Bitmap.
 * 
 * @param context
 *            current context.
 * @param inStream
 *            the inputStream of the pdf file.
 * @return a bitmap.
 * @see https://github.com/jblough/Android-Pdf-Viewer-Library/
 */
@Nullable
public static Bitmap renderToBitmap(Context context, InputStream inStream) {
    Bitmap bi = null;
    try {
        byte[] decode = IOUtils.toByteArray(inStream);
        ByteBuffer buf = ByteBuffer.wrap(decode);
        PDFPage mPdfPage = new PDFFile(buf).getPage(0);
        float width = mPdfPage.getWidth();
        float height = mPdfPage.getHeight();
        RectF clip = null;
        bi = mPdfPage.getImage((int) (width), (int) (height), clip, true,
                true);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            inStream.close();
        } catch (IOException e) {
            // do nothing because the stream has already been closed
        }
    }
    return bi;
}

另外,我正在使用这个library。而我的pdf文件只包含一页,是一张图片,可能在其他情况下,你必须更新你的代码。

我希望这会对某人有所帮助。

【讨论】:

  • 嗨,有没有这样的库,但用户可以在 PDF 页面之间滚动,而不是单击上一个和下一个按钮?我使用的是同一个库。
  • 对不起,我不知道,我只是需要将 pdf 图像转换为位图。我建议创建一个关于 pdf 分页的新问题......祝你好运。
  • 非常感谢您,该代码适用于 lib github.com/jblough/Android-Pdf-Viewer-Library
  • @ahmed_khan_89 为什么输出位图比 pdf 中的源图像小?
  • 我不知道,我没有遇到这个问题。但如果它可能对您有所帮助,您可以通过在 getImage 方法中传递不同的值来选择输出位图的宽度和高度。
【解决方案4】:

代码如下,希望对你有帮助。我设法将所有页面呈现为 Bitmap.Cheers

 try {
        pdfViewer = (ImageView) findViewById(R.id.pdfViewer);
        int x = pdfViewer.getWidth();
        int y = pdfViewer.getHeight();
        Bitmap bitmap = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_4444);
        String StoragePath= Environment.getExternalStorageDirectory()+ "/sample.pdf";
        File file = new File(StoragePath);
        PdfRenderer renderer = new PdfRenderer(ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
        if (currentPage < 0) {
            currentPage = 0;
        } else if (currentPage > renderer.getPageCount()) {
        }


        Matrix m = pdfViewer.getImageMatrix();
        Rect r = new Rect(0, 0, x, y);
        renderer.openPage(currentPage).render(bitmap, r, m, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
        pdfViewer.setImageMatrix(m);
        pdfViewer.setImageBitmap(bitmap);
        pdfViewer.invalidate();


    } catch (Exception ex) {
        Log.v(TAG, ex.getMessage());
    } finally {

    }

【讨论】:

    【解决方案5】:

    依赖关系

    dependencies {
        implementation 'com.tom_roush:pdfbox-android:1.8.10.1'
    }
    

    代码

        PDDocument pd = PDDocument.load (new File (in));
        PDFRenderer pr = new PDFRenderer (pd);
        Bitmap bitmap = pr.renderImageWithDPI(0, 300);
    

    【讨论】:

      【解决方案6】:

      在浏览并尝试了所有答案后,所有 PDF 文件都不适合我。自定义字体 PDF 文件中存在渲染问题。然后我尝试使用library

      代码如下:

      在您的应用 build.gradle 文件中添加以下依赖项:

      implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'
      

      PDF页面转图片的代码:

            public static List<Bitmap> renderToBitmap(Context context, String filePath) {
                  List<Bitmap> images = new ArrayList<>();
                  PdfiumCore pdfiumCore = new PdfiumCore(context);
                  try {
                      File f = new File(pdfPath);
                      ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
                      PdfDocument pdfDocument = pdfiumCore.newDocument(fd);
                      final int pageCount = pdfiumCore.getPageCount(pdfDocument);
                      for (int i = 0; i < pageCount; i++) {
                          pdfiumCore.openPage(pdfDocument, i);
                          int width = pdfiumCore.getPageWidthPoint(pdfDocument, i);
                          int height = pdfiumCore.getPageHeightPoint(pdfDocument, i);
                          Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                          pdfiumCore.renderPageBitmap(pdfDocument, bmp, i, 0, 0, width, height);
                          images.add(bmp);
                      }
                      pdfiumCore.closeDocument(pdfDocument);
                  } catch(Exception e) {
                      //todo with exception
                  }
           return images;
         }
      

      到目前为止,我尝试过的所有 PDF 文件都适用于我。

      【讨论】:

        【解决方案7】:

        我们可以使用 Qoppa PDF 工具包来做到这一点。

        使用 Qoppa PDF 工具包的步骤。

        http://www.qoppa.com/android/pdfsdk/download下载

        此文件包含四项:

        1. version_history.txt – 此文本文件将随工具包的每个新版本更新。
        2. qoppapdf.jar – 这是工具包的主要 jar 文件。需要将此 jar 文件添加到项目的类路径中。
        3. assets 文件夹 - 此文件夹包含工具包使用的资产,例如字体和图标。从 zip 文件中提取后,您需要将此文件夹中的文件复制到项目中的 assets 文件夹中。
        4. libs 文件夹 - 此文件夹包含原生 Android 库,需要这些库来解码某些 JPEG 图像以及 Android 不支持的 JPEG 2000 图像。需要将 libs 文件夹的内容复制到项目中的 libs 文件夹中。如果您的项目中没有 libs 文件夹,请创建一个并将该文件夹的内容复制到其中。

        代码是:

                //Converting PDF to Bitmap Image...
                StandardFontTF.mAssetMgr = getAssets();
                //Load document to get the first page
                try {
                    PDFDocument pdf = new PDFDocument("/sdcard/PDFFilename.pdf", null);
                    PDFPage page = pdf.getPage(0);
        
                    //creating Bitmap and canvas to draw the page into
                    int width = (int)Math.ceil(page.getDisplayWidth());
                    int height = (int)Math.ceil(page.getDisplayHeight());
        
                    Bitmap bm = Bitmap.createBitmap(width, height, Config.ARGB_8888);
                    Canvas c = new Canvas(bm);
                    page.paintPage(c);
        
                    //Saving the Bitmap
                    OutputStream os = new FileOutputStream("/sdcard/GeneratedImageByQoppa.jpg");
                    bm.compress(CompressFormat.JPEG, 80, os);
                    os.close();
                } catch (PDFException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        

        【讨论】:

        • 这有点用,但不是 100%,它会在页面上添加水印。
        • 不要尝试这个,浪费时间,谁希望他们的用户阅读带有水印的 pdf?
        • 那么请提供无许可证的防止水印的解决方案。
        • 很简单,您要么付费,要么使用其他库。
        • qPDF - 除非您愿意在第一年支付 6000 美元,之后每年支付 3000 美元,否则不要费心获得完整版。
        猜你喜欢
        • 1970-01-01
        • 2012-05-28
        • 1970-01-01
        • 1970-01-01
        • 2012-08-26
        • 2015-09-18
        • 2021-12-12
        • 1970-01-01
        • 2011-01-13
        相关资源
        最近更新 更多