6

PdfDocument is a class that makes it possible to generate a PDF from an Android View. You simply add a View to PdfDocument and then save the PDF to memory.

However, I wouldn't like to add a View that is already rendered in the screen, because such View is only good for smartphone screens, and I want to generate a PDF document for printers.

Therefore, I want to pass a View without rendering. While it's certainly possible for me to do that, how would the dimensions and proportions be decided? How can I control this in my PDF?

UPDATE:

Following the answer below from clotodex, I did:

    LayoutInflater inflater = getLayoutInflater();
    View linearview;
    linearview = inflater.inflate(R.layout.printed_order,
                                  findViewById(android.R.id.content),
                                  false);

    PdfDocument document = new PdfDocument();
    PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(2480, 3508, 0).create();
    PdfDocument.Page page = document.startPage(pageInfo);

    linearview.draw(page.getCanvas());
    document.finishPage(page);

    OutputStream outStream;
    File file = new File(getExternalFilesDir(null), "pedido.PDF");

    try {
        outStream = new FileOutputStream(file);
        document.writeTo(outStream);
        document.close();
        outStream.flush();
        outStream.close();

but I get an empty PDF. If I do

View view = findViewById(android.R.id.content);
view.draw(page.getCanvas());

in place of

linearview.draw(page.getCanvas()); 

I get the activity I'm in, which confirms everything is rigth, except for the view that I'm trying to print.

PPP
  • 1,279
  • 1
  • 28
  • 71
  • "but I don't know from which of the 2 layouts this error comes from" -- um, it's associated with line 18 in one of them. It should not be too hard to track down. Or, edit your question and post the layouts, and perhaps somebody can point out which one has the problem. – CommonsWare Jan 29 '20 at 12:10
  • @CommonsWare thanks, I found that. Can you take a look at my update? – PPP Jan 29 '20 at 22:11
  • Use `inflater.inflate(R.layout.printed_order, null);`, as you do not want it to be in your activity's layout. However, you probably need to call `measure()` and `layout()`, matching your desired page size in pixels, before `draw()`. – CommonsWare Jan 29 '20 at 23:21

3 Answers3

3

Have a look at this question render view off-screen in android.

In Android the measurements for a view are given by the parent layout. This means you can create a new layout with your desired measurements and inflate your view with attachToRoot=false and root=your_new_layout.

When you have rendered the view you can now proceed as you would with drawing a rendered view to pdf (following the instruction in your link or converting it to a bitmap before drawing to the page canvas).

clotodex
  • 193
  • 2
  • 10
  • can you take a look at my update? I did almost what you said but I don't know how to create my root layout and I'm getting size errors – PPP Jan 29 '20 at 02:55
  • I updated with better code that now generates a PDF but it's blank. Can you take a look? – PPP Jan 29 '20 at 21:50
  • Maybe the layout hadn't been measured yet? Try adding the layout to your activity and then draw it again but finding the view by id, or rendering the entire content, which should include what you want to print. – shalafi Jan 30 '20 at 22:37
  • @lucas-zanella You can try and follow the answer(s) of [this question](https://stackoverflow.com/questions/4346710/bitmap-from-view-not-displayed-on-android). They seem to have a similar problem. You indeed need to layout your View. ```linearview.measure(...);``` then ```linearview.layout(0, 0, linearview.getMeasuredWidth(), linearview.getMeasuredHeight());``` Please comment again if this doesn't work. – clotodex Jan 31 '20 at 12:58
0

I think if you only want to print to pdf, you can use PrintManager related API. for detail, you can see this API.

here is some example code for pdf.

// method for PrintAdapter
override fun onLayout(
        oldAttributes: PrintAttributes?,
        newAttributes: PrintAttributes,
        cancellationSignal: CancellationSignal?,
        callback: LayoutResultCallback,
        extras: Bundle?
) {
    // Create a new PdfDocument with the requested page attributes
    pdfDocument = PrintedPdfDocument(activity, newAttributes)
    // Compute the expected number of printed pages
    val pages = computePageCount(newAttributes)
    if (pages > 0) {
        // Return print information to print framework
        PrintDocumentInfo.Builder("print_output.pdf")
                .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
                .setPageCount(pages)
                .build()
                .also { info ->
                    // Content layout reflow is complete
                    callback.onLayoutFinished(info, true)
                }
    } else {
        // Otherwise report an error to the print framework
        callback.onLayoutFailed("Page count calculation failed.")
    }
}

Lenoarod
  • 3,441
  • 14
  • 25
  • No, I want to have a custom layout suitable for printers, different from the one that shows data. How should I work with this layout without rendering it to screen? – PPP Jan 20 '20 at 02:47
0

I used PrintHelper you can find its document here

public void print() {
    if(PrintHelper.systemSupportsPrint()){
        final Bitmap bm;
        try {
              bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
              bm.eraseColor(Color.WHITE);// otherwise it will be trans
              final Canvas canvas = new Canvas(bm);
              drawOn(canvas)// draw on canvas
        }catch (OutOfMemoryError er) {
              // out of memory error
              return;
        }
        if(bm == null) return;
        final PrintHelper printHelper = new PrintHelper(getContext());
        printHelper.setScaleMode(PrintHelper.SCALE_MODE_FIT);
        printHelper.printBitmap("fileName", bm, new PrintHelper.OnPrintFinishCallback() {
                @Override
                public void onFinish() {
                        bm.recycle();
                }
            });

    }else{
            // print not supported
    }
}
ygngy
  • 3,630
  • 2
  • 18
  • 29