html2canvas-pro 2.4.4 → 2.4.5
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.cjs +216 -22
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +216 -22
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +216 -22
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +4 -4
- package/dist/lib/render/canvas/box-shadow-geometry.js +52 -0
- package/dist/lib/render/canvas/box-shadow-painter.js +194 -0
- package/dist/lib/render/canvas/box-shadow-transform.js +42 -0
- package/dist/lib/render/canvas/canvas-renderer.js +2 -25
- package/dist/types/render/canvas/box-shadow-geometry.d.ts +3 -0
- package/dist/types/render/canvas/box-shadow-painter.d.ts +13 -0
- package/dist/types/render/canvas/box-shadow-transform.d.ts +16 -0
- package/package.json +1 -1
package/dist/html2canvas-pro.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.4.
|
|
2
|
+
* html2canvas-pro 2.4.5 <https://yorickshan.github.io/html2canvas-pro/>
|
|
3
3
|
* Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
|
|
4
4
|
* Released under MIT License
|
|
5
5
|
*/
|
|
@@ -10809,6 +10809,220 @@ const canvasTextAlign = (textAlign) => {
|
|
|
10809
10809
|
}
|
|
10810
10810
|
};
|
|
10811
10811
|
//#endregion
|
|
10812
|
+
//#region src/render/canvas/box-shadow-geometry.ts
|
|
10813
|
+
const shadowRadius = (radius, spread) => {
|
|
10814
|
+
const delta = spread > radius ? spread * (1 + Math.pow(radius / spread - 1, 3)) : spread;
|
|
10815
|
+
return Math.max(0, radius + delta);
|
|
10816
|
+
};
|
|
10817
|
+
const spreadShadowPath = (paths, spread) => {
|
|
10818
|
+
if (spread === 0) return paths;
|
|
10819
|
+
const corners = paths.map((point, index) => {
|
|
10820
|
+
if (!isBezierCurve(point)) return {
|
|
10821
|
+
x: point.x,
|
|
10822
|
+
y: point.y,
|
|
10823
|
+
rx: 0,
|
|
10824
|
+
ry: 0
|
|
10825
|
+
};
|
|
10826
|
+
return {
|
|
10827
|
+
x: index % 2 === 0 ? point.start.x : point.end.x,
|
|
10828
|
+
y: index % 2 === 0 ? point.end.y : point.start.y,
|
|
10829
|
+
rx: Math.abs(point.end.x - point.start.x),
|
|
10830
|
+
ry: Math.abs(point.end.y - point.start.y)
|
|
10831
|
+
};
|
|
10832
|
+
});
|
|
10833
|
+
const width = corners[1].x - corners[0].x + 2 * spread;
|
|
10834
|
+
const height = corners[3].y - corners[0].y + 2 * spread;
|
|
10835
|
+
if (width <= 0 || height <= 0) return [];
|
|
10836
|
+
const radii = corners.map((c) => ({
|
|
10837
|
+
x: shadowRadius(c.rx, spread),
|
|
10838
|
+
y: shadowRadius(c.ry, spread)
|
|
10839
|
+
}));
|
|
10840
|
+
const ratio = (size, sum) => sum > 0 ? size / sum : 1;
|
|
10841
|
+
const factor = Math.min(1, ratio(width, radii[0].x + radii[1].x), ratio(width, radii[3].x + radii[2].x), ratio(height, radii[0].y + radii[3].y), ratio(height, radii[1].y + radii[2].y));
|
|
10842
|
+
return paths.map((point, index) => {
|
|
10843
|
+
const corner = corners[index];
|
|
10844
|
+
const x = corner.x + (index === 1 || index === 2 ? spread : -spread);
|
|
10845
|
+
const y = corner.y + (index >= 2 ? spread : -spread);
|
|
10846
|
+
if (!isBezierCurve(point)) return new Vector(x, y);
|
|
10847
|
+
const rx = radii[index].x * factor;
|
|
10848
|
+
const ry = radii[index].y * factor;
|
|
10849
|
+
if (!rx || !ry) return new Vector(x, y);
|
|
10850
|
+
const sx = rx / corner.rx;
|
|
10851
|
+
const sy = ry / corner.ry;
|
|
10852
|
+
const resize = (v) => new Vector(x + (v.x - corner.x) * sx, y + (v.y - corner.y) * sy);
|
|
10853
|
+
return new BezierCurve(resize(point.start), resize(point.startControl), resize(point.endControl), resize(point.end));
|
|
10854
|
+
});
|
|
10855
|
+
};
|
|
10856
|
+
//#endregion
|
|
10857
|
+
//#region src/render/canvas/box-shadow-transform.ts
|
|
10858
|
+
const shadowSpace = (matrix, width, height) => {
|
|
10859
|
+
const { a, b, c, d, e, f } = matrix;
|
|
10860
|
+
if (![
|
|
10861
|
+
a,
|
|
10862
|
+
b,
|
|
10863
|
+
c,
|
|
10864
|
+
d,
|
|
10865
|
+
e,
|
|
10866
|
+
f,
|
|
10867
|
+
width,
|
|
10868
|
+
height
|
|
10869
|
+
].every(Number.isFinite)) return null;
|
|
10870
|
+
const determinant = a * d - b * c;
|
|
10871
|
+
if (!Number.isFinite(determinant) || determinant === 0) return null;
|
|
10872
|
+
const inversePoint = (x, y) => ({
|
|
10873
|
+
x: (d * (x - e) - c * (y - f)) / determinant,
|
|
10874
|
+
y: (-b * (x - e) + a * (y - f)) / determinant
|
|
10875
|
+
});
|
|
10876
|
+
const corners = [
|
|
10877
|
+
inversePoint(0, 0),
|
|
10878
|
+
inversePoint(width, 0),
|
|
10879
|
+
inversePoint(width, height),
|
|
10880
|
+
inversePoint(0, height)
|
|
10881
|
+
];
|
|
10882
|
+
if (!corners.every((point) => Number.isFinite(point.x) && Number.isFinite(point.y))) return null;
|
|
10883
|
+
const left = Math.min(...corners.map((point) => point.x));
|
|
10884
|
+
const top = Math.min(...corners.map((point) => point.y));
|
|
10885
|
+
const right = Math.max(...corners.map((point) => point.x));
|
|
10886
|
+
const bottom = Math.max(...corners.map((point) => point.y));
|
|
10887
|
+
const xx = a * a + b * b;
|
|
10888
|
+
const yy = c * c + d * d;
|
|
10889
|
+
const xy = a * c + b * d;
|
|
10890
|
+
const scale = Math.sqrt((xx + yy + Math.hypot(xx - yy, 2 * xy)) / 2);
|
|
10891
|
+
if (!Number.isFinite(scale) || scale <= 0) return null;
|
|
10892
|
+
const tolerance = 1e-10 * Math.max(xx, yy);
|
|
10893
|
+
return {
|
|
10894
|
+
matrix,
|
|
10895
|
+
viewport: new Bounds(left, top, right - left, bottom - top),
|
|
10896
|
+
scale,
|
|
10897
|
+
uniform: Math.abs(xx - yy) <= tolerance && Math.abs(xy) <= tolerance
|
|
10898
|
+
};
|
|
10899
|
+
};
|
|
10900
|
+
//#endregion
|
|
10901
|
+
//#region src/render/canvas/box-shadow-painter.ts
|
|
10902
|
+
const complement = (ctx, rect, hole) => {
|
|
10903
|
+
ctx.beginPath();
|
|
10904
|
+
ctx.rect(rect.left, rect.top, rect.width, rect.height);
|
|
10905
|
+
if (hole.length) {
|
|
10906
|
+
formatCanvasPath(ctx, hole);
|
|
10907
|
+
ctx.closePath();
|
|
10908
|
+
}
|
|
10909
|
+
};
|
|
10910
|
+
const insetHole = (paint, shadow) => {
|
|
10911
|
+
const spread = shadow.spread.number;
|
|
10912
|
+
const box = paddingBox(paint.container);
|
|
10913
|
+
if (box.width - 2 * spread <= 0 || box.height - 2 * spread <= 0) return [];
|
|
10914
|
+
return spreadShadowPath(calculatePaddingBoxPath(paint.curves), -spread);
|
|
10915
|
+
};
|
|
10916
|
+
const paintShadowSurface = async (ctx, paint, shadow, options, budget, space) => {
|
|
10917
|
+
const padding = paddingBox(paint.container);
|
|
10918
|
+
const blur = shadow.blur.number / 2;
|
|
10919
|
+
const margin = Math.ceil(3 * blur) + 2;
|
|
10920
|
+
const spread = shadow.spread.number;
|
|
10921
|
+
const bounds = cropSurface((shadow.inset ? padding : paint.container.bounds.add(shadow.offsetX.number - spread, shadow.offsetY.number - spread, 2 * spread, 2 * spread)).add(-margin, -margin, 2 * margin, 2 * margin), space.viewport, margin, space.scale);
|
|
10922
|
+
if (!bounds.width || !bounds.height) return true;
|
|
10923
|
+
const width = Math.ceil(bounds.width * space.scale);
|
|
10924
|
+
const height = Math.ceil(bounds.height * space.scale);
|
|
10925
|
+
const reserved = reserveSurface(budget, width, height);
|
|
10926
|
+
if (!reserved) return false;
|
|
10927
|
+
let source;
|
|
10928
|
+
let filtered;
|
|
10929
|
+
try {
|
|
10930
|
+
source = ctx.canvas.ownerDocument.createElement("canvas");
|
|
10931
|
+
source.width = width;
|
|
10932
|
+
source.height = height;
|
|
10933
|
+
const sourceCtx = source.getContext("2d");
|
|
10934
|
+
if (!sourceCtx) return false;
|
|
10935
|
+
sourceCtx.scale(space.scale, space.scale);
|
|
10936
|
+
sourceCtx.translate(-bounds.left, -bounds.top);
|
|
10937
|
+
const path = transformPath(shadow.inset ? insetHole(paint, shadow) : spreadShadowPath(calculateBorderBoxPath(paint.curves), spread), shadow.offsetX.number, shadow.offsetY.number, 0, 0);
|
|
10938
|
+
if (shadow.inset) complement(sourceCtx, bounds, path);
|
|
10939
|
+
else createCanvasPath(sourceCtx, path);
|
|
10940
|
+
sourceCtx.fillStyle = asString(shadow.color);
|
|
10941
|
+
sourceCtx.fill(shadow.inset ? "evenodd" : "nonzero");
|
|
10942
|
+
filtered = await renderFilterSurface(source, { blur }, 1, space.scale, options.signal);
|
|
10943
|
+
ctx.save();
|
|
10944
|
+
try {
|
|
10945
|
+
if (shadow.inset) {
|
|
10946
|
+
createCanvasPath(ctx, calculatePaddingBoxPath(paint.curves));
|
|
10947
|
+
ctx.clip();
|
|
10948
|
+
} else {
|
|
10949
|
+
complement(ctx, space.viewport, calculateBorderBoxPath(paint.curves));
|
|
10950
|
+
ctx.clip("evenodd");
|
|
10951
|
+
}
|
|
10952
|
+
ctx.drawImage(filtered, bounds.left, bounds.top, filtered.width / space.scale, filtered.height / space.scale);
|
|
10953
|
+
} finally {
|
|
10954
|
+
ctx.restore();
|
|
10955
|
+
}
|
|
10956
|
+
return true;
|
|
10957
|
+
} catch (error) {
|
|
10958
|
+
if (!(error instanceof FilterSurfaceError)) throw error;
|
|
10959
|
+
return false;
|
|
10960
|
+
} finally {
|
|
10961
|
+
if (filtered && filtered !== source) releaseSurface(filtered);
|
|
10962
|
+
if (source) releaseSurface(source);
|
|
10963
|
+
budget.pixels -= reserved;
|
|
10964
|
+
}
|
|
10965
|
+
};
|
|
10966
|
+
const paintBoxShadow = async (ctx, paint, shadow, options, budget) => {
|
|
10967
|
+
if (options.signal?.aborted) throw new DOMException("The operation was aborted.", "AbortError");
|
|
10968
|
+
if (isTransparent(shadow.color)) return;
|
|
10969
|
+
const spread = shadow.spread.number;
|
|
10970
|
+
if (!shadow.inset && (paint.container.bounds.width + 2 * spread <= 0 || paint.container.bounds.height + 2 * spread <= 0)) return;
|
|
10971
|
+
const knownTransform = typeof ctx.getTransform === "function";
|
|
10972
|
+
const matrix = knownTransform ? ctx.getTransform() : {
|
|
10973
|
+
a: options.scale,
|
|
10974
|
+
b: 0,
|
|
10975
|
+
c: 0,
|
|
10976
|
+
d: options.scale,
|
|
10977
|
+
e: -options.x * options.scale,
|
|
10978
|
+
f: -options.y * options.scale
|
|
10979
|
+
};
|
|
10980
|
+
const space = shadowSpace(matrix, ctx.canvas.width, ctx.canvas.height);
|
|
10981
|
+
if (!space) return;
|
|
10982
|
+
const { viewport } = space;
|
|
10983
|
+
if (shadow.blur.number > 0 && (shadow.inset || !space.uniform) && await paintShadowSurface(ctx, paint, shadow, options, budget, space)) return;
|
|
10984
|
+
const padding = paddingBox(paint.container);
|
|
10985
|
+
ctx.save();
|
|
10986
|
+
try {
|
|
10987
|
+
if (shadow.inset && shadow.blur.number === 0) {
|
|
10988
|
+
createCanvasPath(ctx, calculatePaddingBoxPath(paint.curves));
|
|
10989
|
+
ctx.clip();
|
|
10990
|
+
complement(ctx, padding, transformPath(insetHole(paint, shadow), shadow.offsetX.number, shadow.offsetY.number, 0, 0));
|
|
10991
|
+
ctx.fillStyle = asString(shadow.color);
|
|
10992
|
+
ctx.fill("evenodd");
|
|
10993
|
+
return;
|
|
10994
|
+
}
|
|
10995
|
+
const margin = Math.ceil(shadow.blur.number * 2 + Math.abs(spread) + Math.abs(shadow.offsetX.number) + Math.abs(shadow.offsetY.number)) + 2;
|
|
10996
|
+
const sourceBounds = shadow.inset ? padding.add(-margin, -margin, 2 * margin, 2 * margin) : paint.container.bounds.add(-spread, -spread, 2 * spread, 2 * spread);
|
|
10997
|
+
const { a, b, c, d, e, f } = matrix;
|
|
10998
|
+
const right = sourceBounds.left + sourceBounds.width;
|
|
10999
|
+
const bottom = sourceBounds.top + sourceBounds.height;
|
|
11000
|
+
const maxX = Math.max(a * sourceBounds.left + c * sourceBounds.top + e, a * right + c * sourceBounds.top + e, a * right + c * bottom + e, a * sourceBounds.left + c * bottom + e);
|
|
11001
|
+
const displacement = Math.max(SHADOW_MASK_OFFSET, maxX + margin * space.scale + 2);
|
|
11002
|
+
if (shadow.inset) {
|
|
11003
|
+
createCanvasPath(ctx, calculatePaddingBoxPath(paint.curves));
|
|
11004
|
+
ctx.clip();
|
|
11005
|
+
} else {
|
|
11006
|
+
complement(ctx, viewport, calculateBorderBoxPath(paint.curves));
|
|
11007
|
+
ctx.clip("evenodd");
|
|
11008
|
+
}
|
|
11009
|
+
if (knownTransform) ctx.setTransform(a, b, c, d, e - displacement, f);
|
|
11010
|
+
else ctx.translate(-displacement / a, 0);
|
|
11011
|
+
if (shadow.inset) complement(ctx, sourceBounds, insetHole(paint, shadow));
|
|
11012
|
+
else createCanvasPath(ctx, spreadShadowPath(calculateBorderBoxPath(paint.curves), spread));
|
|
11013
|
+
if (knownTransform) ctx.setTransform(a, b, c, d, e, f);
|
|
11014
|
+
else ctx.translate(displacement / a, 0);
|
|
11015
|
+
ctx.shadowOffsetX = displacement + a * shadow.offsetX.number + c * shadow.offsetY.number;
|
|
11016
|
+
ctx.shadowOffsetY = b * shadow.offsetX.number + d * shadow.offsetY.number;
|
|
11017
|
+
ctx.shadowBlur = shadow.blur.number * space.scale;
|
|
11018
|
+
ctx.shadowColor = asString(shadow.color);
|
|
11019
|
+
ctx.fillStyle = "rgb(0, 0, 0)";
|
|
11020
|
+
ctx.fill(shadow.inset ? "evenodd" : "nonzero");
|
|
11021
|
+
} finally {
|
|
11022
|
+
ctx.restore();
|
|
11023
|
+
}
|
|
11024
|
+
};
|
|
11025
|
+
//#endregion
|
|
10812
11026
|
//#region src/render/canvas/canvas-renderer.ts
|
|
10813
11027
|
var CanvasRenderer = class CanvasRenderer {
|
|
10814
11028
|
constructor(context, options, surfaceRoot, surfaceBudget = { pixels: 0 }) {
|
|
@@ -11111,27 +11325,7 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
11111
11325
|
await this.renderSurfaceBoxShadow(paint, shadow);
|
|
11112
11326
|
continue;
|
|
11113
11327
|
}
|
|
11114
|
-
this.ctx.
|
|
11115
|
-
const borderBoxArea = calculateBorderBoxPath(paint.curves);
|
|
11116
|
-
const maskOffset = shadow.inset ? 0 : SHADOW_MASK_OFFSET;
|
|
11117
|
-
const shadowPaintingArea = transformPath(borderBoxArea, -maskOffset + (shadow.inset ? 1 : -1) * shadow.spread.number, (shadow.inset ? 1 : -1) * shadow.spread.number, shadow.spread.number * (shadow.inset ? -2 : 2), shadow.spread.number * (shadow.inset ? -2 : 2));
|
|
11118
|
-
if (shadow.inset) {
|
|
11119
|
-
this.path(borderBoxArea);
|
|
11120
|
-
this.ctx.clip();
|
|
11121
|
-
this.mask(shadowPaintingArea);
|
|
11122
|
-
} else {
|
|
11123
|
-
this.mask(borderBoxArea);
|
|
11124
|
-
this.ctx.clip();
|
|
11125
|
-
this.path(shadowPaintingArea);
|
|
11126
|
-
}
|
|
11127
|
-
const shadowScale = this.surfaceRoot ? this.options.scale : 1;
|
|
11128
|
-
this.ctx.shadowOffsetX = (shadow.offsetX.number + maskOffset) * shadowScale;
|
|
11129
|
-
this.ctx.shadowOffsetY = shadow.offsetY.number * shadowScale;
|
|
11130
|
-
this.ctx.shadowColor = asString(shadow.color);
|
|
11131
|
-
this.ctx.shadowBlur = shadow.blur.number * shadowScale;
|
|
11132
|
-
this.ctx.fillStyle = shadow.inset ? asString(shadow.color) : "rgba(0,0,0,1)";
|
|
11133
|
-
this.ctx.fill();
|
|
11134
|
-
this.ctx.restore();
|
|
11328
|
+
await paintBoxShadow(this.ctx, paint, shadow, this.options, this.surfaceBudget);
|
|
11135
11329
|
}
|
|
11136
11330
|
}
|
|
11137
11331
|
if (styles.borderImageSource) {
|