Convert a Pdf page into Bitmap in Android Java

I need to convert PDFfile(PDF page) into a Bitmap(or Image file) in Android.

1.Used Pdfbox jar from Apache. But it uses some java classes that is not supported in android. 2. Tried Itext jar which converts image to pdf(I need its reverse operation) Like that I have tried many jars. But no positive result.

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);

I am getting the Image File, enter image description here

Instead of, enter image description here

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();
        }
    }
}

Else, any other way to display pdf file in android using function inbuilt within application?


Solution 1:

I solved this issue. it's as simple as letting the device have time to render each page.

To fix this all you have to do is change

PDFPage page = pdf_file.getPage(2);

to

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

Firstly to view a PDF in Android you have to convert the PDF into images then display them to the user. (I am going to use a webview)

So to do this we need this library. It is my edited version of this git.

After you have imported the library into your project you need to create your activity.

The 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>

The 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());
    }
}

Solution 2:

I know this question is old but I ran into this problem last week, and none of the answers really worked for me.

Here's how I solve this issue without using third-party libraries.

Based on the code from android developers site using android's PDFRenderer class (API 21+), I wrote the following method:

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;

}

the method returns an array of bitmaps, one bitmap for every page in the pdf file.

The height and width are calculated based on this answer to create better-quality images.

Solution 3:

This question is a bit old, but I had to do the same today, so this is my solution:

/**
 * 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;
}

Also, I am using this library. And my pdf file contains only one page and is an image, may be in other cases, you have to update your code.

I hope this will help someone.