I want to generate a PDF File from a View using the PdfDocument
android class introduced in KitKat. I managed to do it, and the file is so far generated ok, ending up having a correct PDF. The only problem is the file is huge, 12Mb for just one page. Is there a way to reduce the File size?
The code I am using to generate the PDF is:
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;
}
In case anyone is still looking for a solution... I was working on a project to generate PDF from images and not satisfied with the file size generated by both Android's PdfDocument and 3rd party AndroidPdfWriter APW.
After some trials I ended up using Apache's PdfBox, which gave me a PDF file (A4 size with a single 1960x1080 image) for around 80K, while it's usually 2~3M with PdfDocument or AndroidPdfWriter.
=====
btw. I guess the reason why they generate a huge file size is because they don't compress the image data while writing to PDF file. If you take a look into AndroidPdfWriter's XObjectImage.deflateImageData() method you will see it's using
java.util.zip.Deflater.NO_COMPRESSION
option to write the image data which is kind of horrible if you've got a picture with size 1960x1080. If you change the options to e.g.Deflater.BEST_COMPRESSION
you get much smaller file size however it takes up to 3-4 seconds for me to handle one single page which is not acceptable.Using PDFDocument, be sure to downscale your images prior to drawing them in the canvas.
When drawing to the screen, this is enough to scale the bitmap :
However, when using the canvas from
PdfDocument.Page.getCanvas
, this canvas will not downscale the bitmap, it will just squeeze it into a smaller zone. Instead you should do something like this:This is embedded in Android so it is much easier than using a third-party library. (The above was tested on a Marshmallow platform)
There are a few main things that increases the size of a PDF file:
Try using iText. Following links give a basice idea for iText in android.
http://technotransit.wordpress.com/2011/06/17/using-itext-in-android/
http://www.mysamplecode.com/2013/05/android-itext-pdf-bluetooth-printer.html
https://stackoverflow.com/a/21025162/3110609
This seems to just be a bug in PdfDocument. The PDF file I created with PdfDocument was 5.6 megabytes. The same document generated through the iOS equivalent was 500K. If I take the Android PDF and run it through Adobe Acrobat's pdf optimization, without compressing any images, the 5.6MB file becomes 350K. They look identical, and I applied no compression in Adobe Acrobat.
In the actual PDF code, the Android image object dictionary is this
The PDF from iOS has this dict
I think the problem is the lack of the FlateDecode filter in the Android version. When I run it through the Adobe Acrobat PDF optimizer, it gets the FlateDecode filter.