xhtml2pdf / xhtml2pdf

A library for converting HTML into PDFs using ReportLab
https://xhtml2pdf.readthedocs.io/
Apache License 2.0
2.26k stars 641 forks source link

Render dynamic Javascript to PDF #681

Closed sgavathe closed 1 year ago

sgavathe commented 1 year ago

Describe the Bug

I am seeing a weird issue where the html has a script tag and a chart. It's not rendering a chart. But I can clearly see a chart when I open the html page. Is there an issue with the script tags for it to export?

Minimal Example to Reproduce

<!DOCTYPE html>
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div> Test Example </div>
        <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: 'local'};</script>
        <script src="https://cdn.plot.ly/plotly-2.18.2.min.js"></script>                
        <div id="774ace57-929f-4e35-9a92-d5a5ca846d70" class="plotly-graph-div" style="height:100%; width:100%;"></div>            
        <script type="text/javascript">                                    window.PLOTLYENV=window.PLOTLYENV || {};                                    if (document.getElementById("774ace57-929f-4e35-9a92-d5a5ca846d70")) {                    Plotly.newPlot(                        "774ace57-929f-4e35-9a92-d5a5ca846d70",                        [{"marker":{"color":"rgb(128, 0, 128)"},"name":"Nodes","x":["Provide Metals and Materials","Produce and Provide Human and Animal Food Products and Services","Produce Chemicals","Produce and Provide Agricultural Products and Services","Provide Medical Care","Provide Payment, Clearing, and Settlement Services","Provide Public Safety","Supply Water","Develop and Maintain Public Works and Services","Provide Materiel and Operational Support to Defense","Operate Government","Provide Capital Markets and Investment Activities","Research and Development","Support Community Health","Maintain Access to Medical Records","Prepare for and Manage Emergencies","Preserve Constitutional Rights","Protect Sensitive Information","Provide Information Technology Products and Services","Provide Radio Broadcast Access Network Services","Operate Core Network","Perform Cyber Incident Management Capabilities","Provide Housing","Manage Wastewater","Transport Cargo and Passengers by Air","Provide and Maintain Infrastructure","Transport Cargo and Passengers by Vessel","Maintain Supply Chains","Transport Cargo and Passengers by Rail","Manage Hazardous Materials","Transport Cargo and Passengers by Road","Transport Materials by Pipeline","Fuel Refining and Processing Fuels","Exploration and Extraction of Fuels","Store Fuel and Maintain Reserves","Manufacture Equipment","Transmit Electricity","Generate Electricity","Provide Satellite Access Network Services","Provide Cable Access Network Services","Provide Wholesale Funding","Distribute Electricity","Provide Positioning, Navigation, and Timing Services","Provide Internet Based Content, Information, and Communication Services","Provide Insurance Services","Conduct Elections","Enforce Law","Provide Identity Management and Associated Trust Support Services","Provide Funding and Liquidity Services","Provide Consumer and Commercial Banking Services","Educate and Train","Transport Passengers by Mass Transit","Provide Wireline Access Network Services","Provide Internet Routing, Access, and Connection Services","Provide Wireless Access Network Services"],"y":["4.270","4.230","4.040","3.420","3.270","2.960","2.890","2.860","2.500","2.410","2.330","2.330","2.280","2.280","2.220","2.190","2.190","2.100","1.950","1.940","1.920","1.860","1.840","1.810","1.760","1.730","1.660","1.650","1.600","1.510","1.510","1.480","1.450","1.390","1.230","1.220","1.150","1.150","1.150","1.140","1.130","1.110","1.060","1.060","1.030","1.030","1.020","1.010","1.000","1.000","0.970","0.970","0.940","0.910","0.890"],"type":"bar"}],                        {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmapgl":[{"type":"heatmapgl","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"}}},"xaxis":{"tickfont":{"size":10},"position":0.05,"tickangle":-90,"tickmode":"array","tickvals":["A","B","C"],"showgrid":true,"gridwidth":0.1,"gridcolor":"rgb(200, 200, 200)"},"font":{"size":18},"title":{"text":"sunburst","x":0.5,"y":0.9},"legend":{"orientation":"v","yanchor":"top","y":-0.2,"xanchor":"left","x":0},"plot_bgcolor":"rgb(0, 0, 0)","yaxis":{"title":{"text":"Page Rank"},"showgrid":true,"gridwidth":0.1,"gridcolor":"rgb(200, 200, 200)"},"showlegend":true},                        {"displayModeBar": false, "showTips": false, "staticPlot": true, "responsive": true}                    )                };                            </script>        </div>
  </body>
</html>

Expected Behavior

I would have expected a PDF with a rendered html that I provided as I see it under html page itself.

Actual Behavior

Display a chart fully rendered in the final pdf.

Additional Information

chart that I see it under html page. image

System Information

ubuntu

OS version: Python version: 3.8.10 XHTML2PDF version: 0.2.6

timobrembeck commented 1 year ago

This library is an HTML renderer, not a JS renderer. So getting something like this to work is completely out of scope for this project.

Please consider to convert the chart to an image in JS, then embed it into a html document, and then convert it to PDF.

sgavathe commented 1 year ago

@timoludwig Thanks. I was hoping it would work this way, since all the other options are fading, especially all the major ones python libraries to export image from html.

coda7777 commented 1 year ago

i understand previously said it's html template i'm getting terrible results when i try to convert a page, colors, structure and everything, it's html x jinja2 template with bootstrap css loaded via cdn or staticfiles. i see photos loaded, and text rendered via jinja but the colors and placement of divs are too wrong ! can actually xhtml2pdf do that job or should i search for another solution ?

sgavathe commented 1 year ago

if you adjust the jinja2 template correctly, xhtml2pdf would do a decent job of aligning divs, tables, tags right. Just keep playing with your output and adjust it.

timobrembeck commented 1 year ago

@coda7777 This library can convert HTML + CSS to PDF. It has no idea what do to with JS code and will just ignore it. Also, it doesn't understand templating languages (such as Jinja2), so you need to render your template to html first (via whichever framework you're using) and then have to pass the html code to this library.

About bootstrap: There are quite a few css features that are not supported by this library (check out the existing issues), so if you have another specific feature that's missing and does not yet have an issue, feel free to open a feature request.

coda7777 commented 1 year ago

@coda7777 This library can convert HTML + CSS to PDF. It has no idea what do to with JS code and will just ignore it. Also, it doesn't understand templating languages (such as Jinja2), so you need to render your template to html first (via whichever framework you're using) and then have to pass the html code to this library.

About bootstrap: There are quite a few css features that are not supported by this library (check out the existing issues), so if you have another specific feature that's missing and does not yet have an issue, feel free to open a feature request.

i removed every CSS, JS calls in the template and used pure divs / css. it doesn't work, for example <h5 class="text-left" style="background-color: #ffc107b3; padding: 12px 6%; margin: 15px -5%;">

The background color is showing pink instead of the actual color orange-ish

these screenshot from same template rendered once as html webpage and the right one is the pdf created version of it, also notice the marked circle, that color is supposed to be grey-ish color <div class="row" style="background-color: #c56b0008; padding: 20px"> that's hardcoded in the template no dependancy on CSS (color wise) https://pasteboard.co/lxcP5dRYWvrT.png

Edited Update : while the issue above presist i figured out what's the reason. xhtml2pdf doesn't accept 8 digits hex color. meaning the transperancy value is not considered and it only renders 6 digits hex. that's why the color goes way off charts.