html2canvas-pro 2.6.0 → 2.6.2
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/README.md +7 -1
- package/dist/html2canvas-pro.cjs +739 -465
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +739 -465
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +739 -465
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +6 -6
- package/dist/types/core/performance-monitor.d.ts +5 -4
- package/dist/types/css/index.d.ts +4 -0
- package/dist/types/css/property-descriptors/contain.d.ts +7 -0
- package/dist/types/css/property-descriptors/will-change.d.ts +7 -0
- package/dist/types/dom/document-cloner.d.ts +7 -0
- package/dist/types/dom/element-container.d.ts +6 -0
- package/dist/types/dom/filter-reference.d.ts +35 -0
- package/dist/types/dom/pseudo-content.d.ts +2 -2
- package/dist/types/render/canvas/canvas-renderer.d.ts +15 -0
- package/dist/types/render/canvas/filter-surface.d.ts +21 -6
- package/dist/types/render/matrix.d.ts +43 -0
- package/package.json +19 -19
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Logger } from './logger';
|
|
2
2
|
/**
|
|
3
3
|
* Performance Metric
|
|
4
4
|
*
|
|
@@ -33,7 +33,8 @@ export interface PerformanceSummary {
|
|
|
33
33
|
*
|
|
34
34
|
* Usage:
|
|
35
35
|
* ```typescript
|
|
36
|
-
*
|
|
36
|
+
* // Standalone (logs disabled) or with the render pipeline's context.
|
|
37
|
+
* const monitor = new PerformanceMonitor(null);
|
|
37
38
|
*
|
|
38
39
|
* monitor.start('clone');
|
|
39
40
|
* await cloneDocument();
|
|
@@ -43,12 +44,12 @@ export interface PerformanceSummary {
|
|
|
43
44
|
* ```
|
|
44
45
|
*/
|
|
45
46
|
export declare class PerformanceMonitor {
|
|
46
|
-
private readonly
|
|
47
|
+
private readonly logger;
|
|
47
48
|
private readonly activeMetrics;
|
|
48
49
|
private readonly completedMetrics;
|
|
49
50
|
private readonly enabled;
|
|
50
51
|
private readonly getTime;
|
|
51
|
-
constructor(
|
|
52
|
+
constructor(logger: Logger | null, enabled?: boolean);
|
|
52
53
|
/**
|
|
53
54
|
* Start measuring a performance metric
|
|
54
55
|
*
|
|
@@ -74,6 +74,8 @@ import { boxDecorationBreak } from './property-descriptors/box-decoration-break'
|
|
|
74
74
|
import { type AccentColor } from './property-descriptors/accent-color';
|
|
75
75
|
import { type WebkitTextFillColor } from './property-descriptors/webkit-text-fill-color';
|
|
76
76
|
import { type ISOLATION } from './property-descriptors/isolation';
|
|
77
|
+
import { type WILL_CHANGE } from './property-descriptors/will-change';
|
|
78
|
+
import { type CONTAIN } from './property-descriptors/contain';
|
|
77
79
|
import { type OUTLINE_STYLE, type OutlineColor } from './property-descriptors/outline';
|
|
78
80
|
import { type FilterValue } from './property-descriptors/filter';
|
|
79
81
|
import { type MaskImage, type MaskPosition, type MaskRepeat, type MaskSize } from './property-descriptors/mask';
|
|
@@ -173,6 +175,8 @@ export declare class CSSParsedDeclaration {
|
|
|
173
175
|
accentColor: AccentColor;
|
|
174
176
|
webkitTextFillColor: WebkitTextFillColor;
|
|
175
177
|
isolation: ISOLATION;
|
|
178
|
+
willChange: WILL_CHANGE;
|
|
179
|
+
contain: CONTAIN;
|
|
176
180
|
outlineColor: OutlineColor;
|
|
177
181
|
outlineStyle: OUTLINE_STYLE;
|
|
178
182
|
outlineWidth: number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IPropertyIdentValueDescriptor } from '../property-descriptor';
|
|
2
|
+
export declare const enum CONTAIN {
|
|
3
|
+
NONE = 0,
|
|
4
|
+
/** `paint`, `layout`, `strict`, `content` or `size paint`-style combos. */
|
|
5
|
+
PAINT_ISOLATION = 1
|
|
6
|
+
}
|
|
7
|
+
export declare const contain: IPropertyIdentValueDescriptor<CONTAIN>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IPropertyListDescriptor } from '../property-descriptor';
|
|
2
|
+
export declare const enum WILL_CHANGE {
|
|
3
|
+
AUTO = 0,
|
|
4
|
+
/** Any paint-affecting hint: the element creates a stacking context. */
|
|
5
|
+
STACKING = 1
|
|
6
|
+
}
|
|
7
|
+
export declare const willChange: IPropertyListDescriptor<WILL_CHANGE>;
|
|
@@ -42,6 +42,13 @@ export declare class DocumentCloner {
|
|
|
42
42
|
* the other stylesheet-cloning paths.
|
|
43
43
|
*/
|
|
44
44
|
private appendDocumentAdoptedStyles;
|
|
45
|
+
/**
|
|
46
|
+
* Add the rules that hide the source ::before / ::after (the clone draws
|
|
47
|
+
* them as surrogate elements) to the clone's <head>. Inside <body> the
|
|
48
|
+
* <style> would be one of its children, and `body > :first-child`,
|
|
49
|
+
* `:nth-child()` and sibling selectors would match the wrong elements.
|
|
50
|
+
*/
|
|
51
|
+
private appendPseudoHideStyles;
|
|
45
52
|
toIFrame(ownerDocument: Document, windowSize: Bounds): Promise<HTMLIFrameElement>;
|
|
46
53
|
createElementClone<T extends HTMLElement | SVGElement>(node: T): HTMLElement | SVGElement;
|
|
47
54
|
createCustomElementClone(originalNode: HTMLElement, clonedNode: HTMLElement): HTMLElement;
|
|
@@ -2,6 +2,7 @@ import { CSSParsedDeclaration } from '../css/index';
|
|
|
2
2
|
import { TextContainer } from './text-container';
|
|
3
3
|
import { Bounds } from '../css/layout/bounds';
|
|
4
4
|
import { Context } from '../core/context';
|
|
5
|
+
import { FilterReferences } from './filter-reference';
|
|
5
6
|
export interface ElementContainerOptions {
|
|
6
7
|
normalizeDom?: boolean;
|
|
7
8
|
}
|
|
@@ -17,6 +18,11 @@ export declare class ElementContainer {
|
|
|
17
18
|
* bounds to leave a matching gap (issue #227).
|
|
18
19
|
*/
|
|
19
20
|
readonly legendBounds?: Bounds;
|
|
21
|
+
/**
|
|
22
|
+
* Same-document `filter: url(#id)` references, resolved while the cloned
|
|
23
|
+
* DOM is available. The surface compositor renders them in an SVG pass.
|
|
24
|
+
*/
|
|
25
|
+
readonly filterReferences?: FilterReferences;
|
|
20
26
|
createsStackingContext: boolean;
|
|
21
27
|
createsRealStackingContext: boolean;
|
|
22
28
|
isListOwner: boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS `filter: url(#id)` references for the surface compositor.
|
|
3
|
+
*
|
|
4
|
+
* The referenced <filter> is resolved while the cloned DOM is still available
|
|
5
|
+
* and copied into a detached, self-contained form: its region is converted to
|
|
6
|
+
* user space around the element's border box, and presentation properties a
|
|
7
|
+
* stylesheet may set are inlined. The copy is later serialized into an SVG
|
|
8
|
+
* image together with the composited surface, so it must not depend on the
|
|
9
|
+
* document it came from.
|
|
10
|
+
*/
|
|
11
|
+
export interface FilterRegion {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
export interface FilterReference {
|
|
18
|
+
/** Detached copy with a userSpaceOnUse region relative to the border box. */
|
|
19
|
+
readonly element: SVGFilterElement;
|
|
20
|
+
readonly region: FilterRegion;
|
|
21
|
+
/** How far (CSS px) the filter region reaches beyond the border box. */
|
|
22
|
+
readonly outset: number;
|
|
23
|
+
}
|
|
24
|
+
export type FilterReferences = ReadonlyMap<string, FilterReference>;
|
|
25
|
+
/** The `#id` of a same-document url() body (`"#id"`, `'#id'` or `#id`), or null. */
|
|
26
|
+
export declare const parseFilterReference: (body: string) => string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve every same-document url() reference of a computed filter value.
|
|
29
|
+
* References that cannot be expressed in the serialized SVG are left out, so
|
|
30
|
+
* the compositor rejects the chain and the subtree keeps the legacy renderer.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveFilterReferences(element: Element, filter: string | null, box: {
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
}): FilterReferences | undefined;
|
|
@@ -15,9 +15,9 @@ export declare enum PseudoElementType {
|
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Inject the stylesheet that hides pseudo-element surrogate containers.
|
|
18
|
-
*
|
|
18
|
+
* Added to the cloned <head> so the surrogates themselves never render.
|
|
19
19
|
*/
|
|
20
|
-
export declare const createPseudoHideStyles: (
|
|
20
|
+
export declare const createPseudoHideStyles: (parent: Element, cspNonce?: string) => void;
|
|
21
21
|
/**
|
|
22
22
|
* Resolves computed `content` of ::before/::after into surrogate DOM nodes.
|
|
23
23
|
*
|
|
@@ -50,11 +50,26 @@ export declare class CanvasRenderer {
|
|
|
50
50
|
constructor(context: Context, options: RenderConfigurations, surfaceRoot?: ElementPaint | undefined, surfaceBudget?: SurfaceBudget);
|
|
51
51
|
renderStack(stack: StackingContext): Promise<void>;
|
|
52
52
|
private canComposite;
|
|
53
|
+
/**
|
|
54
|
+
* Root-to-element transform accumulated from the ancestor chain's
|
|
55
|
+
* TransformEffects (including zoom), stopping at the surface root. The
|
|
56
|
+
* element's own TransformEffect is intentionally excluded: inside the
|
|
57
|
+
* offscreen surface it is still applied by the normal effects pass, and
|
|
58
|
+
* at composition time it is filtered from the recomposed effect list.
|
|
59
|
+
*/
|
|
60
|
+
private ancestorTransform;
|
|
53
61
|
private renderCompositedStack;
|
|
54
62
|
/**
|
|
55
63
|
* Composite an alpha mask onto a finished element surface: all mask
|
|
56
64
|
* layers are painted additively into a mask surface, then kept pixels are
|
|
57
65
|
* selected with destination-in.
|
|
66
|
+
*
|
|
67
|
+
* Coordinate spaces: the source surface paints in LAYOUT space (the
|
|
68
|
+
* ancestor TransformEffects stay active on the main canvas and transform
|
|
69
|
+
* the draw-back), so the mask must be painted in layout space too —
|
|
70
|
+
* anchored to the element's border box (containerBounds) — riding ONLY
|
|
71
|
+
* the element's own transform effects, which apply inside the surface
|
|
72
|
+
* rather than at draw-back.
|
|
58
73
|
*/
|
|
59
74
|
private applyMask;
|
|
60
75
|
/**
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { FilterReferences } from '../../dom/filter-reference';
|
|
1
2
|
export declare class FilterSurfaceError extends Error {
|
|
2
3
|
}
|
|
3
4
|
export declare const releaseSurface: (canvas: HTMLCanvasElement) => void;
|
|
4
5
|
/**
|
|
5
6
|
* A parsed CSS filter chain. Functions keep their declaration order — CSS
|
|
6
7
|
* applies them left to right, and the native canvas backend reproduces that
|
|
7
|
-
* order exactly.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* order exactly. Same-document url() references are kept as their own step
|
|
9
|
+
* and rendered by an SVG pass. Chains containing functions the backends
|
|
10
|
+
* cannot express (external url() references, unknown functions) fail parsing
|
|
11
|
+
* and stay on the legacy renderer, where ctx.filter receives the full string.
|
|
10
12
|
*/
|
|
11
13
|
export type FilterFunction = {
|
|
12
14
|
kind: 'blur';
|
|
@@ -21,6 +23,9 @@ export type FilterFunction = {
|
|
|
21
23
|
kind: 'unitless';
|
|
22
24
|
name: UnitlessFilterName;
|
|
23
25
|
value: number;
|
|
26
|
+
} | {
|
|
27
|
+
kind: 'url';
|
|
28
|
+
ref: string;
|
|
24
29
|
};
|
|
25
30
|
export type UnitlessFilterName = 'brightness' | 'contrast' | 'grayscale' | 'hue-rotate' | 'invert' | 'opacity' | 'saturate' | 'sepia';
|
|
26
31
|
export interface ParsedFilter {
|
|
@@ -36,8 +41,18 @@ export declare const nativeFilterString: (filter: ParsedFilter, scale: number) =
|
|
|
36
41
|
/**
|
|
37
42
|
* Outset (in CSS pixels) a surface must grow so blur/shadow spillover is not
|
|
38
43
|
* cropped. Unitless functions never spread beyond the bounds. Consecutive
|
|
39
|
-
* blurs compound, so their radii sum.
|
|
44
|
+
* blurs compound, so their radii sum. A url() reference can paint up to its
|
|
45
|
+
* filter region, which may extend beyond the border box.
|
|
40
46
|
*/
|
|
41
|
-
export declare function filterOutset(filter: ParsedFilter): number;
|
|
47
|
+
export declare function filterOutset(filter: ParsedFilter, references?: FilterReferences): number;
|
|
42
48
|
export declare function supportsNativeFilters(owner?: Document): boolean;
|
|
43
|
-
|
|
49
|
+
/** Where url() references resolve, and the border box origin inside the surface (CSS px). */
|
|
50
|
+
export interface FilterSurfaceReferences {
|
|
51
|
+
references?: FilterReferences;
|
|
52
|
+
origin: {
|
|
53
|
+
x: number;
|
|
54
|
+
y: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export declare function renderFilterSurface(source: HTMLCanvasElement, filter: ParsedFilter, opacity: number, scale: number, signal?: AbortSignal, references?: FilterSurfaceReferences): Promise<HTMLCanvasElement>;
|
|
58
|
+
export declare function renderSvgFilterSurface(source: HTMLCanvasElement, filter: ParsedFilter, opacity: number, scale: number, signal?: AbortSignal): Promise<HTMLCanvasElement>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2D affine matrix utilities for the composited-surface render path.
|
|
3
|
+
*
|
|
4
|
+
* Matrices use the canvas `transform(a, b, c, d, e, f)` column-vector
|
|
5
|
+
* convention:
|
|
6
|
+
*
|
|
7
|
+
* | a c e | | x' | | a·x + c·y + e |
|
|
8
|
+
* | b d f | × | y' | = | b·x + d·y + f |
|
|
9
|
+
* | 0 0 1 | | 1 | | 1 |
|
|
10
|
+
*
|
|
11
|
+
* `TransformEffect` carries the same tuple order, so effects and bounds can
|
|
12
|
+
* share these helpers. Composition follows the canvas post-multiply rule:
|
|
13
|
+
* `multiplyMatrix(ancestor, own)` equals `ancestor` followed by `own`.
|
|
14
|
+
*/
|
|
15
|
+
import { Bounds } from '../css/layout/bounds';
|
|
16
|
+
import type { Matrix } from '../css/property-descriptors/transform';
|
|
17
|
+
export declare const IDENTITY_MATRIX: Matrix;
|
|
18
|
+
export declare const isIdentityMatrix: (m: Matrix) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Compose two transforms: the result applies `a` first, then `b`
|
|
21
|
+
* (canvas post-multiply, matching successive `ctx.transform` calls).
|
|
22
|
+
*/
|
|
23
|
+
export declare const multiplyMatrix: (a: Matrix, b: Matrix) => Matrix;
|
|
24
|
+
/** Apply a matrix to a point, returning the mapped [x, y]. */
|
|
25
|
+
export declare const applyMatrixToPoint: (m: Matrix, x: number, y: number) => [number, number];
|
|
26
|
+
/**
|
|
27
|
+
* Map a layout-space Bounds through the matrix and return the axis-aligned
|
|
28
|
+
* bounding box of the four transformed corners. Non-uniform scales and
|
|
29
|
+
* rotations grow the box; this is intentionally conservative.
|
|
30
|
+
*/
|
|
31
|
+
export declare const transformBoundsToAabb: (m: Matrix, bounds: Bounds) => Bounds;
|
|
32
|
+
/**
|
|
33
|
+
* Invert an affine matrix. Returns null for singular matrices
|
|
34
|
+
* (zero-scale transforms have no meaningful inverse).
|
|
35
|
+
*/
|
|
36
|
+
export declare const invertMatrix: (m: Matrix) => Matrix | null;
|
|
37
|
+
/**
|
|
38
|
+
* Map a visual-space viewport back into the layout space of `m`'s inputs.
|
|
39
|
+
* Used where a crop window (visual coordinates) must select content measured
|
|
40
|
+
* in layout coordinates: the conservative answer is the AABB of the inverse
|
|
41
|
+
* viewport corners.
|
|
42
|
+
*/
|
|
43
|
+
export declare const inverseTransformBoundsToAabb: (m: Matrix, bounds: Bounds) => Bounds | null;
|
package/package.json
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"default": "./dist/html2canvas-pro.esm.js"
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
-
"version": "2.6.
|
|
22
|
+
"version": "2.6.2",
|
|
23
23
|
"author": {
|
|
24
24
|
"name": "yorickshan",
|
|
25
25
|
"email": "yorickshan@gmail.com",
|
|
@@ -39,44 +39,44 @@
|
|
|
39
39
|
"url": "https://github.com/yorickshan/html2canvas-pro"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@commitlint/cli": "^21.2.
|
|
43
|
-
"@commitlint/config-conventional": "^21.2.
|
|
42
|
+
"@commitlint/cli": "^21.2.4",
|
|
43
|
+
"@commitlint/config-conventional": "^21.2.4",
|
|
44
44
|
"@types/express": "^5.0.6",
|
|
45
|
-
"@types/node": "^24.
|
|
45
|
+
"@types/node": "^24.19.2",
|
|
46
46
|
"@types/pngjs": "^6.0.5",
|
|
47
47
|
"@types/serve-index": "^1.9.4",
|
|
48
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
49
|
-
"@typescript-eslint/parser": "^8.
|
|
48
|
+
"@typescript-eslint/eslint-plugin": "^8.72.1",
|
|
49
|
+
"@typescript-eslint/parser": "^8.72.1",
|
|
50
50
|
"@typescript/native": "npm:typescript@^7.0.2",
|
|
51
|
-
"@vitest/coverage-v8": "^5.0
|
|
52
|
-
"axios": "^1.
|
|
53
|
-
"body-parser": "^2.
|
|
51
|
+
"@vitest/coverage-v8": "^5.1.0",
|
|
52
|
+
"axios": "^1.21.0",
|
|
53
|
+
"body-parser": "^2.4.0",
|
|
54
54
|
"conventional-changelog": "^8.1.3",
|
|
55
55
|
"conventional-changelog-conventionalcommits": "^10.4.1",
|
|
56
56
|
"cors": "^2.8.6",
|
|
57
|
-
"eslint": "^10.
|
|
57
|
+
"eslint": "^10.14.0",
|
|
58
58
|
"eslint-config-prettier": "^10.1.8",
|
|
59
|
-
"eslint-plugin-prettier": "^5.5.
|
|
59
|
+
"eslint-plugin-prettier": "^5.5.7",
|
|
60
60
|
"express": "^5.3.0",
|
|
61
|
-
"express-rate-limit": "^8.7.
|
|
61
|
+
"express-rate-limit": "^8.7.3",
|
|
62
62
|
"glob": "^13.0.6",
|
|
63
63
|
"husky": "^9.1.7",
|
|
64
|
-
"jsdom": "^30.1.
|
|
64
|
+
"jsdom": "^30.1.3",
|
|
65
65
|
"lint-staged": "^17.6.0",
|
|
66
66
|
"pixelmatch": "^8.0.0",
|
|
67
67
|
"playwright": "1.64.0",
|
|
68
68
|
"pngjs": "^7.0.0",
|
|
69
69
|
"prettier": "^3.9.10",
|
|
70
|
-
"rimraf": "^6.1.
|
|
71
|
-
"rolldown": "^1.2.
|
|
70
|
+
"rimraf": "^6.1.4",
|
|
71
|
+
"rolldown": "^1.2.16",
|
|
72
72
|
"serve-index": "^1.9.2",
|
|
73
73
|
"slash": "5.1.0",
|
|
74
74
|
"tsx": "^4.23.15",
|
|
75
75
|
"typedoc": "^0.28.20",
|
|
76
76
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
77
|
-
"vite": "^8.3.
|
|
78
|
-
"vitepress": "
|
|
79
|
-
"vitest": "^5.0
|
|
77
|
+
"vite": "^8.3.5",
|
|
78
|
+
"vitepress": "2.0.0-alpha.21",
|
|
79
|
+
"vitest": "^5.1.0",
|
|
80
80
|
"yargs": "^18.2.0"
|
|
81
81
|
},
|
|
82
82
|
"lint-staged": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"unittest:coverage": "vitest run --coverage",
|
|
100
100
|
"bench:css-parse": "tsx scripts/benchmarks/css-parse.bench.ts",
|
|
101
101
|
"bench:render": "node scripts/benchmarks/render.bench.mjs",
|
|
102
|
-
"reftests-diff": "
|
|
102
|
+
"reftests-diff": "vitest run --config vitest.reftest.config.ts",
|
|
103
103
|
"watch": "rolldown -w",
|
|
104
104
|
"watch:unittest": "vitest",
|
|
105
105
|
"start": "tsx tests/server --port=8080 --cors=8081",
|