You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 05:01:04