Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Drawing to a PDF canvas from WebView

I've been having troubles getting PDF printing work on Android. What I'm trying to do is render some HTML in WebView, then draw the WebView contents on a PDF canvas and finally write the PDF to a file. The problem I'm having is that when I draw to the PDF canvas the content gets clipped even though there is plenty of canvas left. I've tried resizing the canvas using the .clipRect(Rect rect, Op op) and that kind of worked but not as well as I would've liked.

I also have no idea how I can translate the HTML px measurements to the PDF PostScript 1/72th inch measurements reliably.

Here's the code I'm using:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView wv = (WebView) this.findViewById(R.id.webView1);

    wv.loadUrl("file:///android_asset/temp.html");           
}

public void button1onClick(View v)
{
    //Create PDF document
    PdfDocument doc = new PdfDocument();

    //Create A4 sized PDF page
    PageInfo pageInfo = new PageInfo.Builder(595,842,1).create();

    Page page = doc.startPage(pageInfo);

    WebView wv = (WebView) this.findViewById(R.id.webView1);

    page.getCanvas().setDensity(200);

    //Draw the webview to the canvas
    wv.draw(page.getCanvas());

    doc.finishPage(page);

    try
    {
        //Create the PDF file
        File root = Environment.getExternalStorageDirectory();          
        File file = new File(root,"webview.pdf");
        FileOutputStream out = new FileOutputStream(file);
        doc.writeTo(out);
        out.close();
        doc.close();

        //Open the PDF
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file), "application/pdf");
        intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        startActivity(intent);          
    }
    catch(Exception e)
    {
        throw new RuntimeException("Error generating file", e);
    }
}

Basically the program just loads the temp.html file to webview and renders me a button that I can use to create the PDF.

The temp.html file looks like:

<html>
<head>
    <style>
        div.border
        {
            width:600px;
            height:800px;
            border:1px solid black;
        }
    </style>
</head>
<body>
    <div class="border"></div>
</body>

And here is the result with manually added black border to show the scale:

enter image description here

I would really appreciate some tips on how to convert HTML to PDF reliably on Android without using libraries that require licenses for commercial use.

like image 876
Tero Heiskanen Avatar asked Nov 09 '14 12:11

Tero Heiskanen


People also ask

Can WebView load PDF?

Opening a PDF file in Android using WebView All you need to do is just put WebView in your layout and load the desired URL by using the webView. loadUrl() function. Now, run the application on your mobile phone and the PDF will be displayed on the screen.

Can we draw directly on canvas in android studio?

The parameter to onDraw() is a Canvas object that the view can use to draw itself. The Canvas class defines methods for drawing text, lines, bitmaps, and many other graphics primitives. You can use these methods in onDraw() to create your custom user interface (UI).


1 Answers

Summary: Don't modify the density, (it should be set on your device, probably to medium 160 dpi) instead, use scale. If you Just need Bitmaps of your HTML page in your PDF (No hyper-link function), this works. This is what your code is generating, with the following code:

    //Create PDF document

        PdfDocument doc = new PdfDocument();

        //Create A4 sized PDF page
        int my_width  = 595;
        int my_height = 842;

        PageInfo pageInfo = new PageInfo.Builder(my_width,my_height,1).create();
//      PageInfo pageInfo = new PageInfo.Builder(650,850,1).create();

        Page page = doc.startPage(pageInfo);

        WebView wv = (WebView) this.findViewById(R.id.webView1);

        Canvas canvas = page.getCanvas();
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        final DisplayMetrics displayMetrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(displayMetrics);
        int    height  = displayMetrics.heightPixels;
        int    width   = displayMetrics.widthPixels;
        float  density = displayMetrics.density;
        int    wvWidth = wv.getWidth();
        int    wvHeight= wv.getHeight();
        float  wvScaleX= wv.getScaleX();
        float  wvScaleY= wv.getScaleY();

//      canvas.setDensity(100);//200 Bitmap.DENSITY_NONE
        int cdensity = canvas.getDensity();
        float scaleWidth = (float)width/(float)my_width;
        float scaleHeight = (float)height/(float)my_height;
        canvas.scale(scaleWidth, scaleHeight);
        Log.e("button1onClick","canvas width:" + canvas.getHeight() + " canvas height:" +  canvas.getWidth());
        Log.e("button1onClick","metrics width:" + width + " metrics height:" +  height + "metrics density:" +  density);
        Log.e("button1onClick"," wvWidth:" + wvWidth + " wvHeight:" +  wvHeight);
        Log.e("button1onClick"," scaleWidth: " + scaleWidth +
                " scaleHeight:" +  scaleHeight +" cdensity:" + cdensity);
        Paint paint = new Paint();
//      paint.setStyle(Style.FILL);
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1);

        //Draw the webview to the canvas
        wv.draw(canvas);
        canvas.scale(1f, 1f);
        canvas.drawRect(0, 0, canvas.getWidth()-1,  canvas.getHeight()-1, paint);
        canvas.drawText("Direct drawn Red Rectangle to fill page canvas 0, 0," +
                canvas.getWidth() + "," + canvas.getHeight(), 100, 100, paint);

        doc.finishPage(page);

webview.pdf

This works well (Hyper-links cannot work of course). More complex example: more complex example

like image 89
Jon Goodwin Avatar answered Oct 09 '22 12:10

Jon Goodwin