如何保持PDF原尺寸渲染高质量Bitmap,避免文件过大?
解决方案
问题根源
- 你使用的
Bitmap.Config.ARGB_4444是已废弃的低质量配置,色彩深度不足直接导致画质模糊。 - 直接用PDF的原始尺寸(841×595,这是PDF的点数单位而非像素)渲染位图,会生成过小的像素文件,在高DPI屏幕上放大显示时必然出现锯齿。
- 强制渲染到1920×1080会生成远超显示需求的位图,徒增内存占用和文件体积。
优化方案
要在保持原始比例的同时渲染高质量位图,核心是根据显示需求计算合适的像素尺寸,避免不必要的放大或缩小,同时使用高质量的位图配置。
关键调整步骤
- 使用高质量位图配置:替换
ARGB_4444为ARGB_8888,这是当前安卓系统推荐的全色彩深度配置,能保证画质。 - 按显示需求计算位图尺寸:根据RecyclerView的显示宽度(通常是屏幕宽度)和PDF页面的原始比例,计算刚好适配显示的位图尺寸,既避免缩放失真,又控制体积。
- 精准渲染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




