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