html2canvas-pro 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/html2canvas-pro.esm.js +21 -7
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +21 -7
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +3 -3
- package/dist/lib/core/cache-storage.js +2 -2
- package/dist/lib/core/features.js +2 -2
- package/dist/lib/render/canvas/background-renderer.js +6 -0
- package/dist/lib/render/canvas/canvas-renderer.js +5 -1
- package/dist/lib/render/canvas/foreignobject-renderer.js +5 -1
- package/package.json +3 -11
- package/dist/lib/invariant.js +0 -9
- package/dist/types/invariant.d.ts +0 -1
- package/src/__tests__/index.ts +0 -99
- package/src/config.ts +0 -107
- package/src/core/__mocks__/cache-storage.ts +0 -1
- package/src/core/__mocks__/context.ts +0 -19
- package/src/core/__mocks__/features.ts +0 -8
- package/src/core/__mocks__/logger.ts +0 -17
- package/src/core/__tests__/cache-storage.test.ts +0 -205
- package/src/core/__tests__/cache-storage.ts +0 -278
- package/src/core/__tests__/logger.ts +0 -29
- package/src/core/__tests__/validator.ts +0 -359
- package/src/core/bitwise.ts +0 -1
- package/src/core/cache-storage.ts +0 -315
- package/src/core/context.ts +0 -31
- package/src/core/debugger.ts +0 -32
- package/src/core/features.ts +0 -222
- package/src/core/logger.ts +0 -64
- package/src/core/origin-checker.ts +0 -57
- package/src/core/performance-monitor.ts +0 -241
- package/src/core/render-element.ts +0 -272
- package/src/core/util.ts +0 -1
- package/src/core/validator.ts +0 -593
- package/src/css/index.ts +0 -427
- package/src/css/layout/__mocks__/bounds.ts +0 -6
- package/src/css/layout/bounds.ts +0 -79
- package/src/css/layout/text.ts +0 -161
- package/src/css/property-descriptor.ts +0 -49
- package/src/css/property-descriptors/__tests__/background-tests.ts +0 -65
- package/src/css/property-descriptors/__tests__/clip-path.test.ts +0 -280
- package/src/css/property-descriptors/__tests__/font-family.ts +0 -25
- package/src/css/property-descriptors/__tests__/image-rendering-integration.test.ts +0 -153
- package/src/css/property-descriptors/__tests__/image-rendering-performance.test.ts +0 -175
- package/src/css/property-descriptors/__tests__/image-rendering.test.ts +0 -72
- package/src/css/property-descriptors/__tests__/paint-order.ts +0 -87
- package/src/css/property-descriptors/__tests__/text-shadow.ts +0 -94
- package/src/css/property-descriptors/__tests__/transform-tests.ts +0 -18
- package/src/css/property-descriptors/background-clip.ts +0 -30
- package/src/css/property-descriptors/background-color.ts +0 -9
- package/src/css/property-descriptors/background-image.ts +0 -27
- package/src/css/property-descriptors/background-origin.ts +0 -31
- package/src/css/property-descriptors/background-position.ts +0 -38
- package/src/css/property-descriptors/background-repeat.ts +0 -44
- package/src/css/property-descriptors/background-size.ts +0 -27
- package/src/css/property-descriptors/border-color.ts +0 -13
- package/src/css/property-descriptors/border-radius.ts +0 -19
- package/src/css/property-descriptors/border-style.ts +0 -34
- package/src/css/property-descriptors/border-width.ts +0 -20
- package/src/css/property-descriptors/box-shadow.ts +0 -60
- package/src/css/property-descriptors/clip-path.ts +0 -271
- package/src/css/property-descriptors/color.ts +0 -9
- package/src/css/property-descriptors/content.ts +0 -26
- package/src/css/property-descriptors/counter-increment.ts +0 -43
- package/src/css/property-descriptors/counter-reset.ts +0 -36
- package/src/css/property-descriptors/direction.ts +0 -23
- package/src/css/property-descriptors/display.ts +0 -117
- package/src/css/property-descriptors/duration.ts +0 -14
- package/src/css/property-descriptors/float.ts +0 -29
- package/src/css/property-descriptors/font-family.ts +0 -38
- package/src/css/property-descriptors/font-size.ts +0 -9
- package/src/css/property-descriptors/font-style.ts +0 -25
- package/src/css/property-descriptors/font-variant.ts +0 -12
- package/src/css/property-descriptors/font-weight.ts +0 -26
- package/src/css/property-descriptors/image-rendering.ts +0 -33
- package/src/css/property-descriptors/letter-spacing.ts +0 -25
- package/src/css/property-descriptors/line-break.ts +0 -22
- package/src/css/property-descriptors/line-height.ts +0 -22
- package/src/css/property-descriptors/list-style-image.ts +0 -19
- package/src/css/property-descriptors/list-style-position.ts +0 -22
- package/src/css/property-descriptors/list-style-type.ts +0 -179
- package/src/css/property-descriptors/margin.ts +0 -13
- package/src/css/property-descriptors/mix-blend-mode.ts +0 -35
- package/src/css/property-descriptors/object-fit.ts +0 -39
- package/src/css/property-descriptors/opacity.ts +0 -15
- package/src/css/property-descriptors/overflow-wrap.ts +0 -22
- package/src/css/property-descriptors/overflow.ts +0 -34
- package/src/css/property-descriptors/padding.ts +0 -14
- package/src/css/property-descriptors/paint-order.ts +0 -42
- package/src/css/property-descriptors/position.ts +0 -30
- package/src/css/property-descriptors/quotes.ts +0 -57
- package/src/css/property-descriptors/rotate.ts +0 -34
- package/src/css/property-descriptors/text-align.ts +0 -26
- package/src/css/property-descriptors/text-decoration-color.ts +0 -9
- package/src/css/property-descriptors/text-decoration-line.ts +0 -38
- package/src/css/property-descriptors/text-decoration-style.ts +0 -32
- package/src/css/property-descriptors/text-decoration-thickness.ts +0 -30
- package/src/css/property-descriptors/text-overflow.ts +0 -23
- package/src/css/property-descriptors/text-shadow.ts +0 -52
- package/src/css/property-descriptors/text-transform.ts +0 -27
- package/src/css/property-descriptors/text-underline-offset.ts +0 -27
- package/src/css/property-descriptors/transform-origin.ts +0 -29
- package/src/css/property-descriptors/transform.ts +0 -74
- package/src/css/property-descriptors/visibility.ts +0 -25
- package/src/css/property-descriptors/webkit-line-clamp.ts +0 -30
- package/src/css/property-descriptors/webkit-text-stroke-color.ts +0 -8
- package/src/css/property-descriptors/webkit-text-stroke-width.ts +0 -15
- package/src/css/property-descriptors/word-break.ts +0 -25
- package/src/css/property-descriptors/writing-mode.ts +0 -37
- package/src/css/property-descriptors/z-index.ts +0 -27
- package/src/css/syntax/__tests__/tokernizer-tests.ts +0 -29
- package/src/css/syntax/parser.ts +0 -188
- package/src/css/syntax/tokenizer.ts +0 -822
- package/src/css/type-descriptor.ts +0 -7
- package/src/css/types/__tests__/color-tests.ts +0 -147
- package/src/css/types/__tests__/image-tests.ts +0 -239
- package/src/css/types/angle.ts +0 -86
- package/src/css/types/color-math.ts +0 -22
- package/src/css/types/color-spaces/a98.ts +0 -86
- package/src/css/types/color-spaces/p3.ts +0 -92
- package/src/css/types/color-spaces/pro-photo.ts +0 -87
- package/src/css/types/color-spaces/rec2020.ts +0 -90
- package/src/css/types/color-spaces/srgb.ts +0 -87
- package/src/css/types/color-utilities.ts +0 -452
- package/src/css/types/color.ts +0 -485
- package/src/css/types/functions/-prefix-linear-gradient.ts +0 -35
- package/src/css/types/functions/-prefix-radial-gradient.ts +0 -106
- package/src/css/types/functions/-webkit-gradient.ts +0 -69
- package/src/css/types/functions/__tests__/radial-gradient.ts +0 -69
- package/src/css/types/functions/counter.ts +0 -511
- package/src/css/types/functions/gradient.ts +0 -206
- package/src/css/types/functions/linear-gradient.ts +0 -28
- package/src/css/types/functions/radial-gradient.ts +0 -101
- package/src/css/types/image.ts +0 -120
- package/src/css/types/index.ts +0 -1
- package/src/css/types/length-percentage.ts +0 -137
- package/src/css/types/length.ts +0 -7
- package/src/css/types/time.ts +0 -20
- package/src/dom/__mocks__/document-cloner.ts +0 -22
- package/src/dom/__tests__/dom-normalizer.test.ts +0 -133
- package/src/dom/__tests__/element-container.test.ts +0 -129
- package/src/dom/document-cloner.ts +0 -929
- package/src/dom/dom-normalizer.ts +0 -133
- package/src/dom/element-container.ts +0 -75
- package/src/dom/elements/li-element-container.ts +0 -10
- package/src/dom/elements/ol-element-container.ts +0 -12
- package/src/dom/elements/select-element-container.ts +0 -10
- package/src/dom/elements/textarea-element-container.ts +0 -9
- package/src/dom/node-parser.ts +0 -177
- package/src/dom/node-type-guards.ts +0 -70
- package/src/dom/replaced-elements/canvas-element-container.ts +0 -15
- package/src/dom/replaced-elements/iframe-element-container.ts +0 -55
- package/src/dom/replaced-elements/image-element-container.ts +0 -16
- package/src/dom/replaced-elements/index.ts +0 -5
- package/src/dom/replaced-elements/input-element-container.ts +0 -105
- package/src/dom/replaced-elements/pseudo-elements.ts +0 -0
- package/src/dom/replaced-elements/svg-element-container.ts +0 -23
- package/src/dom/text-container.ts +0 -42
- package/src/global.d.ts +0 -19
- package/src/index.ts +0 -82
- package/src/invariant.ts +0 -5
- package/src/options.ts +0 -55
- package/src/render/__tests__/object-fit.test.ts +0 -85
- package/src/render/background.ts +0 -298
- package/src/render/bezier-curve.ts +0 -47
- package/src/render/border.ts +0 -165
- package/src/render/bound-curves.ts +0 -388
- package/src/render/box-sizing.ts +0 -31
- package/src/render/canvas/__tests__/background-renderer.test.ts +0 -72
- package/src/render/canvas/__tests__/border-renderer.test.ts +0 -24
- package/src/render/canvas/__tests__/effects-renderer.test.ts +0 -32
- package/src/render/canvas/__tests__/text-renderer.test.ts +0 -471
- package/src/render/canvas/background-renderer.ts +0 -271
- package/src/render/canvas/border-renderer.ts +0 -224
- package/src/render/canvas/canvas-path.ts +0 -31
- package/src/render/canvas/canvas-renderer.ts +0 -641
- package/src/render/canvas/effects-renderer.ts +0 -130
- package/src/render/canvas/foreignobject-renderer.ts +0 -53
- package/src/render/canvas/text-renderer.ts +0 -700
- package/src/render/effects.ts +0 -75
- package/src/render/font-metrics.ts +0 -72
- package/src/render/object-fit.ts +0 -100
- package/src/render/path.ts +0 -37
- package/src/render/renderer-interface.ts +0 -28
- package/src/render/stacking-context.ts +0 -386
- package/src/render/vector.ts +0 -19
|
@@ -245,5 +245,5 @@ const INLINE_IMG = /^data:image\/.*/i;
|
|
|
245
245
|
const isRenderable = (src) => features_1.FEATURES.SUPPORT_SVG_DRAWING || !isSVG(src);
|
|
246
246
|
const isInlineImage = (src) => INLINE_IMG.test(src);
|
|
247
247
|
const isInlineBase64Image = (src) => INLINE_BASE64.test(src);
|
|
248
|
-
const isBlobImage = (src) => src.
|
|
249
|
-
const isSVG = (src) => src.
|
|
248
|
+
const isBlobImage = (src) => src.substring(0, 4) === 'blob';
|
|
249
|
+
const isSVG = (src) => src.slice(-3).toLowerCase() === 'svg' || INLINE_SVG.test(src);
|
|
@@ -79,7 +79,7 @@ const testForeignObject = (document) => {
|
|
|
79
79
|
canvas.height = size;
|
|
80
80
|
const ctx = canvas.getContext('2d');
|
|
81
81
|
if (!ctx) {
|
|
82
|
-
return Promise.reject(
|
|
82
|
+
return Promise.reject(new Error('Failed to get 2D rendering context'));
|
|
83
83
|
}
|
|
84
84
|
ctx.fillStyle = 'rgb(0, 255, 0)';
|
|
85
85
|
ctx.fillRect(0, 0, size, size);
|
|
@@ -101,7 +101,7 @@ const testForeignObject = (document) => {
|
|
|
101
101
|
// Firefox 55 does not render inline <img /> tags
|
|
102
102
|
return isGreenPixel(data)
|
|
103
103
|
? (0, exports.loadSerializedSVG)((0, exports.createForeignObjectSVG)(size, size, 0, 0, node))
|
|
104
|
-
: Promise.reject(
|
|
104
|
+
: Promise.reject(new Error('ForeignObject rendering not supported'));
|
|
105
105
|
})
|
|
106
106
|
.then((img) => {
|
|
107
107
|
ctx.drawImage(img, 0, 0);
|
|
@@ -87,6 +87,9 @@ class BackgroundRenderer {
|
|
|
87
87
|
canvas.width = width;
|
|
88
88
|
canvas.height = height;
|
|
89
89
|
const ctx = canvas.getContext('2d');
|
|
90
|
+
if (!ctx) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
90
93
|
const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
|
|
91
94
|
(0, gradient_1.processColorStops)(backgroundImage.stops, lineLength || 1).forEach((colorStop) => gradient.addColorStop(colorStop.stop, (0, color_utilities_1.asString)(colorStop.color)));
|
|
92
95
|
ctx.fillStyle = gradient;
|
|
@@ -168,6 +171,9 @@ class BackgroundRenderer {
|
|
|
168
171
|
canvas.width = Math.max(1, width);
|
|
169
172
|
canvas.height = Math.max(1, height);
|
|
170
173
|
const ctx = canvas.getContext('2d');
|
|
174
|
+
if (!ctx) {
|
|
175
|
+
return image;
|
|
176
|
+
}
|
|
171
177
|
// Apply image smoothing based on CSS image-rendering property
|
|
172
178
|
if (imageRendering === image_rendering_1.IMAGE_RENDERING.PIXELATED || imageRendering === image_rendering_1.IMAGE_RENDERING.CRISP_EDGES) {
|
|
173
179
|
this.context.logger.debug(`Disabling image smoothing for background image due to CSS image-rendering`);
|
|
@@ -34,7 +34,11 @@ class CanvasRenderer {
|
|
|
34
34
|
this.context = context;
|
|
35
35
|
this.options = options;
|
|
36
36
|
this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
|
|
37
|
-
|
|
37
|
+
const ctx = this.canvas.getContext('2d');
|
|
38
|
+
if (!ctx) {
|
|
39
|
+
throw new Error('Failed to get 2D rendering context from canvas');
|
|
40
|
+
}
|
|
41
|
+
this.ctx = ctx;
|
|
38
42
|
if (!options.canvas) {
|
|
39
43
|
this.canvas.width = Math.floor(options.width * options.scale);
|
|
40
44
|
this.canvas.height = Math.floor(options.height * options.scale);
|
|
@@ -8,7 +8,11 @@ class ForeignObjectRenderer {
|
|
|
8
8
|
this.context = context;
|
|
9
9
|
this.options = options;
|
|
10
10
|
this.canvas = options.canvas ? options.canvas : document.createElement('canvas');
|
|
11
|
-
|
|
11
|
+
const ctx = this.canvas.getContext('2d');
|
|
12
|
+
if (!ctx) {
|
|
13
|
+
throw new Error('Failed to get 2D rendering context from canvas');
|
|
14
|
+
}
|
|
15
|
+
this.ctx = ctx;
|
|
12
16
|
this.canvas.width = Math.floor(options.width * options.scale);
|
|
13
17
|
this.canvas.height = Math.floor(options.height * options.scale);
|
|
14
18
|
this.canvas.style.width = `${options.width}px`;
|
package/package.json
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
"sideEffects": false,
|
|
10
10
|
"files": [
|
|
11
11
|
"dist/",
|
|
12
|
-
"src/",
|
|
13
12
|
"LICENSE"
|
|
14
13
|
],
|
|
15
14
|
"exports": {
|
|
@@ -20,7 +19,7 @@
|
|
|
20
19
|
"default": "./dist/html2canvas-pro.esm.js"
|
|
21
20
|
}
|
|
22
21
|
},
|
|
23
|
-
"version": "2.1.
|
|
22
|
+
"version": "2.1.1",
|
|
24
23
|
"author": {
|
|
25
24
|
"name": "yorickshan",
|
|
26
25
|
"email": "yorickshan@gmail.com",
|
|
@@ -48,14 +47,11 @@
|
|
|
48
47
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
49
48
|
"@types/chai": "^5.2.3",
|
|
50
49
|
"@types/express": "^5.0.6",
|
|
51
|
-
"@types/filenamify-url": "^2.0.1",
|
|
52
|
-
"@types/glob": "^9.0.0",
|
|
53
50
|
"@types/karma": "^6.3.0",
|
|
54
51
|
"@types/mocha": "^10.0.7",
|
|
55
52
|
"@types/node": "^25.0.3",
|
|
56
53
|
"@types/platform": "^1.3.4",
|
|
57
54
|
"@types/pngjs": "^6.0.5",
|
|
58
|
-
"@types/promise-polyfill": "^6.0.3",
|
|
59
55
|
"@types/serve-index": "^1.9.4",
|
|
60
56
|
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
61
57
|
"@typescript-eslint/parser": "^8.50.0",
|
|
@@ -65,10 +61,10 @@
|
|
|
65
61
|
"body-parser": "^2.2.1",
|
|
66
62
|
"chai": "6.2.2",
|
|
67
63
|
"change-case": "^5.4.4",
|
|
68
|
-
"conventional-changelog
|
|
64
|
+
"conventional-changelog": "^7.2.1",
|
|
65
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
69
66
|
"cors": "^2.8.5",
|
|
70
67
|
"cz-conventional-changelog": "^3.3.0",
|
|
71
|
-
"es6-promise": "^4.2.8",
|
|
72
68
|
"eslint": "^9.13.0",
|
|
73
69
|
"eslint-config-prettier": "^10.1.8",
|
|
74
70
|
"eslint-plugin-prettier": "^5.5.4",
|
|
@@ -76,8 +72,6 @@
|
|
|
76
72
|
"filenamify-url": "4.0.0",
|
|
77
73
|
"glob": "^13.0.0",
|
|
78
74
|
"husky": "^9.1.7",
|
|
79
|
-
"jquery": "^3.5.1",
|
|
80
|
-
"js-polyfills": "^0.1.42",
|
|
81
75
|
"jsdom": "^29.1.1",
|
|
82
76
|
"karma": "^6.3.2",
|
|
83
77
|
"karma-chrome-launcher": "^3.1.0",
|
|
@@ -101,7 +95,6 @@
|
|
|
101
95
|
"rollup-plugin-sourcemaps": "^0.6.3",
|
|
102
96
|
"serve-index": "^1.9.1",
|
|
103
97
|
"slash": "5.1.0",
|
|
104
|
-
"standard-version": "^9.5.0",
|
|
105
98
|
"ts-node": "^10.9.2",
|
|
106
99
|
"tsx": "^4.22.3",
|
|
107
100
|
"typedoc": "^0.28.19",
|
|
@@ -142,7 +135,6 @@
|
|
|
142
135
|
"watch:unittest": "vitest",
|
|
143
136
|
"start": "tsx tests/server --port=8080 --cors=8081",
|
|
144
137
|
"commitlint": "commitlint --config .commitlintrc.json -e -V",
|
|
145
|
-
"tag": "sh scripts/create-tag.sh",
|
|
146
138
|
"docs:dev": "vitepress dev docs",
|
|
147
139
|
"docs:build": "vitepress build docs",
|
|
148
140
|
"docs:preview": "vitepress preview docs",
|
package/dist/lib/invariant.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const invariant: (assertion: boolean, error: string) => void;
|
package/src/__tests__/index.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import html2canvas from '../index';
|
|
2
|
-
|
|
3
|
-
import { CanvasRenderer } from '../render/canvas/canvas-renderer';
|
|
4
|
-
import { DocumentCloner } from '../dom/document-cloner';
|
|
5
|
-
import { COLORS } from '../css/types/color';
|
|
6
|
-
|
|
7
|
-
vi.mock('../core/logger');
|
|
8
|
-
vi.mock('../css/layout/bounds');
|
|
9
|
-
vi.mock('../dom/document-cloner');
|
|
10
|
-
vi.mock('../dom/node-parser', () => {
|
|
11
|
-
return {
|
|
12
|
-
isBodyElement: () => false,
|
|
13
|
-
isHTMLElement: () => false,
|
|
14
|
-
parseTree: vi.fn().mockImplementation(() => {
|
|
15
|
-
return { styles: {}, restoreTree: vi.fn() };
|
|
16
|
-
})
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
vi.mock('../render/stacking-context');
|
|
21
|
-
vi.mock('../render/canvas/canvas-renderer');
|
|
22
|
-
|
|
23
|
-
describe('html2canvas', () => {
|
|
24
|
-
const element = {
|
|
25
|
-
ownerDocument: {
|
|
26
|
-
defaultView: {
|
|
27
|
-
document: {
|
|
28
|
-
createElement: () => ({ href: '' })
|
|
29
|
-
},
|
|
30
|
-
location: { href: 'http://localhost/' },
|
|
31
|
-
pageXOffset: 12,
|
|
32
|
-
pageYOffset: 34,
|
|
33
|
-
innerWidth: 800,
|
|
34
|
-
innerHeight: 600
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
} as unknown as HTMLElement;
|
|
38
|
-
|
|
39
|
-
it('should render with an element', async () => {
|
|
40
|
-
DocumentCloner.destroy = vi.fn().mockReturnValue(true);
|
|
41
|
-
await html2canvas(element);
|
|
42
|
-
expect(CanvasRenderer).toHaveBeenLastCalledWith(
|
|
43
|
-
expect.objectContaining({
|
|
44
|
-
cache: expect.any(Object),
|
|
45
|
-
logger: expect.any(Object),
|
|
46
|
-
windowBounds: expect.objectContaining({ left: 12, top: 34 })
|
|
47
|
-
}),
|
|
48
|
-
expect.objectContaining({
|
|
49
|
-
backgroundColor: 0xffffffff,
|
|
50
|
-
scale: 1,
|
|
51
|
-
height: 50,
|
|
52
|
-
width: 200,
|
|
53
|
-
x: 0,
|
|
54
|
-
y: 0,
|
|
55
|
-
canvas: undefined
|
|
56
|
-
})
|
|
57
|
-
);
|
|
58
|
-
expect(DocumentCloner.destroy).toBeCalled();
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should have transparent background with backgroundColor: null', async () => {
|
|
62
|
-
await html2canvas(element, { backgroundColor: null });
|
|
63
|
-
expect(CanvasRenderer).toHaveBeenLastCalledWith(
|
|
64
|
-
expect.anything(),
|
|
65
|
-
expect.objectContaining({
|
|
66
|
-
backgroundColor: COLORS.TRANSPARENT
|
|
67
|
-
})
|
|
68
|
-
);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should use existing canvas when given as option', async () => {
|
|
72
|
-
const canvas = {} as HTMLCanvasElement;
|
|
73
|
-
await html2canvas(element, { canvas });
|
|
74
|
-
expect(CanvasRenderer).toHaveBeenLastCalledWith(
|
|
75
|
-
expect.anything(),
|
|
76
|
-
expect.objectContaining({
|
|
77
|
-
canvas
|
|
78
|
-
})
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should not remove cloned window when removeContainer: false', async () => {
|
|
83
|
-
DocumentCloner.destroy = vi.fn();
|
|
84
|
-
await html2canvas(element, { removeContainer: false });
|
|
85
|
-
expect(CanvasRenderer).toHaveBeenLastCalledWith(
|
|
86
|
-
expect.anything(),
|
|
87
|
-
expect.objectContaining({
|
|
88
|
-
backgroundColor: 0xffffffff,
|
|
89
|
-
scale: 1,
|
|
90
|
-
height: 50,
|
|
91
|
-
width: 200,
|
|
92
|
-
x: 0,
|
|
93
|
-
y: 0,
|
|
94
|
-
canvas: undefined
|
|
95
|
-
})
|
|
96
|
-
);
|
|
97
|
-
expect(DocumentCloner.destroy).not.toBeCalled();
|
|
98
|
-
});
|
|
99
|
-
});
|
package/src/config.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { Cache } from './core/cache-storage';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configuration options for Html2Canvas
|
|
5
|
-
*
|
|
6
|
-
* This class manages global configuration without using module-level static variables.
|
|
7
|
-
* Each html2canvas invocation can have its own configuration instance.
|
|
8
|
-
*/
|
|
9
|
-
export interface ConfigOptions {
|
|
10
|
-
/**
|
|
11
|
-
* Window object to use for DOM operations
|
|
12
|
-
*/
|
|
13
|
-
window?: Window;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* CSP nonce for inline styles
|
|
17
|
-
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
|
|
18
|
-
*/
|
|
19
|
-
cspNonce?: string;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Cache instance to reuse across multiple calls
|
|
23
|
-
* Useful for avoiding redundant image loads
|
|
24
|
-
*/
|
|
25
|
-
cache?: Cache;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Html2Canvas Configuration
|
|
30
|
-
*
|
|
31
|
-
* Manages configuration state for html2canvas rendering.
|
|
32
|
-
* Eliminates the need for global static variables.
|
|
33
|
-
*/
|
|
34
|
-
export class Html2CanvasConfig {
|
|
35
|
-
readonly window: Window;
|
|
36
|
-
readonly cspNonce?: string;
|
|
37
|
-
readonly cache?: Cache;
|
|
38
|
-
|
|
39
|
-
constructor(options: ConfigOptions = {}) {
|
|
40
|
-
const resolvedWindow = options.window || (typeof window !== 'undefined' ? window : undefined);
|
|
41
|
-
|
|
42
|
-
if (!resolvedWindow) {
|
|
43
|
-
throw new Error('Window object is required but not available');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.window = resolvedWindow;
|
|
47
|
-
this.cspNonce = options.cspNonce;
|
|
48
|
-
this.cache = options.cache;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Create configuration from an element
|
|
53
|
-
* Extracts window from element's owner document
|
|
54
|
-
*/
|
|
55
|
-
static fromElement(element: HTMLElement, options: Partial<ConfigOptions> = {}): Html2CanvasConfig {
|
|
56
|
-
const ownerDocument = element.ownerDocument;
|
|
57
|
-
|
|
58
|
-
if (!ownerDocument) {
|
|
59
|
-
throw new Error('Element is not attached to a document');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const defaultView = ownerDocument.defaultView;
|
|
63
|
-
|
|
64
|
-
if (!defaultView) {
|
|
65
|
-
throw new Error('Document is not attached to a window');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return new Html2CanvasConfig({
|
|
69
|
-
window: defaultView,
|
|
70
|
-
...options
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Clone configuration with override options
|
|
76
|
-
*/
|
|
77
|
-
clone(options: Partial<ConfigOptions> = {}): Html2CanvasConfig {
|
|
78
|
-
return new Html2CanvasConfig({
|
|
79
|
-
window: options.window || this.window,
|
|
80
|
-
cspNonce: options.cspNonce ?? this.cspNonce,
|
|
81
|
-
cache: options.cache ?? this.cache
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Default global configuration (for backward compatibility)
|
|
88
|
-
* @deprecated Use Html2CanvasConfig instances instead
|
|
89
|
-
*/
|
|
90
|
-
let _defaultConfig: Html2CanvasConfig | null = null;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Set default configuration
|
|
94
|
-
* @deprecated Pass configuration directly to html2canvas instead
|
|
95
|
-
*/
|
|
96
|
-
export function setDefaultConfig(config: Html2CanvasConfig): void {
|
|
97
|
-
console.warn('[html2canvas-pro] setDefaultConfig is deprecated. Pass configuration to html2canvas directly.');
|
|
98
|
-
_defaultConfig = config;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Get default configuration
|
|
103
|
-
* @deprecated Pass configuration directly to html2canvas instead
|
|
104
|
-
*/
|
|
105
|
-
export function getDefaultConfig(): Html2CanvasConfig | null {
|
|
106
|
-
return _defaultConfig;
|
|
107
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class CacheStorage {}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { logger, Logger } from './logger';
|
|
2
|
-
|
|
3
|
-
export class Context {
|
|
4
|
-
readonly logger: Logger = logger;
|
|
5
|
-
|
|
6
|
-
readonly _cache: { [key: string]: Promise<any> } = {};
|
|
7
|
-
|
|
8
|
-
readonly cache: any;
|
|
9
|
-
|
|
10
|
-
constructor() {
|
|
11
|
-
this.cache = {
|
|
12
|
-
addImage: vi.fn().mockImplementation((src: string): Promise<void> => {
|
|
13
|
-
const result = Promise.resolve();
|
|
14
|
-
this._cache[src] = result;
|
|
15
|
-
return result;
|
|
16
|
-
})
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export class Logger {
|
|
2
|
-
debug(): void {}
|
|
3
|
-
|
|
4
|
-
static create(): void {}
|
|
5
|
-
|
|
6
|
-
static destroy(): void {}
|
|
7
|
-
|
|
8
|
-
static getInstance(): Logger {
|
|
9
|
-
return logger;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
info(): void {}
|
|
13
|
-
|
|
14
|
-
error(): void {}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const logger = new Logger();
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { strictEqual, ok, deepStrictEqual } from 'assert';
|
|
2
|
-
import { Cache, ResourceOptions } from '../cache-storage';
|
|
3
|
-
import { Context } from '../context';
|
|
4
|
-
import { Bounds } from '../../css/layout/bounds';
|
|
5
|
-
import { Html2CanvasConfig } from '../../config';
|
|
6
|
-
|
|
7
|
-
describe('Cache LRU', () => {
|
|
8
|
-
let context: Context;
|
|
9
|
-
let cache: Cache;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
const mockWindow = {
|
|
13
|
-
document: {
|
|
14
|
-
createElement: (_name: string) => {
|
|
15
|
-
let _href = '';
|
|
16
|
-
return {
|
|
17
|
-
set href(value: string) {
|
|
18
|
-
_href = value;
|
|
19
|
-
},
|
|
20
|
-
get href() {
|
|
21
|
-
return _href;
|
|
22
|
-
},
|
|
23
|
-
get protocol() {
|
|
24
|
-
return 'http:';
|
|
25
|
-
},
|
|
26
|
-
get hostname() {
|
|
27
|
-
return 'localhost';
|
|
28
|
-
},
|
|
29
|
-
get port() {
|
|
30
|
-
return '';
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
location: { href: 'http://localhost/' }
|
|
36
|
-
} as unknown as Window;
|
|
37
|
-
|
|
38
|
-
const config = new Html2CanvasConfig({ window: mockWindow });
|
|
39
|
-
context = new Context(
|
|
40
|
-
{
|
|
41
|
-
logging: false,
|
|
42
|
-
imageTimeout: 15000,
|
|
43
|
-
useCORS: false,
|
|
44
|
-
allowTaint: false
|
|
45
|
-
},
|
|
46
|
-
new Bounds(0, 0, 800, 600),
|
|
47
|
-
config
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
const options: ResourceOptions = {
|
|
51
|
-
imageTimeout: 15000,
|
|
52
|
-
useCORS: false,
|
|
53
|
-
allowTaint: false,
|
|
54
|
-
maxCacheSize: 3 // Small size for testing
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
cache = new Cache(context, options);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should enforce maximum cache size', () => {
|
|
61
|
-
strictEqual(cache.getMaxSize(), 3);
|
|
62
|
-
strictEqual(cache.size(), 0);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should add images to cache', () => {
|
|
66
|
-
const blob1 = 'blob:http://localhost/image1';
|
|
67
|
-
const blob2 = 'blob:http://localhost/image2';
|
|
68
|
-
|
|
69
|
-
cache.addImage(blob1);
|
|
70
|
-
strictEqual(cache.size(), 1);
|
|
71
|
-
|
|
72
|
-
cache.addImage(blob2);
|
|
73
|
-
strictEqual(cache.size(), 2);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should not exceed max cache size', () => {
|
|
77
|
-
const blobs = [
|
|
78
|
-
'blob:http://localhost/image1',
|
|
79
|
-
'blob:http://localhost/image2',
|
|
80
|
-
'blob:http://localhost/image3',
|
|
81
|
-
'blob:http://localhost/image4' // This should trigger eviction
|
|
82
|
-
];
|
|
83
|
-
|
|
84
|
-
blobs.forEach((blob) => cache.addImage(blob));
|
|
85
|
-
|
|
86
|
-
// Should not exceed max size (3)
|
|
87
|
-
strictEqual(cache.size(), 3);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should evict least recently used entry when full', async () => {
|
|
91
|
-
const blob1 = 'blob:http://localhost/image1';
|
|
92
|
-
const blob2 = 'blob:http://localhost/image2';
|
|
93
|
-
const blob3 = 'blob:http://localhost/image3';
|
|
94
|
-
const blob4 = 'blob:http://localhost/image4';
|
|
95
|
-
|
|
96
|
-
// Add 3 images (fill cache)
|
|
97
|
-
cache.addImage(blob1);
|
|
98
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
99
|
-
|
|
100
|
-
cache.addImage(blob2);
|
|
101
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
102
|
-
|
|
103
|
-
cache.addImage(blob3);
|
|
104
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
105
|
-
|
|
106
|
-
strictEqual(cache.size(), 3);
|
|
107
|
-
|
|
108
|
-
// Access blob2 and blob3 (update their access time)
|
|
109
|
-
cache.match(blob2);
|
|
110
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
111
|
-
|
|
112
|
-
cache.match(blob3);
|
|
113
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
114
|
-
|
|
115
|
-
// Add blob4 - should evict blob1 (oldest, never accessed)
|
|
116
|
-
cache.addImage(blob4);
|
|
117
|
-
|
|
118
|
-
strictEqual(cache.size(), 3);
|
|
119
|
-
|
|
120
|
-
// blob1 should be evicted
|
|
121
|
-
strictEqual(cache.match(blob1), undefined);
|
|
122
|
-
|
|
123
|
-
// blob2, blob3, blob4 should exist
|
|
124
|
-
ok(cache.match(blob2) !== undefined);
|
|
125
|
-
ok(cache.match(blob3) !== undefined);
|
|
126
|
-
ok(cache.match(blob4) !== undefined);
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('should update access time on repeated access', async () => {
|
|
130
|
-
const blob1 = 'blob:http://localhost/image1';
|
|
131
|
-
const blob2 = 'blob:http://localhost/image2';
|
|
132
|
-
const blob3 = 'blob:http://localhost/image3';
|
|
133
|
-
|
|
134
|
-
cache.addImage(blob1);
|
|
135
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
136
|
-
|
|
137
|
-
cache.addImage(blob2);
|
|
138
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
139
|
-
|
|
140
|
-
cache.addImage(blob3);
|
|
141
|
-
strictEqual(cache.size(), 3);
|
|
142
|
-
|
|
143
|
-
// Access blob1 multiple times (update access time)
|
|
144
|
-
cache.match(blob1);
|
|
145
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
146
|
-
|
|
147
|
-
cache.addImage(blob1); // Should update access time
|
|
148
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
149
|
-
|
|
150
|
-
// Add 4th image - should evict blob2 (oldest unaccessed)
|
|
151
|
-
const blob4 = 'blob:http://localhost/image4';
|
|
152
|
-
cache.addImage(blob4);
|
|
153
|
-
|
|
154
|
-
strictEqual(cache.size(), 3);
|
|
155
|
-
strictEqual(cache.match(blob2), undefined); // Evicted
|
|
156
|
-
ok(cache.match(blob1) !== undefined); // Still exists
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should clear all cache entries', () => {
|
|
160
|
-
cache.addImage('blob:http://localhost/image1');
|
|
161
|
-
cache.addImage('blob:http://localhost/image2');
|
|
162
|
-
strictEqual(cache.size(), 2);
|
|
163
|
-
|
|
164
|
-
cache.clear();
|
|
165
|
-
strictEqual(cache.size(), 0);
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('should return cache keys', async () => {
|
|
169
|
-
const blob1 = 'blob:http://localhost/image1';
|
|
170
|
-
const blob2 = 'blob:http://localhost/image2';
|
|
171
|
-
|
|
172
|
-
cache.addImage(blob1);
|
|
173
|
-
cache.addImage(blob2);
|
|
174
|
-
|
|
175
|
-
deepStrictEqual(await cache.keys(), [blob1, blob2]);
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('should throw error for invalid max size', () => {
|
|
179
|
-
const options: ResourceOptions = {
|
|
180
|
-
imageTimeout: 15000,
|
|
181
|
-
useCORS: false,
|
|
182
|
-
allowTaint: false,
|
|
183
|
-
maxCacheSize: 0 // Invalid
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
new Cache(context, options);
|
|
188
|
-
ok(false, 'Should have thrown error');
|
|
189
|
-
} catch (error: any) {
|
|
190
|
-
ok(error.message.includes('at least 1'));
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should use default max size if not specified', () => {
|
|
195
|
-
const options: ResourceOptions = {
|
|
196
|
-
imageTimeout: 15000,
|
|
197
|
-
useCORS: false,
|
|
198
|
-
allowTaint: false
|
|
199
|
-
// maxCacheSize not specified
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
const cacheWithDefault = new Cache(context, options);
|
|
203
|
-
strictEqual(cacheWithDefault.getMaxSize(), 100); // Default
|
|
204
|
-
});
|
|
205
|
-
});
|