Android 的 PdfRenderer class 生成低质量图像

Android's PdfRenderer class produces low quality images

我正在使用 PdfRendererabove api 21 在我的应用程序中显示 pdf,我发现页面质量很差。 我还按照 google 示例使用 PdfRenderer,这就是我为页面创建 Bitmap 的方式:

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

我使用 ARGB_8888 因为据我所知,它是显示位图的最佳质量。 我做错了什么吗?

编辑

这就是 PdfRenderer class 和 classic Pdf 的巨大区别 reader:

ARGB_8888` 仅针对颜色质量,但 printing/displaying 质量与分辨率有关(在屏幕上显示时每英寸有多少点)。

例如,如果您有 400 DPI 屏幕(每英寸 400 点)并希望以这种质量显示 PDF,那么您应该通过 Bitmap.createBitmap() 渲染位图,将像素作为其大小:

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

其中:

  1. getResources().getDisplayMetrics().densityDpi是目标DPI分辨率
  2. mCurrentPage.getWidth() returns 以 Postscript 点为单位的宽度,其中每个 pt 为 1/72 英寸。
  3. 72 (DPI) 是默认的 PDF 分辨率。

因此,将 #2 乘以 72 得到英寸,乘以 DPI 得到像素。换句话说,为了匹配显示器打印设备的质量,您应该增加渲染图像的大小,因为默认 PDF 分辨率为 72 DPI。请同时检查 this post

我来晚了。标记的答案对我没有帮助,因为位图变大了,因此无法渲染。我找到了原来的 post,因为我遇到了完全相同的问题,也许这个答案会对遇到我情况的其他人有所帮助。

我四处搜索,看看是否有人有一个巧妙的解决方案来缩放位图,同时保持比例。我发现了这个网站:

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

真的,这并不复杂。我只需要另外两行代码:

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

我按照网站的建议添加了类似的 helper/util 类(所以在实践中,它不止两行 ;))。身高来自

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

缩放只是简单地将设备高度除以原始位图高度得到一个因子,再乘以原始位图宽度得到缩放后的宽度。

这在我的 Nexus 5 上完美运行。我无法在多个设备上测试它,但它似乎是一个可靠的解决方案。

PdfRenderer 一样,您将在 ImageView 中显示 PDF 页面,最简单的方法是简单地创建 ImageView 最大尺寸的位图,并添加一些数学运算以保持 PDF 的比例。由于 PDF 通常用于打印,因此它们的分辨率始终高于您的屏幕,因此您不会冒像素化图像的风险。为确保 ImageView 已分配 measuredWidthmeasuredHeight,请在您的代码中使用 ImageView::post()(请原谅我的 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)
    }