Android Studio中缩放Bitmap打印到PDF时避免图像质量损失
问题根因
图像模糊是两个核心逻辑错误导致的:
- 默认创建的PDF页面为72DPI分辨率,对应A4尺寸仅为595×842像素,仅适合屏幕预览,远达不到打印、高清查看要求的300DPI标准,画布本身分辨率不足是模糊的核心原因。
- 缩放逻辑存在缺陷:提前将高分辨率原图强制缩放到72DPI下的小尺寸,丢失了所有原图细节;同时
Bitmap.createScaledBitmap最后一个参数传false关闭了缩放滤波,绘制时也没有开启抗抖动、双线性插值,进一步放大了锯齿和模糊问题。
修复方案
1. 提升PDF页面基础分辨率
通用打印/高清查看标准为300DPI,按这个分辨率计算A4页面像素尺寸:
72DPI下1pt对应1像素,300DPI下缩放系数为300/72 ≈ 4.17,对应A4页面像素尺寸为2480×3508,直接用这个尺寸创建PageInfo即可。
2. 优化Bitmap加载与绘制逻辑
- 不要提前生成缩放后的Bitmap副本,通过Canvas的Matrix变换直接绘制原图,保留尽可能多的图像细节
- 解码Bitmap时先计算采样率,按目标绘制区域尺寸按需解码,既避免OOM,也不会加载无意义的超大分辨率图像
- 绘制用的Paint开启抗锯齿、双线性滤波、抖动效果,优化缩放后的显示质感
修复后核心实现代码
if (img1_SetImage) { // 按300DPI打印标准初始化A4页面参数 final int PDF_DPI = 300; final float DPI_SCALE = PDF_DPI / 72f; int pageWidth = (int) (595 * DPI_SCALE); int pageHeight = (int) (842 * DPI_SCALE); PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(pageWidth, pageHeight, 1).create(); PdfDocument.Page page = myPDFDoc.startPage(pageInfo); Canvas canvas = page.getCanvas(); // 换算300DPI下的目标绘制区域参数 int targetAreaW = (int) (436 * DPI_SCALE); int targetAreaH = (int) (270 * DPI_SCALE); int areaCenterX = (int) (298 * DPI_SCALE); int areaCenterY = (int) (175 * DPI_SCALE); // 先获取原图尺寸,不加载到内存 BitmapFactory.Options decodeOpt = new BitmapFactory.Options(); decodeOpt.inJustDecodeBounds = true; BitmapFactory.decodeFile(img1_Uri.getPath(), decodeOpt); int originW = decodeOpt.outWidth; int originH = decodeOpt.outHeight; // 计算合适的采样率,按需解码避免OOM int inSampleSize = 1; if (originH > targetAreaH || originW > targetAreaW) { int halfH = originH / 2; int halfW = originW / 2; while ((halfH / inSampleSize) >= targetAreaH && (halfW / inSampleSize) >= targetAreaW) { inSampleSize *= 2; } } decodeOpt.inSampleSize = inSampleSize; decodeOpt.inScaled = false; decodeOpt.inJustDecodeBounds = false; Bitmap originBmp = BitmapFactory.decodeFile(img1_Uri.getPath(), decodeOpt); // 计算等比缩放参数和绘制坐标 float wScale = (float) targetAreaW / originBmp.getWidth(); float hScale = (float) targetAreaH / originBmp.getHeight(); float drawScale = Math.min(wScale, hScale); float drawW = originBmp.getWidth() * drawScale; float drawH = originBmp.getHeight() * drawScale; float drawX = areaCenterX - drawW / 2; float drawY = areaCenterY - drawH / 2; // 配置高质量绘制画笔 Paint drawPaint = new Paint(); drawPaint.setAntiAlias(true); drawPaint.setFilterBitmap(true); drawPaint.setDither(true); // 通过矩阵直接绘制原图,不需要提前生成缩放Bitmap Matrix drawMatrix = new Matrix(); drawMatrix.postScale(drawScale, drawScale); drawMatrix.postTranslate(drawX, drawY); canvas.drawBitmap(originBmp, drawMatrix, drawPaint); originBmp.recycle(); myPDFDoc.finishPage(page); }
可选优化项
- 如果对PDF文件体积敏感,可以将Bitmap解码格式设置为
RGB_565,相比默认的ARGB_8888可以减少一半内存占用,照片类图像几乎看不出显示差异。 - 不要使用
Bitmap.createScaledBitmap手动生成缩放副本,会额外增加一次内存拷贝和精度损失,通过Matrix直接在Canvas绘制的效果更好、性能更高。 - 如果仅需要屏幕预览不需要打印,可以将DPI设置为150,平衡清晰度和文件体积。
内容的提问来源于stack exchange,提问作者Dina
相关产品推荐
相关产品推荐

