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

Android Studio中如何减小生成的PDF文件大小

问题原因

你当前代码生成PDF体积过大的核心原因是直接将全分辨率原始Bitmap绘制到PDF画布:Android原生PdfDocument默认会将传入的Bitmap以原始像素格式嵌入PDF文档,不会自动做分辨率适配、编码压缩;你设置的inScaled = false更是强制加载原图全尺寸数据,哪怕图片在PDF里只占几百pt的显示区域,实际嵌入的是原图几千像素的完整数据,再加上默认用ARGB_8888格式存储像素(每像素占4字节),体积自然居高不下。你之前用ColorMatrix转灰度只是修改了绘制颜色,并没有减少Bitmap本身的像素数据量,所以压缩效果有限。

可落地的优化方案

按优先级做以下修改,最终单页PDF体积可以控制在1~2MB以内,清晰度完全满足屏幕查看和普通打印需求:

  • 第一步:按PDF实际显示尺寸下采样解码Bitmap,砍掉冗余像素
    PDF默认采用72DPI的坐标体系,你的图片在A4页面(595842pt)里的最大显示尺寸只有436270pt,哪怕按150DPI的打印清晰度要求,需要的实际像素尺寸也仅为908*563px,完全不需要加载原图动辄几千像素的全尺寸数据。
    解码图片时不要设置inScaled = false,先通过inJustDecodeBounds获取原图尺寸,计算合适的inSampleSize做下采样,只加载需要尺寸的Bitmap,这一步可以减少70%~90%的像素数据量。
    参考代码:
    BitmapFactory.Options opt = new BitmapFactory.Options();
    opt.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(img_Uri.getPath(), opt);
    // 按150DPI计算图片实际需要的像素尺寸,仅屏幕查看可把150f改成72f,体积更小
    int targetWidth = (int) (436 * 150f / 72f);
    int targetHeight = (int) (270 * 150f / 72f);
    // 计算采样率
    int sampleSize = 1;
    if (opt.outHeight > targetHeight || opt.outWidth > targetWidth) {
        int halfHeight = opt.outHeight / 2;
        int halfWidth = opt.outWidth / 2;
        while ((halfHeight / sampleSize) >= targetHeight && (halfWidth / sampleSize) >= targetWidth) {
            sampleSize *= 2;
        }
    }
    opt.inSampleSize = sampleSize;
    opt.inJustDecodeBounds = false;
    // 图片无透明通道,用RGB_565格式代替默认ARGB_8888,像素数据量直接减半
    opt.inPreferredConfig = Bitmap.Config.RGB_565;
    Bitmap bmp = BitmapFactory.decodeFile(img_Uri.getPath(), opt);
    
  • 第二步:提前把Bitmap缩放到绘制尺寸,不要靠Canvas做缩放
    你当前代码通过myCanvas.scale()做缩放,PDF里实际嵌入的还是全尺寸的Bitmap数据,只是显示的时候缩放。应该在绘制前先把Bitmap缩放到和目标显示尺寸完全匹配的大小,再调用drawBitmap,保证PDF里嵌入的位图没有多余像素。
    参考代码:
    // 先通过你原来的xy方法计算图片在PDF里的实际显示宽高和坐标
    int[] xyImg = xy(bmp.getWidth(), bmp.getHeight(), 298, 175);
    // 直接把Bitmap缩放到最终显示的尺寸
    Bitmap scaledBmp = Bitmap.createScaledBitmap(bmp, xyImg[0], xyImg[1], true);
    bmp.recycle();
    
  • 第三步:灰度转换直接作用于缩放后的小尺寸Bitmap,减少运算量同时不额外占空间
    你原来的ColorMatrix灰度逻辑可以保留,但要作用在缩放后的小尺寸Bitmap上,不要对全尺寸原图做处理。处理完直接用这个缩放后的灰度Bitmap绘制,不需要再给Canvas加缩放参数,直接按坐标绘制即可:
    PdfDocument.PageInfo myPageInfo = new PdfDocument.PageInfo.Builder(595, 842, 1).create();
    PdfDocument.Page myPage = myPDFDoc.startPage(myPageInfo);
    Canvas myCanvas = myPage.getCanvas();
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    // 直接给画笔加灰度滤镜
    ColorMatrix cm = new ColorMatrix();
    cm.setSaturation(0);
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    // 直接按计算好的坐标绘制缩放后的位图,不需要Canvas做缩放
    myCanvas.drawBitmap(scaledBmp, xyImg[2], xyImg[3], paint);
    myPDFDoc.finishPage(myPage);
    scaledBmp.recycle();
    
  • 可选优化:进一步压缩位图质量
    如果对清晰度要求不高,可以在绘制前把缩放后的Bitmap压缩成质量为60~80的JPEG字节流,再重新解码成Bitmap绘制,利用JPEG的有损压缩进一步减少像素数据的体积,肉眼基本看不出差异。
    参考代码:
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    scaledBmp.compress(Bitmap.CompressFormat.JPEG, 70, baos);
    Bitmap compressedBmp = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.size());
    scaledBmp.recycle();
    // 后续用compressedBmp绘制即可
    
优化效果

以上步骤全部做完后,单页带图PDF的体积基本可以稳定在1MB上下,如果用72DPI的屏幕适配标准,体积可以压到500KB以内,完全满足常规使用需求,不会出现之前十几二十MB的情况。

内容的提问来源于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 09:36:24