Android's PdfRenderer class produces low quality images

爱⌒轻易说出口 提交于 2019-11-28 07:36:30
Eugene

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?

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.

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)
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!