Compare commits

...

5 Commits

10 changed files with 142 additions and 66 deletions

View File

@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [1.4.1](https://github.com/niklasvh/html2canvas/compare/v1.4.0...v1.4.1) (2022-01-22)
### deps
* fix source maps (#2812) ([67c5e8d](https://github.com/niklasvh/html2canvas/commit/67c5e8dec4b2af9260a2b5b75b3399495fd1fee9)), closes [#2812](https://github.com/niklasvh/html2canvas/issues/2812)
### feat
* add support for <video> elements (#2788) ([181d1b1](https://github.com/niklasvh/html2canvas/commit/181d1b1103910d6e1b5277d5c007fc5e3006c6bf)), closes [#2788](https://github.com/niklasvh/html2canvas/issues/2788)
### fix
* Properties x and y of BoundingRect is undefined in old browser (#2797) ([e587a82](https://github.com/niklasvh/html2canvas/commit/e587a82dca01d9ada78cae34fd1bdb934e547f9b)), closes [#2797](https://github.com/niklasvh/html2canvas/issues/2797)
* source maps (#2787) ([46db867](https://github.com/niklasvh/html2canvas/commit/46db86755f064828559a4b0b37310f3ae94f5494)), closes [#2787](https://github.com/niklasvh/html2canvas/issues/2787)
# [1.4.0](https://github.com/niklasvh/html2canvas/compare/v1.3.4...v1.4.0) (2022-01-01)

90
package-lock.json generated
View File

@ -1,15 +1,15 @@
{
"name": "html2canvas",
"version": "1.4.0",
"version": "1.4.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "1.2.2",
"version": "1.4.0",
"license": "MIT",
"dependencies": {
"css-line-break": "2.0.1",
"text-segmentation": "^1.0.2"
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"devDependencies": {
"@babel/cli": "^7.4.3",
@ -5705,6 +5705,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz",
"integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==",
"dev": true,
"engines": {
"node": ">= 0.6.0"
}
@ -8465,19 +8466,11 @@
}
},
"node_modules/css-line-break": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.0.1.tgz",
"integrity": "sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"dependencies": {
"base64-arraybuffer": "^0.2.0"
}
},
"node_modules/css-line-break/node_modules/base64-arraybuffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==",
"engines": {
"node": ">= 0.6.0"
"utrie": "^1.0.2"
}
},
"node_modules/cssom": {
@ -22757,11 +22750,11 @@
}
},
"node_modules/text-segmentation": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.2.tgz",
"integrity": "sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"dependencies": {
"utrie": "^1.0.1"
"utrie": "^1.0.2"
}
},
"node_modules/text-table": {
@ -23805,11 +23798,19 @@
}
},
"node_modules/utrie": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.1.tgz",
"integrity": "sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"dependencies": {
"base64-arraybuffer": "^1.0.1"
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/utrie/node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/uuid": {
@ -29686,7 +29687,8 @@
"base64-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.1.tgz",
"integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA=="
"integrity": "sha512-vFIUq7FdLtjZMhATwDul5RZWv2jpXQ09Pd6jcVEOvIsqCWTRFD/ONHNfyOS8dA/Ippi5dsIgpyKWKZaAKZltbA==",
"dev": true
},
"base64-js": {
"version": "1.5.1",
@ -31950,18 +31952,11 @@
}
},
"css-line-break": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.0.1.tgz",
"integrity": "sha512-gwKYIMUn7xodIcb346wgUhE2Dt5O1Kmrc16PWi8sL4FTfyDj8P5095rzH7+O8CTZudJr+uw2GCI/hwEkDJFI2w==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"requires": {
"base64-arraybuffer": "^0.2.0"
},
"dependencies": {
"base64-arraybuffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
"integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ=="
}
"utrie": "^1.0.2"
}
},
"cssom": {
@ -43210,11 +43205,11 @@
"dev": true
},
"text-segmentation": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.2.tgz",
"integrity": "sha512-uTqvLxdBrVnx/CFQOtnf8tfzSXFm+1Qxau7Xi54j4OPTZokuDOX8qncQzrg2G8ZicAMOM8TgzFAYTb+AqNO4Cw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"requires": {
"utrie": "^1.0.1"
"utrie": "^1.0.2"
}
},
"text-table": {
@ -44011,11 +44006,18 @@
"dev": true
},
"utrie": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.1.tgz",
"integrity": "sha512-JPaDXF3vzgZxfeEwutdGzlrNoVFL5UvZcbO6Qo9D4GoahrieUPoMU8GCpVpR7MQqcKhmShIh8VlbEN3PLM3EBg==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"requires": {
"base64-arraybuffer": "^1.0.1"
"base64-arraybuffer": "^1.0.2"
},
"dependencies": {
"base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
}
}
},
"uuid": {

View File

@ -6,7 +6,7 @@
"module": "dist/html2canvas.esm.js",
"typings": "dist/types/index.d.ts",
"browser": "dist/html2canvas.js",
"version": "1.4.0",
"version": "1.4.1",
"author": {
"name": "Niklas von Hertzen",
"email": "niklasvh@gmail.com",
@ -118,7 +118,7 @@
"homepage": "https://html2canvas.hertzen.com",
"license": "MIT",
"dependencies": {
"css-line-break": "2.0.1",
"text-segmentation": "^1.0.2"
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
}
}

View File

@ -30,7 +30,7 @@ export default {
// Allow json resolution
json(),
// Compile TypeScript files
typescript(),
typescript({ sourceMap: true, inlineSources: true }),
// Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
commonjs({
include: 'node_modules/**'

View File

@ -20,8 +20,8 @@ export class Bounds {
const domRect = Array.from(domRectList).find((rect) => rect.width !== 0);
return domRect
? new Bounds(
domRect.x + context.windowBounds.left,
domRect.y + context.windowBounds.top,
domRect.left + context.windowBounds.left,
domRect.top + context.windowBounds.top,
domRect.width,
domRect.height
)

View File

@ -13,7 +13,8 @@ import {
isStyleElement,
isSVGElementNode,
isTextareaElement,
isTextNode
isTextNode,
isVideoElement
} from './node-parser';
import {isIdentToken, nonFunctionArgSeparator} from '../css/syntax/parser';
import {TokenType} from '../css/syntax/tokenizer';
@ -145,7 +146,9 @@ export class DocumentCloner {
if (isCanvasElement(node)) {
return this.createCanvasClone(node);
}
if (isVideoElement(node)) {
return this.createVideoClone(node);
}
if (isStyleElement(node)) {
return this.createStyleClone(node);
}
@ -244,6 +247,32 @@ export class DocumentCloner {
return clonedCanvas;
}
createVideoClone(video: HTMLVideoElement): HTMLCanvasElement {
const canvas = video.ownerDocument.createElement('canvas');
canvas.width = video.offsetWidth;
canvas.height = video.offsetHeight;
const ctx = canvas.getContext('2d');
try {
if (ctx) {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
if (!this.options.allowTaint) {
ctx.getImageData(0, 0, canvas.width, canvas.height);
}
}
return canvas;
} catch (e) {
this.context.logger.info(`Unable to clone video as it is tainted`, video);
}
const blankCanvas = video.ownerDocument.createElement('canvas');
blankCanvas.width = video.offsetWidth;
blankCanvas.height = video.offsetHeight;
return blankCanvas;
}
appendChildNode(clone: HTMLElement | SVGElement, child: Node, copyStyles: boolean): void {
if (
!isElementNode(child) ||
@ -257,6 +286,23 @@ export class DocumentCloner {
}
}
cloneChildNodes(node: Element, clone: HTMLElement | SVGElement, copyStyles: boolean): void {
for (
let child = node.shadowRoot ? node.shadowRoot.firstChild : node.firstChild;
child;
child = child.nextSibling
) {
if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === 'function') {
const assignedNodes = child.assignedNodes() as ChildNode[];
if (assignedNodes.length) {
assignedNodes.forEach((assignedNode) => this.appendChildNode(clone, assignedNode, copyStyles));
}
} else {
this.appendChildNode(clone, child, copyStyles);
}
}
}
cloneNode(node: Node, copyStyles: boolean): Node {
if (isTextNode(node)) {
return document.createTextNode(node.data);
@ -290,19 +336,8 @@ export class DocumentCloner {
copyStyles = true;
}
for (
let child = node.shadowRoot ? node.shadowRoot.firstChild : node.firstChild;
child;
child = child.nextSibling
) {
if (isElementNode(child) && isSlotElement(child) && typeof child.assignedNodes === 'function') {
const assignedNodes = child.assignedNodes() as ChildNode[];
if (assignedNodes.length) {
assignedNodes.forEach((assignedNode) => this.appendChildNode(clone, assignedNode, copyStyles));
}
} else {
this.appendChildNode(clone, child, copyStyles);
}
if (!isVideoElement(node)) {
this.cloneChildNodes(node, clone, copyStyles);
}
if (before) {

View File

@ -124,6 +124,7 @@ export const isHTMLElement = (node: Element): node is HTMLHtmlElement => node.ta
export const isSVGElement = (node: Element): node is SVGSVGElement => node.tagName === 'svg';
export const isBodyElement = (node: Element): node is HTMLBodyElement => node.tagName === 'BODY';
export const isCanvasElement = (node: Element): node is HTMLCanvasElement => node.tagName === 'CANVAS';
export const isVideoElement = (node: Element): node is HTMLVideoElement => node.tagName === 'VIDEO';
export const isImageElement = (node: Element): node is HTMLImageElement => node.tagName === 'IMG';
export const isIFrameElement = (node: Element): node is HTMLIFrameElement => node.tagName === 'IFRAME';
export const isStyleElement = (node: Element): node is HTMLStyleElement => node.tagName === 'STYLE';

BIN
tests/assets/cc0-video.mp4 Normal file

Binary file not shown.

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Video tests</title>
<script type="text/javascript" src="../../test.js"></script>
</head>
<body>
<h2>Same origin</h2>
<video controls width="250">
<source src="../../assets/cc0-video.mp4" type="video/mp4">
Sorry, your browser doesn't support embedded videos.
</video>
<h2>Cross-origin (doesn't taint)</h2>
<video controls width="250">
<source src="http://localhost:8081/cors/tests/assets/cc0-video.mp4" type="video/mp4">
Sorry, your browser doesn't support embedded videos.
</video>
</body>
</html>

View File

@ -12,7 +12,7 @@ const mkdirp = require('mkdirp');
export const app = express();
app.use('/', serveIndex(path.resolve(__dirname, '../'), {icons: true}));
app.use('/', express.static(path.resolve(__dirname, '../')));
app.use([/^\/src($|\/)/, '/'], express.static(path.resolve(__dirname, '../')));
export const corsApp = express();
corsApp.use('/proxy', proxy());