Skip to content

Commit

Permalink
fix: Large Dom sizes failing to be drawn correctly into canvas when e…
Browse files Browse the repository at this point in the history
…xporting to PNG (#197)

When context.drawImage is called within the toCanvas method, we are able
to go over the maximum limits of the browser inbuilt canvas object.
When this happens draw commands within context.drawImage are ignored resulting
in missing parts of the image.
See
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size
for details.
This adds a checkCanvasDimensions function to ensure that the image is
appropriately scaled before being drawn and a susbsequent options.skipAutoScale if a
library user wishes to turn this default functionality off.

Co-authored-by: Darren Impey <dh118592@dunnhumby.com>
  • Loading branch information
Daz2345 and Darren Impey authored Oct 9, 2021
1 parent dfe1707 commit 1ee2e7f
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,14 @@ html2Image.toSVG(element1, { fontEmbedCss });
html2Image.toSVG(element2, { fontEmbedCss });
```

### skipAutoScale

When supplied, the library will skip the process of scaling extra large doms into the canvas object.
You may experience loss of parts of the image if set to `true` and you are exporting a very large image.

Defaults to `false`


## Browsers

Only standard lib is currently used, but make sure your browser supports:
Expand Down
27 changes: 27 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ export async function toSvg<T extends HTMLElement>(
.then((clonedNode) => nodeToDataURL(clonedNode, width, height))
}

const dimensionCanvasLimit = 16384; // as per https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size

function checkCanvasDimensions(canvas: HTMLCanvasElement) {
if (canvas.width > dimensionCanvasLimit || canvas.height > dimensionCanvasLimit) {
if (canvas.width > dimensionCanvasLimit && canvas.height > dimensionCanvasLimit) {
if (canvas.width > canvas.height) {
canvas.height = canvas.height * (dimensionCanvasLimit / canvas.width);
canvas.width = dimensionCanvasLimit;
} else {
canvas.width = canvas.width * (dimensionCanvasLimit / canvas.height);
canvas.height = dimensionCanvasLimit;
}
} else {
if (canvas.width > dimensionCanvasLimit) {
canvas.height = canvas.height * (dimensionCanvasLimit / canvas.width);
canvas.width = dimensionCanvasLimit;
} else {
canvas.width = canvas.width * (dimensionCanvasLimit / canvas.height);
canvas.height = dimensionCanvasLimit;
}
}
}
}
export async function toCanvas<T extends HTMLElement>(
node: T,
options: Options = {},
Expand All @@ -51,6 +74,10 @@ export async function toCanvas<T extends HTMLElement>(

canvas.width = canvasWidth * ratio
canvas.height = canvasHeight * ratio

if(!options.skipAutoScale) {
checkCanvasDimensions(canvas);
}
canvas.style.width = `${canvasWidth}`
canvas.style.height = `${canvasHeight}`

Expand Down
4 changes: 4 additions & 0 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ export interface Options {
* create embed CSS for use across multiple calls to library functions.
*/
fontEmbedCSS?: string
/**
* A boolean to turn off auto scaling for truly massive images..
*/
skipAutoScale?: boolean
}

0 comments on commit 1ee2e7f

Please sign in to comment.