Create a PDF from Webview on Android
Asked Answered
M

3

7

So I am trying to create a PDF from a Webview. Right now I can create an image from the webview, but I am having some problems to split my document in many pages.

First, I create a Bitmap from the webview:

public static Bitmap screenShot(View view) {
        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
                view.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawColor(Color.WHITE);
        view.draw(canvas);
        return bitmap;
    }

Second, I create and I show the PDF:

public void criaPdf(){
        Bitmap bitmap = Utils.screenShot(mContratoWebview);

        Document doc = new Document();


        File dir = new File(getFilesDir(), "app_imageDir");

        if(!dir.exists()) {
            dir.mkdirs();
        }

        File file = new File(dir, "contratoPdf.pdf");

        try {
            FileOutputStream fOut = new FileOutputStream(file);

            PdfWriter.getInstance(doc, fOut);

            //open the document
            doc.open();

            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);

            byte[] byteArray = stream.toByteArray();
            Image image = Image.getInstance(byteArray);
            image.scaleToFit(PageSize.A4.getHeight(), PageSize.A4.getWidth());

            doc.newPage();
            doc.add(image);
        } catch (DocumentException de) {
            Log.e("PDFCreator", "DocumentException:" + de);
        } catch (IOException e) {
            Log.e("PDFCreator", "ioException:" + e);
        }
        finally {
            doc.close();
        }

        mPdfView.fromFile(file)
                .pages(0, 1) // all pages are displayed by default
                .enableSwipe(true)
                .load();
        mPdfView.setVisibility(View.VISIBLE);
}

This is what I got so far:

enter image description here

So my problem is: The content of the Webview is too big to fit in the PDF. How can I solve this?

Mellifluent answered 21/2, 2017 at 19:49 Comment(2)
how to show image in webview as well as in pdf!?Methedrine
Did you solve the problem? please shareCoakley
D
8

WebView has built-in functionality to generate PDFs which is made available by using PrintManager Service. For your use case, I would suggest you to write/store the final output of WebView's PrintAdapter which is a PDF file to a local file and go from there.

This link will walk you through the details and implementation. http://www.annalytics.co.uk/android/pdf/2017/04/06/Save-PDF-From-An-Android-WebView/

You can achieve API level 19(KitKat) compatibility with small tweaks for the above solution.

This should solve your problem but in case you face any issues with the implementation let me know.

Doddering answered 10/4, 2017 at 14:21 Comment(19)
I am trying the code you mentioned in the link annalytics.co.uk/android/pdf/2017/04/06/… but when i create PdfPrint class it gives error that PrintDocumentAdapter.WriteResultCallback is not public and can not be accessed from outside package.Chafer
I must have to create android.print packageChafer
When i create document , it's size is 0 byteChafer
Hi @AhesanaliMomin could you please provide more details on the problem you are facing?. I would suggest you to create a new question describing your problem in detail with your code and post that question link here.Doddering
I am using the code mentioned in above blog but the pdf created is of size 0Chafer
You need to load some content(url or raw Html) into the webView before generating a PDF. You can do that by using webview.load() after which you can attach a webClient which will generate the print job after the page is loaded in onPageLoadFinished(){} call back.Doddering
@RakeshGopathi Can you explain what the "small tweaks" are to achieve API 19 compatibility?Cankered
You could create the PrintAdpter from the WebView by using a if statements to check the API version like this __________ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { printAdapter = webView.createPrintDocumentAdapter(jobName); } else { printAdapter = webView.createPrintDocumentAdapter(); }Doddering
i am getting this error WriteResultCallback() is not public in WriteResultCallback; cannot be accessed from outside packageOahu
Did you save the PdfPrint class in package android.print ?Doddering
@RakeshGopathi can you help me please https://mcmap.net/q/753690/-pdf-printing-view-issueMohammedmohammedan
@AhesanaliMomin how to solve this PdfPrint class it gives error that PrintDocumentAdapter.WriteResultCallback is not public and can not be accessed from outside package. ???Methedrine
Create android.print package in your app and create the class inside itChafer
@AhesanaliMomin thank you for quick reply, error is solved but couldn't see anything in webview.Methedrine
If webview has nothing, print will do nothing. First try to load something in webviewChafer
hii @RakeshGopathi i tried your solution but i can only create one page in pdf; can you help me here #54870664Methedrine
@AhesanaliMomin you are right now my webview is working perfectly fine but i cant create and print multiple pages in pdf #54870664Methedrine
@AhesanaliSuthar I still can't solve the "PrintDocumentAdapter.WriteResultCallback is not public and can not be accessed from outside package." error, I created an android.print package in one of the modules and it still gives me that error, where exactly I have to put this package?Microorganism
It works in some device and i also face issues in other devices too. Finally i move to server to generate PDF task.Chafer
H
5

