html2canvas-pro 1.5.12 → 1.6.0
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 +20 -0
- package/dist/html2canvas-pro.esm.js +153 -19
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +153 -19
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +2 -2
- package/dist/lib/css/layout/bounds.js +13 -1
- package/dist/lib/css/layout/bounds.js.map +1 -1
- package/dist/lib/css/property-descriptors/background-position.js +14 -1
- package/dist/lib/css/property-descriptors/background-position.js.map +1 -1
- package/dist/lib/css/types/length-percentage.js +91 -1
- package/dist/lib/css/types/length-percentage.js.map +1 -1
- package/dist/lib/dom/document-cloner.js +2 -1
- package/dist/lib/dom/document-cloner.js.map +1 -1
- package/dist/lib/dom/node-parser.js +14 -1
- package/dist/lib/dom/node-parser.js.map +1 -1
- package/dist/lib/render/canvas/canvas-renderer.js +16 -10
- package/dist/lib/render/canvas/canvas-renderer.js.map +1 -1
- package/dist/lib/render/stacking-context.js +7 -4
- package/dist/lib/render/stacking-context.js.map +1 -1
- package/dist/types/css/types/length-percentage.d.ts +11 -1
- package/package.json +1 -1
package/dist/html2canvas-pro.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 1.
|
|
2
|
+
* html2canvas-pro 1.6.0 <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
|
*/
|
|
@@ -118,7 +118,19 @@
|
|
|
118
118
|
return new Bounds(clientRect.left + context.windowBounds.left, clientRect.top + context.windowBounds.top, clientRect.width, clientRect.height);
|
|
119
119
|
};
|
|
120
120
|
Bounds.fromDOMRectList = function (context, domRectList) {
|
|
121
|
-
var
|
|
121
|
+
var rects = Array.from(domRectList);
|
|
122
|
+
// First try to find a rect with non-zero width
|
|
123
|
+
var domRect = rects.find(function (rect) { return rect.width !== 0; });
|
|
124
|
+
// If not found, try to find a rect with non-zero height
|
|
125
|
+
// This handles cases like inline-flex with single child where width might be 0
|
|
126
|
+
if (!domRect) {
|
|
127
|
+
domRect = rects.find(function (rect) { return rect.height !== 0; });
|
|
128
|
+
}
|
|
129
|
+
// If still not found but rects exist, use the first rect
|
|
130
|
+
// Position info (left, top) might still be valid even if dimensions are 0
|
|
131
|
+
if (!domRect && rects.length > 0) {
|
|
132
|
+
domRect = rects[0];
|
|
133
|
+
}
|
|
122
134
|
return domRect
|
|
123
135
|
? new Bounds(domRect.left + context.windowBounds.left, domRect.top + context.windowBounds.top, domRect.width, domRect.height)
|
|
124
136
|
: Bounds.EMPTY;
|
|
@@ -1610,6 +1622,94 @@
|
|
|
1610
1622
|
var isLengthPercentage = function (token) {
|
|
1611
1623
|
return token.type === 16 /* TokenType.PERCENTAGE_TOKEN */ || isLength(token);
|
|
1612
1624
|
};
|
|
1625
|
+
/**
|
|
1626
|
+
* Check if a token is a calc() function
|
|
1627
|
+
*/
|
|
1628
|
+
var isCalcFunction = function (token) {
|
|
1629
|
+
return token.type === 18 /* TokenType.FUNCTION */ && token.name === 'calc';
|
|
1630
|
+
};
|
|
1631
|
+
/**
|
|
1632
|
+
* Evaluate a calc() expression and convert to LengthPercentage token
|
|
1633
|
+
* Supports basic arithmetic: +, -, *, /
|
|
1634
|
+
* Note: Percentages in calc() are converted based on a context value
|
|
1635
|
+
*/
|
|
1636
|
+
var evaluateCalcToLengthPercentage = function (calcToken, contextValue) {
|
|
1637
|
+
if (contextValue === void 0) { contextValue = 0; }
|
|
1638
|
+
// Build expression string from tokens
|
|
1639
|
+
var buildExpression = function (values) {
|
|
1640
|
+
var expression = '';
|
|
1641
|
+
for (var _i = 0, values_1 = values; _i < values_1.length; _i++) {
|
|
1642
|
+
var value = values_1[_i];
|
|
1643
|
+
if (value.type === 31 /* TokenType.WHITESPACE_TOKEN */) {
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
if (value.type === 18 /* TokenType.FUNCTION */) {
|
|
1647
|
+
if (value.name === 'calc') {
|
|
1648
|
+
var nested = buildExpression(value.values);
|
|
1649
|
+
if (nested === null)
|
|
1650
|
+
return null;
|
|
1651
|
+
expression += "(".concat(nested, ")");
|
|
1652
|
+
}
|
|
1653
|
+
else {
|
|
1654
|
+
return null;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
else if (value.type === 17 /* TokenType.NUMBER_TOKEN */) {
|
|
1658
|
+
expression += value.number.toString();
|
|
1659
|
+
}
|
|
1660
|
+
else if (value.type === 15 /* TokenType.DIMENSION_TOKEN */) {
|
|
1661
|
+
// Convert units to px
|
|
1662
|
+
if (value.unit === 'px') {
|
|
1663
|
+
expression += value.number.toString();
|
|
1664
|
+
}
|
|
1665
|
+
else if (value.unit === 'rem' || value.unit === 'em') {
|
|
1666
|
+
expression += (value.number * 16).toString();
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
expression += value.number.toString();
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
else if (value.type === 16 /* TokenType.PERCENTAGE_TOKEN */) {
|
|
1673
|
+
// Convert percentage to absolute value based on context
|
|
1674
|
+
expression += ((value.number / 100) * contextValue).toString();
|
|
1675
|
+
}
|
|
1676
|
+
else if (value.type === 6 /* TokenType.DELIM_TOKEN */) {
|
|
1677
|
+
var op = value.value;
|
|
1678
|
+
if (op === '+' || op === '-' || op === '*' || op === '/') {
|
|
1679
|
+
expression += " ".concat(op, " ");
|
|
1680
|
+
}
|
|
1681
|
+
else if (op === '(') {
|
|
1682
|
+
expression += '(';
|
|
1683
|
+
}
|
|
1684
|
+
else if (op === ')') {
|
|
1685
|
+
expression += ')';
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
return expression;
|
|
1690
|
+
};
|
|
1691
|
+
try {
|
|
1692
|
+
var expression = buildExpression(calcToken.values);
|
|
1693
|
+
if (expression === null || expression.trim() === '') {
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
// Evaluate the expression
|
|
1697
|
+
// Note: Using Function constructor (similar to color.ts line 185)
|
|
1698
|
+
var result = new Function('return ' + expression)();
|
|
1699
|
+
if (typeof result === 'number' && !isNaN(result)) {
|
|
1700
|
+
// Return as a number token in px
|
|
1701
|
+
return {
|
|
1702
|
+
type: 17 /* TokenType.NUMBER_TOKEN */,
|
|
1703
|
+
number: result,
|
|
1704
|
+
flags: FLAG_INTEGER
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
catch (e) {
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
return null;
|
|
1712
|
+
};
|
|
1613
1713
|
var parseLengthPercentageTuple = function (tokens) {
|
|
1614
1714
|
return tokens.length > 1 ? [tokens[0], tokens[1]] : [tokens[0]];
|
|
1615
1715
|
};
|
|
@@ -3350,7 +3450,20 @@
|
|
|
3350
3450
|
prefix: false,
|
|
3351
3451
|
parse: function (_context, tokens) {
|
|
3352
3452
|
return parseFunctionArgs(tokens)
|
|
3353
|
-
.map(function (values) {
|
|
3453
|
+
.map(function (values) {
|
|
3454
|
+
// Convert calc() to length-percentage tokens, keep other length-percentage as is
|
|
3455
|
+
return values
|
|
3456
|
+
.map(function (value) {
|
|
3457
|
+
if (isCalcFunction(value)) {
|
|
3458
|
+
// For calc() at parse time, we can't know the container size
|
|
3459
|
+
// So we evaluate with 0 context which will work for px-only calc()
|
|
3460
|
+
// Percentage-based calc() will need special handling
|
|
3461
|
+
return evaluateCalcToLengthPercentage(value, 0);
|
|
3462
|
+
}
|
|
3463
|
+
return isLengthPercentage(value) ? value : null;
|
|
3464
|
+
})
|
|
3465
|
+
.filter(function (v) { return v !== null; });
|
|
3466
|
+
})
|
|
3354
3467
|
.map(parseLengthPercentageTuple);
|
|
3355
3468
|
}
|
|
3356
3469
|
};
|
|
@@ -5706,7 +5819,19 @@
|
|
|
5706
5819
|
container.styles.isTransformed() ||
|
|
5707
5820
|
(isBodyElement(node) && root.styles.isTransparent()));
|
|
5708
5821
|
};
|
|
5709
|
-
var createsStackingContext = function (styles) {
|
|
5822
|
+
var createsStackingContext = function (styles) {
|
|
5823
|
+
// Positioned and floating elements create stacking contexts
|
|
5824
|
+
if (styles.isPositioned() || styles.isFloating()) {
|
|
5825
|
+
return true;
|
|
5826
|
+
}
|
|
5827
|
+
// Fix for Issue #137: Inline-level containers (inline-flex, inline-block, etc.)
|
|
5828
|
+
// should create stacking contexts to prevent their children from being added
|
|
5829
|
+
// to the parent's stacking context, which causes rendering order issues
|
|
5830
|
+
return (contains(styles.display, 268435456 /* DISPLAY.INLINE_FLEX */) ||
|
|
5831
|
+
contains(styles.display, 33554432 /* DISPLAY.INLINE_BLOCK */) ||
|
|
5832
|
+
contains(styles.display, 536870912 /* DISPLAY.INLINE_GRID */) ||
|
|
5833
|
+
contains(styles.display, 134217728 /* DISPLAY.INLINE_TABLE */));
|
|
5834
|
+
};
|
|
5710
5835
|
var isTextNode = function (node) { return node.nodeType === Node.TEXT_NODE; };
|
|
5711
5836
|
var isElementNode = function (node) { return node.nodeType === Node.ELEMENT_NODE; };
|
|
5712
5837
|
var isHTMLElementNode = function (node) {
|
|
@@ -6542,7 +6667,8 @@
|
|
|
6542
6667
|
// Edge does not provide value for cssText
|
|
6543
6668
|
for (var i = style.length - 1; i >= 0; i--) {
|
|
6544
6669
|
var property = style.item(i);
|
|
6545
|
-
|
|
6670
|
+
// fix: Chrome_138 ignore custom properties
|
|
6671
|
+
if (ignoredStyleProperties.indexOf(property) === -1 && !property.startsWith('--')) {
|
|
6546
6672
|
target.style.setProperty(property, style.getPropertyValue(property));
|
|
6547
6673
|
}
|
|
6548
6674
|
}
|
|
@@ -7068,8 +7194,9 @@
|
|
|
7068
7194
|
this.effects.push(new OpacityEffect(this.container.styles.opacity));
|
|
7069
7195
|
}
|
|
7070
7196
|
if (this.container.styles.rotate !== null) {
|
|
7071
|
-
var
|
|
7072
|
-
var
|
|
7197
|
+
var origin_1 = this.container.styles.transformOrigin;
|
|
7198
|
+
var offsetX = this.container.bounds.left + getAbsoluteValue(origin_1[0], this.container.bounds.width);
|
|
7199
|
+
var offsetY = this.container.bounds.top + getAbsoluteValue(origin_1[1], this.container.bounds.height);
|
|
7073
7200
|
// Apply rotate property if present
|
|
7074
7201
|
var angle = this.container.styles.rotate;
|
|
7075
7202
|
var rad = (angle * Math.PI) / 180;
|
|
@@ -7079,8 +7206,9 @@
|
|
|
7079
7206
|
this.effects.push(new TransformEffect(offsetX, offsetY, rotateMatrix));
|
|
7080
7207
|
}
|
|
7081
7208
|
if (this.container.styles.transform !== null) {
|
|
7082
|
-
var
|
|
7083
|
-
var
|
|
7209
|
+
var origin_2 = this.container.styles.transformOrigin;
|
|
7210
|
+
var offsetX = this.container.bounds.left + getAbsoluteValue(origin_2[0], this.container.bounds.width);
|
|
7211
|
+
var offsetY = this.container.bounds.top + getAbsoluteValue(origin_2[1], this.container.bounds.height);
|
|
7084
7212
|
var matrix = this.container.styles.transform;
|
|
7085
7213
|
this.effects.push(new TransformEffect(offsetX, offsetY, matrix));
|
|
7086
7214
|
}
|
|
@@ -7651,15 +7779,9 @@
|
|
|
7651
7779
|
CanvasRenderer.prototype.renderTextWithLetterSpacing = function (text, letterSpacing, baseline) {
|
|
7652
7780
|
var _this = this;
|
|
7653
7781
|
if (letterSpacing === 0) {
|
|
7654
|
-
//
|
|
7655
|
-
//
|
|
7656
|
-
|
|
7657
|
-
this.ctx.textBaseline = 'ideographic';
|
|
7658
|
-
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + text.bounds.height);
|
|
7659
|
-
}
|
|
7660
|
-
else {
|
|
7661
|
-
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
7662
|
-
}
|
|
7782
|
+
// Use alphabetic baseline for consistent text positioning across browsers
|
|
7783
|
+
// Issue #129: text.bounds.top + text.bounds.height causes text to render too low
|
|
7784
|
+
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
7663
7785
|
}
|
|
7664
7786
|
else {
|
|
7665
7787
|
var letters = segmentGraphemes(text.text);
|
|
@@ -7742,7 +7864,19 @@
|
|
|
7742
7864
|
_this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
7743
7865
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7744
7866
|
_this.ctx.lineJoin = !!window.chrome ? 'miter' : 'round';
|
|
7745
|
-
|
|
7867
|
+
// Issue #110: Use baseline (fontSize) for consistent positioning with fill
|
|
7868
|
+
// Previously used text.bounds.height which caused stroke to render too low
|
|
7869
|
+
var baseline_1 = styles.fontSize.number;
|
|
7870
|
+
if (styles.letterSpacing === 0) {
|
|
7871
|
+
_this.ctx.strokeText(text.text, text.bounds.left, text.bounds.top + baseline_1);
|
|
7872
|
+
}
|
|
7873
|
+
else {
|
|
7874
|
+
var letters = segmentGraphemes(text.text);
|
|
7875
|
+
letters.reduce(function (left, letter) {
|
|
7876
|
+
_this.ctx.strokeText(letter, left, text.bounds.top + baseline_1);
|
|
7877
|
+
return left + _this.ctx.measureText(letter).width;
|
|
7878
|
+
}, text.bounds.left);
|
|
7879
|
+
}
|
|
7746
7880
|
}
|
|
7747
7881
|
_this.ctx.strokeStyle = '';
|
|
7748
7882
|
_this.ctx.lineWidth = 0;
|