html-to-image
html-to-image copied to clipboard
styles issue in 1.11.13
On upgrading html-to-image from 1.11.11 to 1.11.13 in https://github.com/80avin/jsontree/tree/cde2580307f9e6e891bc8326c5f5d3bf24edfdca I see the SVG & png are not drawn correctly. On inspecting, I find that the line modified in PR https://github.com/bubkoo/html-to-image/pull/384 is giving error
Error loading remote stylesheet SyntaxError: Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to parse the rule
Strangely, the exact same rule passes in 1.11.13 and the only difference I see in the failing line was introduced in https://github.com/bubkoo/html-to-image/pull/384
Expected Behavior
Download image like
Current Behavior
Image generated is
Possible Solution
Steps To Reproduce
- Clone the project https://github.com/80avin/jsontree/tree/cde2580307f9e6e891bc8326c5f5d3bf24edfdca ( checkout to this commit if it is not latest )
- Update html-to-image to 1.11.13
- Run the app and click on download button in header
Error Message & Stack Trace
<!-- Provide a log message if relevant -->
Additional Context
Your Environment
- html-to-image: 1.11.13
- OS: Ubuntu 24.04
- Browser: Version 134.0.6998.165 (Official Build) (64-bit)
👋 @80avin
Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines.
We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.
@80avin
it could be font problem, try to add skipFonts: true
toPng( ref.current, { ....... skipFonts: true, } )
@kdl-github-albert Confirmed, it is not font problem.
Even with skipFonts: true, it fails.
I am also seeing regressions. We upgraded from v1.11.11 -> 1.11.13
<div style="width: 400px; height: 200px; position: relative; background-color: white; overflow: hidden; display: flex; justify-content: center; padding: 0px 10px;"><div style="width: calc(100% - 20px); height: auto; display: flex; flex-direction: column; align-items: center; overflow: hidden;"><table style="border-collapse: collapse;" cellspacing="0">
<tbody>
<tr>
<td style="background-color: #2f5496; vertical-align: top; width: 155px; border: 1px solid black;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;"><span style="color: white;">Project Phase</span></span></span></span></p>
</td>
<td style="background-color: #2f5496; border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: 1px solid black; vertical-align: top; width: 396px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;"><span style="color: white;">Activities in Scope</span></span></span></span></p>
</td>
<td style="background-color: #2f5496; border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: 1px solid black; vertical-align: top; width: 120px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;"><span style="color: white;">Estimated Hours</span></span></span></span></p>
</td>
</tr>
<tr>
<td style="background-color: #e7e6e6; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; border-top: none; vertical-align: top; width: 671px;" colspan="3">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;"><span style="color: black;">{technology} Cloud Build</span></span></span></span></p>
</td>
</tr>
<tr>
<td style="border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; border-top: none; vertical-align: top; width: 155px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">Deploy (2) Nodes within AWS per Region</span></span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 396px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">Our Services will assist with onboarding of the remote offices. We believe having three nodes per AWS Region will provide optimal High Availability (HA)</span></span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 120px;">
<p><span style="font-family: Calibri,sans-serif;"><span style="font-size: 16px;">16</span></span></p>
</td>
</tr>
<tr>
<td style="background-color: #e7e6e6; border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; border-top: none; vertical-align: top; width: 552px;" colspan="2">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;"><span style="color: black;">Feedback and Environment Remediation</span></span></span></span></p>
</td>
<td style="background-color: #e7e6e6; border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 120px;">
<p> </p>
</td>
</tr>
<tr>
<td style="border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; border-top: none; vertical-align: top; width: 155px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">Solicit Initial feedback</span></span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 396px;">
<p><span style="font-family: Calibri,sans-serif;"><span style="font-size: 16px;">Work with initial pilot user groups to solicit feedback around the performance of the platform. </span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 120px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">5</span></span></span></p>
</td>
</tr>
<tr>
<td style="border-bottom: 1px solid black; border-left: 1px solid black; border-right: 1px solid black; border-top: none; vertical-align: top; width: 155px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">Environment Remediation</span></span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 396px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">Our Services will allocate up to <strong>10 project-hours</strong> for initial remediation as part of this engagement. Should more hours be needed, we will discuss it with the client project lead and provide an addendum to this scope definition upon mutual agreement.</span></span></span></p>
</td>
<td style="border-bottom: 1px solid black; border-left: none; border-right: 1px solid black; border-top: none; vertical-align: top; width: 120px;">
<p><span style="font-size: 11pt;"><span style="font-family: Calibri,sans-serif;"><span style="font-size: 12.0pt;">20</span></span></span></p>
</td>
</tr>
</tbody>
</table></div></div>
Renders
With no options present (removed them during triage)
+1 on this issue - it seems like style rendering overall is broken in 1.11.13
any workarounds for this issue?
update: the below code worked for me...i m using nextjs with tailwind await toPng(ref.current, { includeQueryParams: true, filter: (node) => !node.classList?.contains('no-export'), });
The css classes for SVGs are not applied after upgrading to 1.11.13. Works in 1.11.11
import React, { useState } from "react"; import { Panel, useReactFlow, getNodesBounds } from "reactflow"; import { toPng } from "html-to-image"; import { Button } from "@mui/material"; import { Download } from "@mui/icons-material";
function downloadImage(dataUrl) {
const a = document.createElement("a");
a.setAttribute("download", workflow-${Date.now()}.png);
a.setAttribute("href", dataUrl);
a.click();
}
function getEdgeBounds(nodes, edges) { let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
nodes.forEach((node) => { const nodeX = node.position.x; const nodeY = node.position.y; const nodeWidth = node.width || 150; const nodeHeight = node.height || 50;
minX = Math.min(minX, nodeX);
minY = Math.min(minY, nodeY);
maxX = Math.max(maxX, nodeX + nodeWidth);
maxY = Math.max(maxY, nodeY + nodeHeight);
});
edges.forEach((edge) => { if (edge.sourceX && edge.sourceY && edge.targetX && edge.targetY) { minX = Math.min(minX, edge.sourceX, edge.targetX); minY = Math.min(minY, edge.sourceY, edge.targetY); maxX = Math.max(maxX, edge.sourceX, edge.targetX); maxY = Math.max(maxY, edge.sourceY, edge.targetY); } });
const edgePadding = 200; return { x: minX - edgePadding, y: minY - edgePadding, width: maxX - minX + edgePadding * 2, height: maxY - minY + edgePadding * 2, }; }
function DownloadButton() { const { getNodes, getEdges } = useReactFlow(); const [isDownloading, setIsDownloading] = useState(false);
const onClick = () => { setIsDownloading(true);
const reactFlowElement = document.querySelector(".react-flow");
const nodes = getNodes();
const edges = getEdges();
const bounds = getEdgeBounds(nodes, edges);
const viewportElement = document.querySelector(".react-flow__viewport");
const edgePaths = reactFlowElement.querySelectorAll(
".react-flow__edge-path"
);
edgePaths.forEach((path) => {
path.setAttribute(
"style",
"stroke: #b1b1b7; stroke-width: 2; fill: none;"
);
});
toPng(viewportElement, {
backgroundColor: "#ffffff",
width: bounds.width,
height: bounds.height,
pixelRatio: 2,
style: {
width: bounds.width,
height: bounds.height,
transform: `translate(${-bounds.x}px, ${-bounds.y}px) scale(1)`,
},
})
.then(downloadImage)
.catch((error) => {
console.error("Export failed:", error);
})
.finally(() => {
setIsDownloading(false);
});
};
return ( <Panel position="top-right"> <Button onClick={onClick} color="primary" variant="contained" disabled={isDownloading} sx={{ "&:hover": { backgroundColor: "#1565c0", }, }} startIcon={<Download />} > {isDownloading ? "Downloading..." : "Download Image"} </Button> </Panel> ); }
export default DownloadButton;
Just Create Download button and implement like this it will download perfect image :)
This is still a regression from 1.11.11. Are you going to publish a fix for this?