to create pdf from webview you need android>kitkat -> sdk>=19

  btnSave.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {

                createWebPrintJob(webView);
            } else {



            }

        }
    });

//// Function:

private void createWebPrintJob(WebView webView) {

    PrintManager printManager = (PrintManager) this
            .getSystemService(Context.PRINT_SERVICE);

    PrintDocumentAdapter printAdapter =
            webView.createPrintDocumentAdapter();

    String jobName = getString(R.string.app_name) + " Print Test";

    if (printManager != null) {
        printManager.print(jobName, printAdapter,
                new PrintAttributes.Builder().build());
    }
}

I have problem in create image from webview :))))

Hollishollister answered 6/1, 2018 at 6:57 Comment(2)
did you find any solution to show image in webview as well as in pdf!?Methedrine
can you share your code or help me how to do it here #54870664Methedrine
O
0

In my case, I solved this by firstly converting the webview into a bitmap, then scaling the bitmap to fit into the pdf page.

As for the printing part, I think it was more flexible to simply share the pdf and ask the user to select his printer software, as it's more useful than simply saving as pdf.

If you want to print several pages, I think it is more manageable to create different bitmaps and assign them to different pdf pages.

Here is the code to converting the webview into a single pdf page and then sharing it:

public static void sharePdfFile(WebView webView, Context context)
{
    Bitmap bitmap = webviewToBitmap( webView );
    PrintedPdfDocument pdf =  bitmapToPdf( bitmap, context );
    File file = pdfToFile( pdf, context );
    shareFile( file,"application/pdf", context );
}

private static void shareFile(File file, String contentType, Context context)
{
    Uri uri = FileProvider.getUriForFile(
        context,
        context.getPackageName() + ".fileprovider",
        file);
    Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
    shareIntent.setType(contentType);
    shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
    shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    Toast.makeText(
        context,
        "Choose your printer app",
        Toast.LENGTH_LONG
    ).show();
    context.startActivity( shareIntent );
}

private static File pdfToFile(PrintedPdfDocument printedPdfDocument, Context context)
{
    File file = new File(context.getFilesDir(), "share.pdf");
    try {
        FileOutputStream outputStream = new FileOutputStream(file);
        printedPdfDocument.writeTo(outputStream);
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    printedPdfDocument.close();
    return file;
}


private static PrintedPdfDocument bitmapToPdf(Bitmap bitmap, Context context)
{
    PrintAttributes printAttributes = new PrintAttributes.Builder()
        .setColorMode(PrintAttributes.COLOR_MODE_COLOR)
        .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
        .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
        .setResolution(new PrintAttributes.Resolution("1", "label", 300, 300))
        .build();
    PrintedPdfDocument printedPdfDocument = new PrintedPdfDocument(context, printAttributes);
    PdfDocument.Page pdfDocumentPage = printedPdfDocument.startPage(1);
    Canvas pdfCanvas = pdfDocumentPage.getCanvas();
    bitmap = scaleBitmapToHeight(bitmap, pdfCanvas.getHeight());
    pdfCanvas.drawBitmap(bitmap, 0f, 0f, null);
    printedPdfDocument.finishPage(pdfDocumentPage);
    return printedPdfDocument;
}

private static Bitmap webviewToBitmap(WebView webView) {
    webView.measure(
        View.MeasureSpec.makeMeasureSpec(
            0,
            View.MeasureSpec.UNSPECIFIED
        ),
        View.MeasureSpec.makeMeasureSpec(
            0,
            View.MeasureSpec.UNSPECIFIED
        )
    );
    int webViewWidth = webView.getMeasuredWidth();
    int webViewHeight = webView.getMeasuredHeight();
    webView.layout(0,0, webViewWidth, webViewHeight );
    Bitmap bitmap = Bitmap.createBitmap(webViewWidth, webViewHeight, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    canvas.drawBitmap(bitmap, 0, bitmap.getHeight(), new Paint());
    webView.draw(canvas);
    return bitmap;
}

private static Bitmap scaleBitmapToHeight(Bitmap bitmap, int maxHeight) {
    int height = bitmap.getHeight();
    if(height > maxHeight) {
        int width = bitmap.getWidth();
        float scalePercentage = ((float)maxHeight) / height;
        return Bitmap.createScaledBitmap(bitmap, (int) (width * scalePercentage), maxHeight, false);
    }
    return bitmap;
}
Overscrupulous answered 8/8, 2022 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.