Convert a Pdf page into Bitmap in Android Java
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:@Overrideprotected 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()); }}
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.
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. */@Nullablepublic 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/ */@Nullablepublic 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.