Search code examples
javaandroidpdfbitmapandroid-viewpager

Print pdf in multiple pages if one page not enough


I'm trying to create a PDF from layout; I converted the layout to bitmap and then printed into the pdf page. The application converts the output into a long PDF page, but I want to divide the bitmap into several parts then print in multiple PDF pages each one A4 size, if the first page is not enough, create a second page and print the remaining part on it ..

How I can do it?

private void generatePdfFromView(View view) {

    Bitmap bitmap = getBitmapFromView(view);
    document = new PdfDocument();

    PdfDocument.PageInfo myPageInfo = new PdfDocument.PageInfo.Builder(view.getWidth(),view.getHeight(),1).create();
    PdfDocument.Page myPage = document.startPage(myPageInfo);
    Canvas canvas = myPage.getCanvas();
    canvas.drawBitmap(bitmap,0,0,null);

    document.finishPage(myPage);

    PdfDocument.PageInfo myPageInfo1 = new PdfDocument.PageInfo.Builder(view.getWidth(),view.getHeight(),2).create();
    PdfDocument.Page myPage1 = document.startPage(myPageInfo1);
    Canvas canvas1 = myPage1.getCanvas();
    canvas1.drawBitmap(bitmap,0,0,null);
    document.finishPage(myPage1);
    createFile();
}
    
    
private Bitmap getBitmapFromView(View view) {

    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(),Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(returnedBitmap);

    Drawable bgDrawable = view.getBackground();
    if (bgDrawable != null){
        bgDrawable.draw(canvas);
    } else {
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);

    return returnedBitmap;
}

Solution

  • This really depends on how you generate your layout (which you don't show in your question) and what your layout shows and how nicely you want the split across multiple pages to be.

    The are 2 main strategies:-

    1. Just split the bitmap in multiple bitmaps and put each new bitmap on a new pages. This does not produce very good results because it is hard to split the bitmap in a logical location (i.e not half way in a line of text)

    2. Draw the view direct to the PDF canvas using a view Just for the PDF, one that is never displayed on screen (the reason why this view is never displayed on screen because an A4 page is 595 pixels wide and 842 pixels high and won't match the size of the devices display screen). This has the advantage that the PDF is editable, as text is text not a picture of text, which the PDF scales better on screen and is smaller in size). It also allows you to reformat each page.

    My App actually uses a hybrid of both strategies because it also wants to produce png's for facebook for each PDF page, but the main strategy is 2. "draw direct"

    So a summary of the "draw direct" method.

    1. You generate your layout as multiple views in a LinearLayout (makes it easier for splitting)

    2. Create an ArrayList of View's you want to add as rows in your LinearLayout and programmatically create each view and add them to the ArrayList

    3. Add all views to your LinearLayout and then measure and layout the LinearLayout

    for ( int c = 0; c < viewArrayList.size(); c++){
       linearLayout.addView(classTables.get(c));
    }
    
    linearLayout.measure(
            // Measure to A4 width
            View.MeasureSpec.makeMeasureSpec(595, View.MeasureSpec.EXACTLY
            ),
            // Measure to as high as the view needs
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
            )
        )
    // Layout the view out to the measure dimensions
    linearLayout.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight())
    

    This will size all the views

    1. Remove all the views from the linearLayout
    linearLayout.removeAllViews();
    
    1. Iterate over the arraylist again adding the views back to the linearLayout until the cumulative height is row short of exceeding the max height of an A4 page (842 pixels).

    Then remeasure and layout to position everything again to get everything on screen.

    Draw this layout to the canvas of PDF page (or bitmap)

    1. Repeat Steps 4 and 5 for each PDF page (removing all view and then adding the next page set of row to the LinearLayout. Then measure/layout this page and draw to canvas.

    Do this until all rows are drawn to multiple PDF pages.


    The key is measure all view elements on get their height, so you can plan how many you can add to a Layout to fit on a PDF page.

    This is sort of how I display a view on to multiple pages of a PDF (I actually size the view for the width to be Wrap Content and work out a scale to size it to A4 width and calculate what height at that scale makes a single page and add enough elements to fill that, then create a bitmap of this page and add the bitmap to the pdf Page's canvas by setting the scale on the pdf's canvas. The reason I do this hybrid approach is that as well as a paginated pdf of the view I also want Png's of each page to put on Facebook)

    The key is actually to split your view generation in to multiple views