html2canvas-pro 2.3.2 → 2.3.3
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 +98 -10
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +98 -10
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +98 -10
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +3 -3
- package/dist/lib/css/property-descriptors/background-clip.js +2 -0
- package/dist/lib/render/canvas/canvas-renderer.js +123 -9
- package/dist/types/css/property-descriptors/background-clip.d.ts +2 -1
- package/dist/types/render/canvas/canvas-renderer.d.ts +18 -0
- package/package.json +1 -1
package/dist/html2canvas-pro.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.3.
|
|
2
|
+
* html2canvas-pro 2.3.3 <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
|
*/
|
|
@@ -3959,6 +3959,7 @@ const backgroundClip = {
|
|
|
3959
3959
|
if (isIdentToken(token)) switch (token.value) {
|
|
3960
3960
|
case "padding-box": return 1;
|
|
3961
3961
|
case "content-box": return 2;
|
|
3962
|
+
case "text": return 3;
|
|
3962
3963
|
}
|
|
3963
3964
|
return 0;
|
|
3964
3965
|
});
|
|
@@ -10525,6 +10526,7 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
10525
10526
|
this.effectsRenderer.applyEffects(paint.getEffects(2));
|
|
10526
10527
|
const styles = paint.container.styles;
|
|
10527
10528
|
const hasBackground = !isTransparent(styles.backgroundColor) || styles.backgroundImage.length;
|
|
10529
|
+
const hasTextClip = hasTextBackgroundClip(styles);
|
|
10528
10530
|
const borders = [
|
|
10529
10531
|
{
|
|
10530
10532
|
style: styles.borderTopStyle,
|
|
@@ -10547,17 +10549,21 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
10547
10549
|
width: styles.borderLeftWidth
|
|
10548
10550
|
}
|
|
10549
10551
|
];
|
|
10550
|
-
const
|
|
10552
|
+
const backgroundClipValue = getBackgroundValueForIndex(styles.backgroundClip, 0);
|
|
10553
|
+
const backgroundPaintingArea = calculateBackgroundCurvedPaintingArea(backgroundClipValue, paint.curves);
|
|
10551
10554
|
if (hasBackground || styles.boxShadow.length) {
|
|
10552
|
-
this.
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
|
|
10556
|
-
this.ctx.
|
|
10557
|
-
|
|
10555
|
+
if (hasTextClip && paint.container.textNodes.length > 0) await this.renderTextClippedBackground(paint);
|
|
10556
|
+
else {
|
|
10557
|
+
this.ctx.save();
|
|
10558
|
+
this.path(backgroundPaintingArea);
|
|
10559
|
+
this.ctx.clip();
|
|
10560
|
+
if (!isTransparent(styles.backgroundColor)) {
|
|
10561
|
+
this.ctx.fillStyle = asString(styles.backgroundColor);
|
|
10562
|
+
this.ctx.fill();
|
|
10563
|
+
}
|
|
10564
|
+
await this.backgroundRenderer.renderBackgroundImage(paint.container);
|
|
10565
|
+
this.ctx.restore();
|
|
10558
10566
|
}
|
|
10559
|
-
await this.backgroundRenderer.renderBackgroundImage(paint.container);
|
|
10560
|
-
this.ctx.restore();
|
|
10561
10567
|
styles.boxShadow.slice(0).reverse().forEach((shadow) => {
|
|
10562
10568
|
this.ctx.save();
|
|
10563
10569
|
const borderBoxArea = calculateBorderBoxPath(paint.curves);
|
|
@@ -10616,6 +10622,82 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
10616
10622
|
this.effectsRenderer.applyEffects([]);
|
|
10617
10623
|
return this.canvas;
|
|
10618
10624
|
}
|
|
10625
|
+
/**
|
|
10626
|
+
* Render background clipped to text shape using offscreen canvas with destination-in compositing.
|
|
10627
|
+
* This implements background-clip: text support.
|
|
10628
|
+
*
|
|
10629
|
+
* Algorithm:
|
|
10630
|
+
* 1. Draw background (color + images) onto an offscreen canvas
|
|
10631
|
+
* 2. Use destination-in compositing to clip the background to the text glyph shapes
|
|
10632
|
+
* 3. Composite the result back onto the main canvas
|
|
10633
|
+
*
|
|
10634
|
+
* The offscreen canvas uses CSS-pixel dimensions (not device-pixel) because the
|
|
10635
|
+
* background renderer handles scaling internally via BackgroundRenderer options.
|
|
10636
|
+
*/
|
|
10637
|
+
async renderTextClippedBackground(paint) {
|
|
10638
|
+
const container = paint.container;
|
|
10639
|
+
const styles = container.styles;
|
|
10640
|
+
const bounds = container.bounds;
|
|
10641
|
+
if (bounds.width <= 0 || bounds.height <= 0) return;
|
|
10642
|
+
const offscreen = (this.canvas.ownerDocument ?? document).createElement("canvas");
|
|
10643
|
+
const width = Math.ceil(bounds.width);
|
|
10644
|
+
const height = Math.ceil(bounds.height);
|
|
10645
|
+
offscreen.width = width;
|
|
10646
|
+
offscreen.height = height;
|
|
10647
|
+
const offCtx = offscreen.getContext("2d");
|
|
10648
|
+
if (!offCtx) return;
|
|
10649
|
+
const [fontString] = this.textRenderer.createFontStyle(styles);
|
|
10650
|
+
offCtx.font = fontString;
|
|
10651
|
+
offCtx.textBaseline = "alphabetic";
|
|
10652
|
+
offCtx.textAlign = "left";
|
|
10653
|
+
offCtx.direction = styles.direction === 1 ? "rtl" : "ltr";
|
|
10654
|
+
const baseline = measureBaseline(offCtx, styles.fontSize.number);
|
|
10655
|
+
const bgRenderer = new BackgroundRenderer({
|
|
10656
|
+
ctx: offCtx,
|
|
10657
|
+
context: this.context,
|
|
10658
|
+
canvas: offscreen,
|
|
10659
|
+
options: {
|
|
10660
|
+
width,
|
|
10661
|
+
height,
|
|
10662
|
+
scale: 1
|
|
10663
|
+
}
|
|
10664
|
+
});
|
|
10665
|
+
if (!isTransparent(styles.backgroundColor)) {
|
|
10666
|
+
offCtx.fillStyle = asString(styles.backgroundColor);
|
|
10667
|
+
offCtx.fillRect(0, 0, width, height);
|
|
10668
|
+
}
|
|
10669
|
+
offCtx.save();
|
|
10670
|
+
offCtx.translate(-bounds.left, -bounds.top);
|
|
10671
|
+
await bgRenderer.renderBackgroundImage(container);
|
|
10672
|
+
offCtx.restore();
|
|
10673
|
+
offCtx.globalCompositeOperation = "destination-in";
|
|
10674
|
+
offCtx.fillStyle = "#000";
|
|
10675
|
+
const writingMode = styles.writingMode;
|
|
10676
|
+
const letterSpacing = styles.letterSpacing;
|
|
10677
|
+
for (const textNode of container.textNodes) for (const textBound of textNode.textBounds) {
|
|
10678
|
+
const localLeft = textBound.bounds.left - bounds.left;
|
|
10679
|
+
const localTop = textBound.bounds.top - bounds.top + baseline;
|
|
10680
|
+
if (letterSpacing > 0) this.renderTextMaskWithLetterSpacing(offCtx, textBound, letterSpacing, localLeft, localTop, writingMode);
|
|
10681
|
+
else offCtx.fillText(textBound.text, localLeft, localTop);
|
|
10682
|
+
}
|
|
10683
|
+
this.ctx.drawImage(offscreen, bounds.left, bounds.top);
|
|
10684
|
+
}
|
|
10685
|
+
/**
|
|
10686
|
+
* Render text glyphs one-by-one as a mask, applying letter-spacing between characters.
|
|
10687
|
+
* This ensures the mask matches how the text renderer lays out the characters.
|
|
10688
|
+
*/
|
|
10689
|
+
renderTextMaskWithLetterSpacing(ctx, text, letterSpacing, x, y, writingMode) {
|
|
10690
|
+
const letters = segmentGraphemes(text.text);
|
|
10691
|
+
let offset = x;
|
|
10692
|
+
for (const letter of letters) {
|
|
10693
|
+
if (isVerticalWritingMode(writingMode)) {
|
|
10694
|
+
ctx.fillText(text.text, x, y);
|
|
10695
|
+
return;
|
|
10696
|
+
}
|
|
10697
|
+
ctx.fillText(letter, offset, y);
|
|
10698
|
+
offset += ctx.measureText(letter).width + letterSpacing;
|
|
10699
|
+
}
|
|
10700
|
+
}
|
|
10619
10701
|
};
|
|
10620
10702
|
const calculateBackgroundCurvedPaintingArea = (clip, curves) => {
|
|
10621
10703
|
switch (clip) {
|
|
@@ -10624,6 +10706,12 @@ const calculateBackgroundCurvedPaintingArea = (clip, curves) => {
|
|
|
10624
10706
|
default: return calculatePaddingBoxPath(curves);
|
|
10625
10707
|
}
|
|
10626
10708
|
};
|
|
10709
|
+
/**
|
|
10710
|
+
* Check if any background layer uses background-clip: text
|
|
10711
|
+
*/
|
|
10712
|
+
const hasTextBackgroundClip = (styles) => {
|
|
10713
|
+
return styles.backgroundClip.some((clip) => clip === 3);
|
|
10714
|
+
};
|
|
10627
10715
|
//#endregion
|
|
10628
10716
|
//#region src/render/canvas/foreignobject-renderer.ts
|
|
10629
10717
|
var ForeignObjectRenderer = class {
|