Android PdfDocument file size
Asked Answered
A

4

12

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;
}
Athlete answered 2/4, 2014 at 8:32 Comment(2)
Have you find any solution for using the native android APITomika
Please read my comment in the accepted answer. It was solved resizing bitmaps in ImageViews before generating the PDF.Athlete
T
6

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://mcmap.net/q/927704/-how-to-reduce-pdf-file-size-programmatically-in-java

Tune answered 2/4, 2014 at 11:41 Comment(2)
Thanks for the advice, but I still want to use the system's one. I'll try to simplify the PDF, but it is just some textViews and an image. No special fonts or any other embedded objects...Athlete
It turned out the problem was the image. Even when the ImageView holding it was quite small, the bitmap was huge and it spent most of the size. Fixed just scaling the bitmap before setting it to ImageView. Thanks.Athlete
E
8

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.

Eades answered 9/11, 2017 at 1:14 Comment(5)
Also PdfBox takes a lot of time to render, I tested a 90 pages file, gave up after 6 minutes and i started debugging and see its at page 31Paraph
How to centre the image on page?Sematic
Hi @AkashChaudhary, please refer to the comments in the example answer, you may want to call PDPage.getCropBox() to get the page rect in order to center the image (providing you already know the image rect).Eades
But using image on A4 size makes the image out of page due to which it is partially visible. Can you please tell how to make it fit inside the A4 page without scaling it down.Sematic
Hi @AkashChaudhary, in short you may want to scale the image to fit in your document page before drawing it. For example, if the RECT size you retrieve from PDPage.getCropBox() is 600x800, then you will need to scale your image (usually keeping the ratio) so its width <= 600 (and maybe height <= 800 as well if needed). You can refer to @JM Lord's answer using Bitmap.createScaledBitmap().Eades
T
6

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://mcmap.net/q/927704/-how-to-reduce-pdf-file-size-programmatically-in-java

Tune answered 2/4, 2014 at 11:41 Comment(2)
Thanks for the advice, but I still want to use the system's one. I'll try to simplify the PDF, but it is just some textViews and an image. No special fonts or any other embedded objects...Athlete
It turned out the problem was the image. Even when the ImageView holding it was quite small, the bitmap was huge and it spent most of the size. Fixed just scaling the bitmap before setting it to ImageView. Thanks.Athlete
F
4

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)

Floodgate answered 15/12, 2017 at 22:51 Comment(0)
T
3

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.

Testudinal answered 29/4, 2015 at 20:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.