Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android PdfDocument damaged when saved to external storage

I'm trying to create a simple PDF document using Androids native PdfDocument class (from api 19). What i want is to have an XML layout file, for example called pdf_doc.xml, and then inflate it when creating the PDF. Inside the pdf_doc.xml i would then have a bunch of views that could be fetched in the code, and then drawn onto the PdfDocuments pages, seperately. The problem is, that this creates a damaged PDF file.

On the other hand, if i just create a simple TextView, in my main_activity.xml (the xml of the activity i'm using when creating the PDF) and use that TextView instead, it works fine.

Why does it make a difference whether the TextView comes from an inflated layout or the activity's layout? Am i trying to do this the wrong way?

FYI: It also fails when creating the TextView programmatically.

Below is my source code. These two functions are called right after eachother. The first one creates the PDF, the other one saves it. The problem is in the view, called content, that im getting from the inflated layout. If i instead put that TextView in the Activity's XML and then get it from the activity, like this act.findViewById(R.id.pdf_text); it then workst as intended.

Code:

    public static PdfDocument createPdf(Activity act){
        PrintAttributes printAttrs = new PrintAttributes.Builder().
                setColorMode(PrintAttributes.COLOR_MODE_COLOR).
                setMediaSize(PrintAttributes.MediaSize.ISO_A4).
                setMinMargins(PrintAttributes.Margins.NO_MARGINS).
                build();

        ViewGroup mainLayout = (ViewGroup) View.inflate(act, R.layout.pdf_doc, null);

        int pageHeight = printAttrs.getMediaSize().getHeightMils() / 1000 * 72;
        int pageWidth = printAttrs.getMediaSize().getWidthMils() / 1000 * 72;

        PdfDocument document = new PrintedPdfDocument(act, printAttrs);
        PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(pageWidth, pageHeight, 1).create();
        PdfDocument.Page page = document.startPage(pageInfo);

        View content = mainLayout.findViewById(R.id.pdf_text);
        content.draw(page.getCanvas());
        document.finishPage(page);

        return document;
    }

    public static void saveFile(PdfDocument doc){
        String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString();
        File myDir = new File(root + "/pdf_test");
        myDir.mkdirs();

        File file = new File(myDir, "test.pdf");

        if (file.exists()) {
            file.delete();
        }

        try {
            FileOutputStream out = new FileOutputStream(file);
            doc.writeTo(out);
            doc.close();
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        String path = file.getAbsolutePath();
        Log.d("pdftest", "path: " + path);
    }
like image 958
Teilmann Avatar asked Nov 10 '22 00:11

Teilmann


1 Answers

Two suggestions:

  1. Since your mainLayout will have zero height and zero width (you haven't inflated it into a parent), try manually laying it out, by calling measure() and layout() on it, in that order. You will need to specify a size in pixels that you want the layout to be sized to.

  2. Call out.getFd().sync() after out.flush() and before out.close(). I doubt that this is causing your specific problem here, but it's a good idea and is unlikely to hurt.

like image 102
CommonsWare Avatar answered Nov 14 '22 22:11

CommonsWare