19

I have created an Android Invoice app. The generated invoice is standard Android layout with nested views. I am looking for a library that I can use to convert this view to an pdf document.

I am surprised there is no straight forward option coming up in my search or Perhaps I have the done the first thing last. Or perhaps what I am looking for is not possible.

Would someone please help point me to a tool that will help me convert or generate a PDF from an Android view. I am open to free and modest paid option. Or let me know is if what I am looking for is not possible.

Aniruddh Parihar
  • 3,072
  • 3
  • 21
  • 39
Val Okafor
  • 3,371
  • 13
  • 47
  • 72

4 Answers4

17

Take a screen at your device:

Bitmap screen;
View v1 = MyView.getRootView();
v1.setDrawingCacheEnabled(true);
screen= Bitmap.createBitmap(v1.getDrawingCache());
v1.setDrawingCacheEnabled(false);

If you're having ScrollView as root view then:

LayoutInflater inflater = (LayoutInflater) this.getSystemService(LAYOUT_INFLATER_SERVICE);
RelativeLayout root = (RelativeLayout) inflater.inflate(R.layout.activity_main, null); //RelativeLayout is root view of my UI(xml) file.
root.setDrawingCacheEnabled(true);
Bitmap screen= getBitmapFromView(this.getWindow().findViewById(R.id.relativelayout)); // here give id of our root layout (here its my RelativeLayout's id)

Here is the getBitmapFromView() method:

public static Bitmap getBitmapFromView(View view) {
    //Define a bitmap with the same size as the view
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    //Bind a canvas to it
    Canvas canvas = new Canvas(returnedBitmap);
    //Get the view's background
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null) 
        //has background drawable, then draw it on the canvas
        bgDrawable.draw(canvas);
    else 
        //does not have background drawable, then draw white background on the canvas
        canvas.drawColor(Color.WHITE);
    // draw the view on the canvas
    view.draw(canvas);
    //return the bitmap
    return returnedBitmap;
}

It will display entire screen including content hidden in your ScrollView. Now that we have our bitmap screen let's save it to pdf (you have to download itextpdf-5.3.2.jar file and attach in your project..)

private static String FILE = "mnt/sdcard/invoice.pdf"; // add permission in your manifest...

try 
{
    Document document = new Document();

    PdfWriter.getInstance(document, new FileOutputStream(FILE));
    document.open();
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    screen.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    addImage(document,byteArray);
    document.close();
}

catch (Exception e) 
{
    e.printStackTrace();
}

private static void addImage(Document document,byte[] byteArray) 
{
    try 
    {
        image = Image.getInstance(byteArray);  
    } 
    catch (BadElementException e) 
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (MalformedURLException e) 
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (IOException e) 
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
     // image.scaleAbsolute(150f, 150f);
      try 
      {
        document.add(image);
    } catch (DocumentException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Haven't tested anything. Here are all the sources I used: source1, source2, source3.

Community
  • 1
  • 1
n1nsa1d00
  • 856
  • 9
  • 23
  • Interesting, I am exploring your suggestion right now – Val Okafor Apr 19 '15 at 14:39
  • Cool. Let me know if it works... If you're able to recreate the same layout in a `WebView` then you should search for a way to save `html` to pdf... – n1nsa1d00 Apr 19 '15 at 14:42
  • 2
    Thanks, brilliant idea, it almost works. However it took screenshot of everything including the Actionbar. It also final pdf also is a little blurry. Thanks again for the suggestion. It opened up my eyes and I will continue to see other alternatives. Thanks again for your great contribution. – Val Okafor Apr 20 '15 at 04:50
  • so appreciate it sir @ValOkafor – Elltz Aug 01 '15 at 09:56
  • Looks very interesting, but don´t you have to pay for text license? – david Sep 03 '15 at 16:29
  • yes @Marco Dufai it is painful, I actually have to pull my app off the Play Store and exploring other my alternatives. I spent three months writing my Invoice app and the PDF generation was only a small portion of it. I wrote the company and they confirmed to me in writing that I need to pay for yearly license per each download of the app. So I un-publish the app for now. Definetly pay attention to licenses, not all open source is free – Val Okafor Sep 04 '15 at 06:52
  • @ValOkafor Sorry about that.. Didn't even know about it.. As I stated at the end of my answer I just got all the sorces that could've realize my initial idea here and there around this website... Anyway it's a good thing that we've pointed that out at least in the comments section right ? – n1nsa1d00 Sep 04 '15 at 10:14
  • @MarcoDufal hello as i am trying to decode the pdf it is not showing entire screen why it is so. – Nikhil Singh Mar 09 '16 at 14:38
  • 1
    I am using the same code but i am getting only half of view pdf , please any one help me on it – Nikhil Singh Mar 10 '16 at 06:52
  • @NikhilSingh Are you trying to say that you can only display half .pdf document in your `Activity`? – n1nsa1d00 Mar 10 '16 at 12:02
5

You can use a custom library such as https://github.com/HendrixString/Android-PdfMyXml. I prefer this library than any other method. Just Go through these.

but there is another way - How to convert Android View to PDF - that generate a pdf that contains bitmap of your layout

Avinash
  • 361
  • 4
  • 16
2

I made a library to achieve this objective (Getting PDF from Java View objects).

The main code snippet is -

 PdfGenerator.getBuilder()
                        .setContext(context)
                        .fromViewSource()
                        .fromView(targetView) /* "targetView" is the view ,you want to convert PDF */
            /* "fromLayoutXML()" takes array of layout resources.
             * You can also invoke "fromLayoutXMLList()" method here which takes list of layout resources instead of array. */
                        .setDefaultPageSize(PdfGenerator.PageSize.A4)
            /* It takes default page size like A4,A5. You can also set custom page size in pixel
             * by calling ".setCustomPageSize(int widthInPX, int heightInPX)" here. */
                        .setFileName("Test-PDF")
            /* It is file name */
                        .setFolderName("FolderA/FolderB/FolderC")
            /* It is folder name. If you set the folder name like this pattern (FolderA/FolderB/FolderC), then
             * FolderA creates first.Then FolderB inside FolderB and also FolderC inside the FolderB and finally
             * the pdf file named "Test-PDF.pdf" will be store inside the FolderB. */
                        .openPDFafterGeneration(true)
            /* It true then the generated pdf will be shown after generated. */
                        .build(new PdfGeneratorListener() {
                            @Override
                            public void onFailure(FailureResponse failureResponse) {
                                super.onFailure(failureResponse);
                /* If pdf is not generated by an error then you will findout the reason behind it
                 * from this FailureResponse. */
                            }

                            @Override
                            public void showLog(String log) {
                                super.showLog(log);
                /*It shows logs of events inside the pdf generation process*/ 
                            }

                            @Override
                            public void onSuccess(SuccessResponse response) {
                                super.onSuccess(response);
                /* If PDF is generated successfully then you will find SuccessResponse 
                 * which holds the PdfDocument,File and path (where generated pdf is stored)*/
                
                            }
                        });
Gk Mohammad Emon
  • 6,084
  • 3
  • 42
  • 42
2

Without using a third-party library you can use PdfDocument which was introduced in Android API 19. However, keep in mind that the dimension of the pdf file will be in the postscript point(1/72 inch). Therefore, you have to convert your view's dimension to match the requirement before drawing to the canvas.

Patriotic
  • 2,103
  • 4
  • 26
  • 36