Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android's PdfRenderer class produces low quality images

I'm using PdfRendererabove api 21 to display pdf in my app and I noticed that the quality of pages is very poor. I followed also google sample to use PdfRenderer and this is how I create Bitmap for page:

//mCurrentPage is a PdfRenderer.Page and mImageView is an ImageView
Bitmap bitmap = Bitmap.createBitmap(mCurrentPage.getWidth(), 
                    mCurrentPage.getHeight(),
                    Bitmap.Config.ARGB_8888);
mCurrentPage.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
mImageView.setImageBitmap(bitmap);

I used ARGB_8888 because as far as I know, it's the best quality to display bitmaps. Am i doing something wrong?

EDIT

This is the huge difference between PdfRenderer class and a classic Pdf reader:

enter image description here enter image description here

like image 262
Giorgio Antonioli Avatar asked Aug 28 '15 14:08

Giorgio Antonioli


3 Answers

ARGB_8888` is for color quality only but the printing/displaying quality is related to the resolution (how much dots per inch you have when displaying on screen).

For example, if you have 400 DPI screen (400 Dots Per Inch) and want to display PDF with this quality then you should render the bitmap via Bitmap.createBitmap() that takes pixels as its sizes:

Bitmap bitmap = Bitmap.createBitmap(
    getResources().getDisplayMetrics().densityDpi * mCurrentPage.getWidth() / 72,                        
    getResources().getDisplayMetrics().densityDpi * mCurrentPage.getHeight() / 72,
    Bitmap.Config.ARGB_8888
);

where:

  1. getResources().getDisplayMetrics().densityDpi is the target DPI resolution
  2. mCurrentPage.getWidth() returns width in Postscript points, where each pt is 1/72 inch.
  3. 72 (DPI) is the default PDF resolution.

Hence, diving #2 by 72 we get inches and multiplying by DPI we get pixels. In other words to match the quality of the printing device of the display you should increase the size of the image rendered as default PDF resolution is 72 DPI. Please also check this post?

like image 67
Eugene Avatar answered Nov 17 '22 14:11

Eugene


I am a bit late. The answer marked did not help me, because the bitmap got to big, and thus could not be rendered. I found the original post because I had the exact same problem, maybe this answer will help others in my situation.

I searched around to see if anyone had a neat solution to scaling the bitmap, while keeping the ratio. I came across this site:

https://guides.codepath.com/android/Working-with-the-ImageView#scaling-a-bitmap

It is not complicated stuff, really. I only needed two additional lines of code:

int height = DeviceDimensionsHelper.getDisplayHeight(this);
Bitmap scaledBitmap = BitmapUtil.scaleToFitHeight(bitmap, height);

I added similar helper/util classes as the site suggests(so in practice, it is more than two lines ;) ). The height comes from

context.getResources().getDisplayMetrics().widthPixels;

The scaling simply divides the device height with the original bitmap height to get a factor, which is in turn multiplied with the original bitmap width to find the scaled width.

This works perfectly on my Nexus 5. I have not been able to test this on multiple devices, but it seems like a solid solution.

like image 7
stianak Avatar answered Nov 17 '22 14:11

stianak


As with the PdfRenderer you'll be displaying PDF pages in an ImageView, it's easiest to simply create a bitmap of a max size of your ImageView, with some maths added to preserve the PDF's proportions. Since PDF's are generally made for print, they'll always be of higher resolution than your screen, so you're not risking getting a pixelated image. To be sure the ImageView has it's measuredWidth and measuredHeight assigned, use ImageView::post() in your code (excuse my Kotlin):

    pdfPageImageView.post {
        val viewWidth = pdfPageImageView.measuredWidth
        val viewHeight = pdfPageImageView.measuredHeight
        val pageWidth = page.width
        val pageHeight = page.height
        val pageRatio = 1.0 * pageWidth / pageHeight
        val viewRatio = 1.0 * viewWidth / viewHeight
        val bitmapWidth: Int
        val bitmapHeight: Int
        if (pageRatio > viewRatio) {
            bitmapWidth = viewWidth
            bitmapHeight = (viewWidth / pageRatio).toInt()
        } else {
            bitmapHeight = viewHeight
            bitmapWidth = (viewHeight * pageRatio).toInt()
        }
        val bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888)
        page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
        pdfPageImageView.setImageBitmap(bitmap)
    }
like image 1
javaxian Avatar answered Nov 17 '22 14:11

javaxian