Android PdfDocument 文件大小

Posted

技术标签:

【中文标题】Android PdfDocument 文件大小【英文标题】:Android PdfDocument file size 【发布时间】:2014-05-13 09:33:30 【问题描述】:

我想使用 KitKat 中引入的PdfDocument android 类从视图生成 PDF 文件。我设法做到了,到目前为止,文件生成正常,最终得到了正确的 PDF。唯一的问题是文件很大,只有一页12Mb。有没有办法减小文件大小?

我用来生成 PDF 的代码是:

public static File generateDocument(Activity activity, String fileName, ViewGroup container) throws IOException
    File f = new File(activity.getExternalFilesDir(null), fileName);
    PdfDocument document = new PdfDocument();
    try
        for(int i=0;i<container.getChildCount();i++)
            View v = container.getChildAt(i);
            PdfDocument.PageInfo.Builder pageBuilder = new PdfDocument.PageInfo.Builder(v.getWidth(), v.getHeight(), i);
            Page page = document.startPage(pageBuilder.create());
            v.draw(page.getCanvas());
            document.finishPage(page);
        

        document.writeTo(new FileOutputStream(f));
     finally
        if(document!=null)
            document.close();
        
    
    return f;

【问题讨论】:

你有没有找到任何使用原生android API的解决方案 请阅读我在已接受答案中的评论。在生成 PDF 之前,已解决在 ImageViews 中调整位图大小的问题。 【参考方案1】:

有几个主要因素会增加 PDF 文件的大小:

hi-resolution pictures (where lo-res would suffice)
embedded fonts (where content would still be readable "good enough" without them)
PDF content not required any more for the current version/view (older version of certain objects)
embedded ICC profiles
embedded third-party files (using the PDF as a container)
embedded job tickets (for printing)
embedded javascript
and a few more

尝试使用 iText。以下链接给出了 android 中 iText 的基本概念。

http://technotransit.wordpress.com/2011/06/17/using-itext-in-android/

http://www.mysamplecode.com/2013/05/android-itext-pdf-bluetooth-printer.html

https://***.com/a/21025162/3110609

【讨论】:

谢谢你的建议,但我还是想用系统的那个。我将尝试简化 PDF,但它只是一些文本视图和图像。没有特殊字体或任何其他嵌入对象... 原来问题出在图片上。即使持有它的 ImageView 非常小,位图也很大,并且占用了大部分大小。修复了在将其设置为 ImageView 之前仅缩放位图的问题。谢谢。【参考方案2】:

这似乎只是 PdfDocument 中的一个错误。我用 PdfDocument 创建的 PDF 文件是 5.6 兆字节。通过 ios 等效生成的相同文档为 500K。如果我把Android PDF通过Adobe Acrobat的pdf优化运行,不压缩任何图像,5.6MB文件变成350K。它们看起来一样,我在 Adob​​e Acrobat 中没有应用压缩。

在实际的PDF代码中,Android图像对象字典是这样的

<</Type /XObject
/Subtype /Image
/Width 1224
/Height 1584
/ColorSpace /DeviceRGB
/BitsPerComponent 8
/Length 5816448
>>

iOS 的 PDF 有这个字典

<< /Length 8 0 R
/Type /XObject
/Subtype /Image
/Width 1224
/Height 1584
/ColorSpace /DeviceRGB
/SMask 9 0 R
/BitsPerComponent 8
/Filter /FlateDecode >>

我认为问题在于 Android 版本中缺少 FlateDecode 过滤器。当我通过 Adob​​e Acrobat PDF 优化器运行它时,它会得到 FlateDecode 过滤器。

【讨论】:

【参考方案3】:

如果有人仍在寻找解决方案...我正在开展一个从图像生成 PDF 的项目,但对 Android 的 PdfDocument 和第 3 方 生成的文件大小不满意>AndroidPdfWriter APW.

经过一些试验后,我最终使用了 Apache 的 PdfBox,它为我提供了大约 80K 的 PDF 文件(A4 大小,单个 1960x1080 图像),而 PdfDocument 或通常为 2~3M AndroidPdfWriter

PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);

// Define a content stream for adding to the PDF
contentStream = new PDPageContentStream(document, page);

Bitmap bimap = _get_your_bitmap_();
// Here you have great control of the compression rate and DPI on your image.
// Update 2017/11/22: The DPI param actually is useless as of current version v1.8.9.1 if you take a look into the source code. Compression rate is enough to achieve a much smaller file size.
PDImageXObject ximage = JPEGFactory.createFromImage(document, bitmap, 0.75, 72);
// You may want to call PDPage.getCropBox() in order to place your image
// somewhere inside this page rect with (x, y) and (width, height).
contentStream.drawImage(ximage, 0, 0);

// Make sure that the content stream is closed:
contentStream.close();

document.save(_your_file_path_);
document.close();

=====

顺便说一句。我猜他们生成巨大文件的原因是因为他们在写入 PDF 文件时不压缩图像数据。如果您查看 AndroidPdfWriter 的 XObjectImage.deflateImageData() 方法,您会看到它使用java.util.zip.Deflater.NO_COMPRESSION 选项来写入图像数据,如果您的图片大小为 1960x1080,这有点可怕。如果您将选项更改为例如Deflater.BEST_COMPRESSION 你会得到更小的文件大小,但我处理一个页面需要 3-4 秒,这是不可接受的。

【讨论】:

另外 PdfBox 需要很长时间来渲染,我测试了一个 90 页的文件,6 分钟后放弃了,我开始调试并在第 31 页看到它 如何让图片在页面居中? 嗨@AkashChaudhary,请参考示例答案中的 cmets,您可能需要调用 PDPage.getCropBox() 以获取页面 rect 以使图像居中(前提是您已经知道图像 rect) . 但是使用 A4 尺寸的图像会使图像超出页面,因此部分可见。你能告诉我如何使它适合 A4 页面而不缩小它。 嗨@AkashChaudhary,简而言之,您可能希望在绘制之前缩放图像以适合您的文档页面。例如,如果您从PDPage.getCropBox() 检索到的 RECT 大小为 600x800,那么您将需要缩放图像(通常保持比例),使其宽度 Bitmap.createScaledBitmap() 参考@JM Lord 的回答。【参考方案4】:

使用 PDFDocument, 确保在将图像绘制到画布之前缩小图像。

绘制到屏幕时,这足以缩放位图:

canvas.drawBitmap(bmp, src, dst, paint);

但是,当使用来自PdfDocument.Page.getCanvas 的画布时,此画布不会缩小位图,它只会将其压缩到更小的区域。相反,您应该这样做:

// Scale bitmap : filter = false since we are always downSampling
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bmp, dstWidth, dstHeight,
    false); // filter=false if downscaling, true if upscaling

canvas.drawBitmap(scaledBitmap, null, dst, paint);

scaledBitmap.recycle();

这是嵌入在 Android 中的,因此比使用第三方库要容易得多。 (以上是在 Marshmallow 平台上测试的)

【讨论】:

以上是关于Android PdfDocument 文件大小的主要内容,如果未能解决你的问题,请参考以下文章

错误:PDFDocument:流必须有数据

在C#中使用PDFDocument发送没有文件名的邮件

将 PDFPage 添加到 PDFDocument 时 PDFView 不更新

使用 AWS KMS 返回的数字签名签署 PdfDocument

如何将 List<PdfDocument> 合并为单个 PdfDocument

PDFKit 和 PDFDocument 注释在 Adob​​e Acrobat 中不可见