Android PdfDocument file size

11,382

Solution 1

There are a few main things that increases the size of a PDF file:

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

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

Solution 2

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.

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();

=====

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.

Solution 3

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 :

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

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:

// 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();

This is embedded in Android so it is much easier than using a third-party library. (The above was tested on a Marshmallow platform)

Solution 4

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

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

The PDF from iOS has this dict

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

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.

Share:
11,382
evaristokbza
Author by

evaristokbza

Software engineer specialized in Android development.

Updated on June 03, 2022

Comments

  • evaristokbza
    evaristokbza about 2 years

    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;
    }