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。它们看起来一样,我在 Adobe 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 过滤器。当我通过 Adobe 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 文件大小的主要内容,如果未能解决你的问题,请参考以下文章
将 PDFPage 添加到 PDFDocument 时 PDFView 不更新
使用 AWS KMS 返回的数字签名签署 PdfDocument