26
votes

All I need to do is take a (locally saved) PDF-document and convert one or all of it's pages to image format like JPG or PNG.

I've tried lot's of PDF Rendering/viewing solutions like APV PDF Viewer, APDFViewer, droidreader, android-pdf, MuPdf and many others but couldn't figure it out so far that how to convert a pdf-page into image?.

EDIT: Also I'd rather have a PDF to image converter than a PDF renderer that I need to edit to convert PDF to image.

9
I'm not an Android dev, but my just-on-the-offchance web search just now reveals that ImageMagick has been ported to this platform. Perhaps worth a go? - halfer
You got those guys that can do it for you, they got they own API, so if you have internet connection it will do, if not...You should hack them, coz they doing a really great job ;) - Ilya Gazman
@AgarwalShankar, not sure if you have tested this code yourself. This is not gonna to work. Why? because the core class PDFImageWriter used in this code has dependency on java.awt.* class, check out the source code yourself. I hope you or people who vote this up can tell me I am wrong, from my basic knowledge: Java awt is not supported by Android. - yorkw
hmmm i didnt tested but if any one confirms then i will delete this answer. - Shankar Agarwal

9 Answers

10
votes

To support API 8 and above, follow:

Using this library: android-pdfview and the following code, you can reliably convert the PDF pages into images (JPG, PNG):

DecodeServiceBase decodeService = new DecodeServiceBase(new PdfContext());
decodeService.setContentResolver(mContext.getContentResolver());

// a bit long running
decodeService.open(Uri.fromFile(pdf));

int pageCount = decodeService.getPageCount();
for (int i = 0; i < pageCount; i++) {
    PdfPage page = decodeService.getPage(i);
    RectF rectF = new RectF(0, 0, 1, 1);

    // do a fit center to 1920x1080
    double scaleBy = Math.min(AndroidUtils.PHOTO_WIDTH_PIXELS / (double) page.getWidth(), //
            AndroidUtils.PHOTO_HEIGHT_PIXELS / (double) page.getHeight());
    int with = (int) (page.getWidth() * scaleBy);
    int height = (int) (page.getHeight() * scaleBy);

    // you can change these values as you to zoom in/out
    // and even distort (scale without maintaining the aspect ratio)
    // the resulting images

    // Long running
    Bitmap bitmap = page.renderBitmap(with, height, rectF);

    try {
        File outputFile = new File(mOutputDir, System.currentTimeMillis() + FileUtils.DOT_JPEG);
        FileOutputStream outputStream = new FileOutputStream(outputFile);

        // a bit long running
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);

        outputStream.close();
    } catch (IOException e) {
        LogWrapper.fatalError(e);
    }
}

You should do this work in the background i.e. by using an AsyncTask or something similar as quite a few methods take computation or IO time (I have marked them in comments).

9
votes

You need to have look at this open-source for project for the same requirement, that can be helpful to you to do many more things also.

Project : PdfRenderer

There is one Java class named PDFPage.java in pdfview package. that class have a method to get Image of the page.

I have also implemented the same thing in my test project and the java code is here for you. I have created one method showPage which accepts the page no and zoom level and return that page as Bitmap.

Hope this can help you. You just need to get that Project or JAR for that, Read the well-documented JAVADOC for the same and then try and implement the same as I did.

Take your time, Happy Coding :)

7
votes

Starting from Android API 21 PdfRenderer is what you are looking for.

5
votes

Use the lib https://github.com/barteksc/PdfiumAndroid

