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