You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何保持PDF原尺寸渲染高质量Bitmap,避免文件过大?

解决方案

问题根源

  1. 你使用的Bitmap.Config.ARGB_4444是已废弃的低质量配置,色彩深度不足直接导致画质模糊。
  2. 直接用PDF的原始尺寸(841×595,这是PDF的点数单位而非像素)渲染位图,会生成过小的像素文件,在高DPI屏幕上放大显示时必然出现锯齿。
  3. 强制渲染到1920×1080会生成远超显示需求的位图,徒增内存占用和文件体积。

优化方案

要在保持原始比例的同时渲染高质量位图,核心是根据显示需求计算合适的像素尺寸,避免不必要的放大或缩小,同时使用高质量的位图配置。

关键调整步骤

  1. 使用高质量位图配置:替换ARGB_4444ARGB_8888,这是当前安卓系统推荐的全色彩深度配置,能保证画质。
  2. 按显示需求计算位图尺寸:根据RecyclerView的显示宽度(通常是屏幕宽度)和PDF页面的原始比例,计算刚好适配显示的位图尺寸,既避免缩放失真,又控制体积。
  3. 精准渲染PDF页面:使用计算后的尺寸创建位图,让PDF页面刚好填满位图,无需额外缩放。

修改后的代码

private void pdfToBitmaps(Uri pdfUri) {
    // 获取屏幕显示参数,用于计算合适的位图尺寸
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    // 假设RecyclerView项占满屏幕宽度,可根据实际布局调整此值
    int targetWidth = metrics.widthPixels;

    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.execute(() -> {
        ParcelFileDescriptor parcelFileDescriptor = null;
        PdfRenderer renderer = null;
        try {
            parcelFileDescriptor = getContentResolver().openFileDescriptor(pdfUri, "r");
            if (parcelFileDescriptor == null) {
                Log.e("PdfToBitmaps", "Failed to open PDF file");
                return;
            }
            renderer = new PdfRenderer(parcelFileDescriptor);
            int pageCount = renderer.getPageCount();

            if (pageCount >= 600) {
                Log.e("PdfToBitmaps", "Too many pages to process");
                return;
            }

            Log.d("PdfToBitmaps", "Total pages: " + pageCount);

            for (int i = 0; i < pageCount; i++) {
                PdfRenderer.Page page = renderer.openPage(i);
                Log.d("PdfToBitmaps", "Rendering page: " + i);

                // 获取PDF页面的原始比例(点数单位)
                float pageAspectRatio = (float) page.getHeight() / page.getWidth();
                // 根据目标宽度计算对应高度,保持原始比例
                int targetHeight = (int) (targetWidth * pageAspectRatio);

                // 创建高质量位图
                Bitmap bitmap = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                canvas.drawColor(Color.WHITE);

                // 渲染PDF页面到位图,确保适配尺寸
                page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);

                mlkitforembededtext(bitmap, i);

                // 更新UI线程的位图列表
                runOnUiThread(() -> {
                    pdfBitmaps.add(bitmap);
                    pdfAdapter.notifyItemInserted(pdfBitmaps.size() - 1);
                });

                page.close();
            }
        } catch (Exception e) {
            Log.e("PdfToBitmaps", "Error processing PDF", e);
        } finally {
            // 确保资源正确关闭
            try {
                if (renderer != null) renderer.close();
                if (parcelFileDescriptor != null) parcelFileDescriptor.close();
            } catch (IOException e) {
                Log.e("PdfToBitmaps", "Error closing resources", e);
            }
            executor.shutdown();
        }
    });
}

额外优化建议

  • 位图回收:当RecyclerView的项被销毁时,调用bitmap.recycle()释放内存,避免内存泄漏。
  • 内存复用:使用BitmapFactory.Options.inBitmap复用旧位图的内存空间,减少内存波动。
  • 分页加载:如果PDF页数较多,不要一次性加载所有位图,实现分页懒加载,进一步降低内存占用。

内容的提问来源于stack exchange,提问作者Tndstn

火山引擎 最新活动