public Bitmap getBitmap(File file){
 int pageNum = 0;
            PdfiumCore pdfiumCore = new PdfiumCore(context);
            try {
                PdfDocument pdfDocument = pdfiumCore.newDocument(openFile(file));
                pdfiumCore.openPage(pdfDocument, pageNum);

                int width = pdfiumCore.getPageWidthPoint(pdfDocument, pageNum);
                int height = pdfiumCore.getPageHeightPoint(pdfDocument, pageNum);


                // ARGB_8888 - best quality, high memory usage, higher possibility of OutOfMemoryError
                // RGB_565 - little worse quality, twice less memory usage
                Bitmap bitmap = Bitmap.createBitmap(width , height ,
                        Bitmap.Config.RGB_565);
                pdfiumCore.renderPageBitmap(pdfDocument, bitmap, pageNum, 0, 0,
                        width, height);
                //if you need to render annotations and form fields, you can use
                //the same method above adding 'true' as last param

                pdfiumCore.closeDocument(pdfDocument); // important!
                return bitmap;
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            return null;
}

 public static ParcelFileDescriptor openFile(File file) {
        ParcelFileDescriptor descriptor;
        try {
            descriptor = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return descriptor;
    }
2
votes

Finally I found very simple solution to this, Download library from here.

Use below code to get images from PDF:

import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.provider.MediaStore;

import org.vudroid.core.DecodeServiceBase;
import org.vudroid.core.codec.CodecPage;
import org.vudroid.pdfdroid.codec.PdfContext;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;

/**
 * Created by deepakd on 06-06-2016.
 */
public class PrintUtils extends AsyncTask<Void, Void, ArrayList<Uri>>
{
    File file;
    Context context;
    ProgressDialog progressDialog;

    public PrintUtils(File file, Context context)
    {

        this.file = file;
        this.context = context;
    }

    @Override
    protected void onPreExecute()
    {
        super.onPreExecute();
        // create and show a progress dialog
        progressDialog = ProgressDialog.show(context, "", "Please wait...");
        progressDialog.show();
    }

    @Override
    protected ArrayList<Uri> doInBackground(Void... params)
    {
        ArrayList<Uri> uris = new ArrayList<>();

        DecodeServiceBase decodeService = new DecodeServiceBase(new PdfContext());
        decodeService.setContentResolver(context.getContentResolver());
        // a bit long running
        decodeService.open(Uri.fromFile(file));
        int pageCount = decodeService.getPageCount();
        for (int i = 0; i < pageCount; i++)
        {
            CodecPage page = decodeService.getPage(i);
            RectF rectF = new RectF(0, 0, 1, 1);
            // do a fit center to A4 Size image 2480x3508
            double scaleBy = Math.min(UIUtils.PHOTO_WIDTH_PIXELS / (double) page.getWidth(), //
                    UIUtils.PHOTO_HEIGHT_PIXELS / (double) page.getHeight());
            int with = (int) (page.getWidth() * scaleBy);
            int height = (int) (page.getHeight() * scaleBy);
            // Long running
            Bitmap bitmap = page.renderBitmap(with, height, rectF);
            try
            {
                OutputStream outputStream = FileUtils.getReportOutputStream(System.currentTimeMillis() + ".JPEG");
                // a bit long running
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
                outputStream.close();
               // uris.add(getImageUri(context, bitmap));
                uris.add(saveImageAndGetURI(bitmap));
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        return uris;
    }

    @Override
    protected void onPostExecute(ArrayList<Uri> uris)
    {
        progressDialog.hide();
        //get all images by uri 
        //ur implementation goes here
    }




    public void shareMultipleFilesToBluetooth(Context context, ArrayList<Uri> uris)
    {
        try
        {
            Intent sharingIntent = new Intent();
            sharingIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
            sharingIntent.setType("image/*");
           // sharingIntent.setPackage("com.android.bluetooth");
            sharingIntent.putExtra(Intent.EXTRA_STREAM, uris);
            context.startActivity(Intent.createChooser(sharingIntent,"Print PDF using..."));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }





    private Uri saveImageAndGetURI(Bitmap finalBitmap) {
        String root = Environment.getExternalStorageDirectory().toString();
        File myDir = new File(root + "/print_images");
        myDir.mkdirs();
        String fname = "Image-"+ MathUtils.getRandomID() +".jpeg";
        File file = new File (myDir, fname);
        if (file.exists ()) file.delete ();
        try {
            FileOutputStream out = new FileOutputStream(file);
            finalBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
            out.close();

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

        return Uri.parse("file://"+file.getPath());
    }

}

FileUtils.java

package com.airdata.util;

import android.net.Uri;
import android.os.Environment;
import android.support.annotation.NonNull;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * Created by DeepakD on 21-06-2016.
 */
public class FileUtils
{

    @NonNull
    public static OutputStream getReportOutputStream(String fileName) throws FileNotFoundException
{
    // create file
    File pdfFolder = getReportFilePath(fileName);
    // create output stream
    return new FileOutputStream(pdfFolder);
}

    public static Uri getReportUri(String fileName)
    {
        File pdfFolder = getReportFilePath(fileName);
        return Uri.fromFile(pdfFolder);
    }
    public static File getReportFilePath(String fileName)
    {
        /*File file = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DOWNLOADS), FileName);*/
        File file = new File(Environment.getExternalStorageDirectory() + "/AirPlanner/Reports");
        //Create report directory if does not exists
        if (!file.exists())
        {
            //noinspection ResultOfMethodCallIgnored
            file.mkdirs();
        }
        file = new File(Environment.getExternalStorageDirectory() + "/AirPlanner/Reports/" + fileName);
        return file;
    }
}

You can view converted images in Gallery or in SD card. Please let me know if you need any help.

1
votes

I will say you a simple trick not a complete solution.Once if you successfully rendered the pdf page you will get its bitmap from screen as follow

View view = MuPDFActivity.this.getWindow().getDecorView();
if (false == view.isDrawingCacheEnabled()) {
    view.setDrawingCacheEnabled(true);
}
Bitmap bitmap = view.getDrawingCache();

Then you can save this bitmap, that is your pdf page as image in locally

try {
    new File(Environment.getExternalStorageDirectory()+"/PDF Reader").mkdirs();
    File outputFile = new File(Environment.getExternalStorageDirectory()+"/PDF Reader", System.currentTimeMillis()+"_pdf.jpg");
    FileOutputStream outputStream = new FileOutputStream(outputFile);

    // a bit long running
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.close();
} catch (IOException e) {
    Log.e("During IMAGE formation", e.toString());
}

that's all, hope you help this.

1
votes

Using Android default libraries like AppCompat, you can convert all the PDF pages into images. This way is very fast and optimized. The below code is for getting separate images of a PDF page. It is very fast and quick.

I have implemented like below:

ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(new File("pdfFilePath.pdf"), MODE_READ_ONLY);
    PdfRenderer renderer = new PdfRenderer(fileDescriptor);
    final int pageCount = renderer.getPageCount();
    for (int i = 0; i < pageCount; i++) {
        PdfRenderer.Page page = renderer.openPage(i);
        Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(),Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bitmap, 0, 0, null);
        page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
        page.close();

        if (bitmap == null)
            return null;

        if (bitmapIsBlankOrWhite(bitmap))
            return null;

        String root = Environment.getExternalStorageDirectory().toString();
        File file = new File(root + filename + ".png");

        if (file.exists()) file.delete();
        try {
            FileOutputStream out = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            Log.v("Saved Image - ", file.getAbsolutePath());
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

=======================================================

private static boolean bitmapIsBlankOrWhite(Bitmap bitmap) {
    if (bitmap == null)
        return true;

    int w = bitmap.getWidth();
    int h = bitmap.getHeight();
    for (int i =  0; i < w; i++) {
        for (int j = 0; j < h; j++) {
            int pixel =  bitmap.getPixel(i, j);
            if (pixel != Color.WHITE) {
                return false;
            }
        }
    }
    return true;
}

I have already posted it in another question :P

Link is - https://stackoverflow.com/a/58420401/12228284

1
votes

from below code, you can extract all pages as image (PNG) format from PDF using PDFRender:

// This method is used to extract all pages in image (PNG) format.
    private void getImagesFromPDF(File pdfFilePath, File DestinationFolder) throws IOException {

        // Check if destination already exists then delete destination folder.
        if(DestinationFolder.exists()){
            DestinationFolder.delete();
        }

        // Create empty directory where images will be saved.
        DestinationFolder.mkdirs();

        // Reading pdf in READ Only mode.
        ParcelFileDescriptor fileDescriptor = ParcelFileDescriptor.open(pdfFilePath, ParcelFileDescriptor.MODE_READ_ONLY);

        // Initializing PDFRenderer object.
        PdfRenderer renderer = new PdfRenderer(fileDescriptor);

        // Getting total pages count.
        final int pageCount = renderer.getPageCount();

        // Iterating pages
        for (int i = 0; i < pageCount; i++) {

            // Getting Page object by opening page.
            PdfRenderer.Page page = renderer.openPage(i);

            // Creating empty bitmap. Bitmap.Config can be changed.
            Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(),Bitmap.Config.ARGB_8888);

            // Creating Canvas from bitmap.
            Canvas canvas = new Canvas(bitmap);

            // Set White background color.
            canvas.drawColor(Color.WHITE);

            // Draw bitmap.
            canvas.drawBitmap(bitmap, 0, 0, null);

            // Rednder bitmap and can change mode too.
            page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

            // closing page
            page.close();

            // saving image into sdcard.
            File file = new File(DestinationFolder.getAbsolutePath(), "image"+i + ".png");

            // check if file already exists, then delete it.
            if (file.exists()) file.delete();

            // Saving image in PNG format with 100% quality.
            try {
                FileOutputStream out = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                Log.v("Saved Image - ", file.getAbsolutePath());
                out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

You can call this method in below way:

// Getting images from Test.pdf file.
        File source = new File(Environment.getExternalStorageDirectory() + "/" + "Test" + ".pdf");

        // Images will be saved in Test folder.
        File destination = new File(Environment.getExternalStorageDirectory() + "/Test");

        // Getting images from pdf in png format.
        try {
            getImagesFromPDF(source, destination);
        } catch (IOException e) {
            e.printStackTrace();
        }

Cheers!

0
votes

After going through and trying all the answers, none worked for me for all the PDF files. Rendering issues were there in custom font PDF files. Then I tried using library. I took inspiration from NickUncheck's answer for getting Images from all PDF pages.

The code is as follows:

In your app build.gradle file add the following dependency:

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

The code for converting PDF pages to images:

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

So far it is working for me all the PDF files that I tried.