html2canvas-pro 2.3.8 → 2.4.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/dist/html2canvas-pro.cjs +46 -30
- package/dist/html2canvas-pro.cjs.map +1 -1
- package/dist/html2canvas-pro.esm.js +46 -30
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +46 -30
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +4 -4
- package/dist/lib/dom/document-cloner.js +10 -8
- package/dist/lib/render/canvas/canvas-renderer.js +11 -8
- package/dist/lib/render/canvas/content-renderer.js +22 -9
- package/dist/lib/render/canvas/font-utils.js +24 -7
- package/dist/types/render/canvas/content-renderer.d.ts +9 -0
- package/dist/types/render/canvas/font-utils.d.ts +10 -2
- package/package.json +1 -1
package/dist/html2canvas-pro.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.
|
|
2
|
+
* html2canvas-pro 2.4.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
|
*/
|
|
@@ -6987,19 +6987,18 @@ var DocumentCloner = class {
|
|
|
6987
6987
|
const documentClone = cloneWindow.document;
|
|
6988
6988
|
const iframeLoad = iframeLoader(iframe).then(async () => {
|
|
6989
6989
|
this.scrolledElements.forEach(restoreNodeScroll);
|
|
6990
|
-
if (cloneWindow)
|
|
6991
|
-
cloneWindow.scrollTo(windowSize.left, windowSize.top);
|
|
6992
|
-
if (/AppleWebKit/g.test(navigator.userAgent) && (cloneWindow.scrollY !== windowSize.top || cloneWindow.scrollX !== windowSize.left)) {
|
|
6993
|
-
this.context.logger.warn("Unable to restore scroll position for cloned document");
|
|
6994
|
-
this.context.windowBounds = this.context.windowBounds.add(cloneWindow.scrollX - windowSize.left, cloneWindow.scrollY - windowSize.top, 0, 0);
|
|
6995
|
-
}
|
|
6996
|
-
}
|
|
6990
|
+
if (cloneWindow) cloneWindow.scrollTo(windowSize.left, windowSize.top);
|
|
6997
6991
|
const onclone = this.options.onclone;
|
|
6998
6992
|
const referenceElement = this.clonedReferenceElement;
|
|
6999
6993
|
if (typeof referenceElement === "undefined") throw new Error(`Error finding the ${this.referenceElement.nodeName} in the cloned document`);
|
|
7000
6994
|
if (documentClone.fonts && documentClone.fonts.ready) await documentClone.fonts.ready;
|
|
7001
6995
|
if (/(AppleWebKit)/g.test(navigator.userAgent)) await imagesReady(documentClone);
|
|
7002
|
-
if (typeof onclone === "function")
|
|
6996
|
+
if (typeof onclone === "function") await Promise.resolve().then(() => onclone(documentClone, referenceElement));
|
|
6997
|
+
cloneWindow.scrollTo(windowSize.left, windowSize.top);
|
|
6998
|
+
if (/AppleWebKit/g.test(navigator.userAgent) && (cloneWindow.scrollY !== windowSize.top || cloneWindow.scrollX !== windowSize.left)) {
|
|
6999
|
+
this.context.logger.warn("Unable to restore scroll position for cloned document");
|
|
7000
|
+
this.context.windowBounds = this.context.windowBounds.add(cloneWindow.scrollX - windowSize.left, cloneWindow.scrollY - windowSize.top, 0, 0);
|
|
7001
|
+
}
|
|
7003
7002
|
return iframe;
|
|
7004
7003
|
});
|
|
7005
7004
|
/**
|
|
@@ -9089,8 +9088,8 @@ var TextDecorationRenderer = class {
|
|
|
9089
9088
|
/**
|
|
9090
9089
|
* Font measurement utility
|
|
9091
9090
|
*
|
|
9092
|
-
* Provides Canvas API-based
|
|
9093
|
-
*
|
|
9091
|
+
* Provides Canvas API-based font measurement that works correctly with webfonts
|
|
9092
|
+
* (which may not be loaded in the original document) and system fonts.
|
|
9094
9093
|
*
|
|
9095
9094
|
* Fallback chain:
|
|
9096
9095
|
* 1. fontBoundingBoxAscent — font-level metric (Chrome 99+, FF 116+, Safari 17.4+)
|
|
@@ -9098,6 +9097,18 @@ var TextDecorationRenderer = class {
|
|
|
9098
9097
|
* 3. fallback value — coarse CSS fallback
|
|
9099
9098
|
*/
|
|
9100
9099
|
const SAMPLE_TEXT = "Mg";
|
|
9100
|
+
const isValidMetric = (value) => value !== void 0 && !Number.isNaN(value);
|
|
9101
|
+
/**
|
|
9102
|
+
* Measure the baseline ascent and full font box for the currently set font.
|
|
9103
|
+
*/
|
|
9104
|
+
const measureFontMetrics = (ctx, fallback) => {
|
|
9105
|
+
const tm = ctx.measureText(SAMPLE_TEXT);
|
|
9106
|
+
const fontMetrics = tm;
|
|
9107
|
+
return {
|
|
9108
|
+
baseline: isValidMetric(fontMetrics.fontBoundingBoxAscent) ? fontMetrics.fontBoundingBoxAscent : isValidMetric(tm.actualBoundingBoxAscent) ? tm.actualBoundingBoxAscent : fallback,
|
|
9109
|
+
height: isValidMetric(fontMetrics.fontBoundingBoxAscent) && isValidMetric(fontMetrics.fontBoundingBoxDescent) ? fontMetrics.fontBoundingBoxAscent + fontMetrics.fontBoundingBoxDescent : isValidMetric(tm.actualBoundingBoxAscent) && isValidMetric(tm.actualBoundingBoxDescent) ? tm.actualBoundingBoxAscent + tm.actualBoundingBoxDescent : fallback
|
|
9110
|
+
};
|
|
9111
|
+
};
|
|
9101
9112
|
/**
|
|
9102
9113
|
* Measure the baseline ascent for the currently set font.
|
|
9103
9114
|
*
|
|
@@ -9106,10 +9117,7 @@ const SAMPLE_TEXT = "Mg";
|
|
|
9106
9117
|
* @returns The distance from the text baseline to the top of the bounding box
|
|
9107
9118
|
*/
|
|
9108
9119
|
const measureBaseline = (ctx, fallback) => {
|
|
9109
|
-
|
|
9110
|
-
const fmAscent = tm.fontBoundingBoxAscent;
|
|
9111
|
-
const ascent = fmAscent !== void 0 && !Number.isNaN(fmAscent) ? fmAscent : tm.actualBoundingBoxAscent;
|
|
9112
|
-
return ascent !== void 0 && !Number.isNaN(ascent) ? ascent : fallback;
|
|
9120
|
+
return measureFontMetrics(ctx, fallback).baseline;
|
|
9113
9121
|
};
|
|
9114
9122
|
//#endregion
|
|
9115
9123
|
//#region src/render/canvas/text-renderer.ts
|
|
@@ -10356,11 +10364,13 @@ function renderFormElements(ctx, textRenderer, pathFn, container, styles) {
|
|
|
10356
10364
|
if (isTextInputElement(container) && container.value.length) {
|
|
10357
10365
|
const [font] = textRenderer.createFontStyle(styles);
|
|
10358
10366
|
ctx.font = font;
|
|
10359
|
-
const
|
|
10367
|
+
const fontSizeValue = getAbsoluteValue(styles.fontSize, 0);
|
|
10368
|
+
const { baseline, height: fontHeight } = measureFontMetrics(ctx, fontSizeValue);
|
|
10360
10369
|
ctx.fillStyle = container instanceof InputElementContainer && container.isPlaceholder ? asString(PLACEHOLDER_COLOR) : asString(styles.color);
|
|
10361
10370
|
ctx.textBaseline = "alphabetic";
|
|
10362
10371
|
ctx.textAlign = canvasTextAlign(container.styles.textAlign);
|
|
10363
10372
|
const bounds = contentBox(container);
|
|
10373
|
+
const clipBounds = container instanceof InputElementContainer ? inputTextClipBounds(bounds, paddingBox(container), fontHeight) : bounds;
|
|
10364
10374
|
let x = 0;
|
|
10365
10375
|
switch (container.styles.textAlign) {
|
|
10366
10376
|
case 1:
|
|
@@ -10371,21 +10381,17 @@ function renderFormElements(ctx, textRenderer, pathFn, container, styles) {
|
|
|
10371
10381
|
break;
|
|
10372
10382
|
}
|
|
10373
10383
|
let verticalOffset = 0;
|
|
10374
|
-
if (container instanceof InputElementContainer)
|
|
10375
|
-
const fontSizeValue = getAbsoluteValue(styles.fontSize, 0);
|
|
10376
|
-
verticalOffset = (bounds.height - fontSizeValue) / 2;
|
|
10377
|
-
}
|
|
10384
|
+
if (container instanceof InputElementContainer) verticalOffset = (bounds.height - fontHeight) / 2;
|
|
10378
10385
|
const textBounds = bounds.add(x, verticalOffset, 0, 0);
|
|
10379
10386
|
ctx.save();
|
|
10380
10387
|
pathFn([
|
|
10381
|
-
new Vector(
|
|
10382
|
-
new Vector(
|
|
10383
|
-
new Vector(
|
|
10384
|
-
new Vector(
|
|
10388
|
+
new Vector(clipBounds.left, clipBounds.top),
|
|
10389
|
+
new Vector(clipBounds.left + clipBounds.width, clipBounds.top),
|
|
10390
|
+
new Vector(clipBounds.left + clipBounds.width, clipBounds.top + clipBounds.height),
|
|
10391
|
+
new Vector(clipBounds.left, clipBounds.top + clipBounds.height)
|
|
10385
10392
|
]);
|
|
10386
10393
|
ctx.clip();
|
|
10387
10394
|
const lines = wrapTextToWidth(ctx, container.value, bounds.width, styles.whiteSpace === "pre" || styles.whiteSpace === "nowrap");
|
|
10388
|
-
const fontSizeValue = getAbsoluteValue(styles.fontSize, 0);
|
|
10389
10395
|
const lineHeight = computeLineHeight(styles.lineHeight, fontSizeValue);
|
|
10390
10396
|
lines.forEach((line, index) => {
|
|
10391
10397
|
let lineX = textBounds.left;
|
|
@@ -10407,6 +10413,14 @@ function renderFormElements(ctx, textRenderer, pathFn, container, styles) {
|
|
|
10407
10413
|
}
|
|
10408
10414
|
}
|
|
10409
10415
|
/**
|
|
10416
|
+
* Native single-line inputs may paint value text into their padding area when
|
|
10417
|
+
* fixed height and vertical padding leave a content box shorter than the font.
|
|
10418
|
+
* Preserve the content box horizontally, but avoid clipping those glyphs to the
|
|
10419
|
+
* collapsed vertical content box.
|
|
10420
|
+
* @internal exported for testing
|
|
10421
|
+
*/
|
|
10422
|
+
const inputTextClipBounds = (contentBounds, inputPaddingBox, fontHeight) => contentBounds.height < fontHeight ? new Bounds(contentBounds.left, inputPaddingBox.top, contentBounds.width, inputPaddingBox.height) : contentBounds;
|
|
10423
|
+
/**
|
|
10410
10424
|
* Split text into lines that fit the given pixel width, preserving hard line
|
|
10411
10425
|
* breaks and (when wrapping is enabled) breaking at word boundaries — mirroring
|
|
10412
10426
|
* how a <textarea> lays out its value.
|
|
@@ -10602,11 +10616,13 @@ var CanvasRenderer = class CanvasRenderer {
|
|
|
10602
10616
|
}
|
|
10603
10617
|
mask(paths) {
|
|
10604
10618
|
this.ctx.beginPath();
|
|
10605
|
-
this.
|
|
10606
|
-
this.
|
|
10607
|
-
this.ctx.
|
|
10608
|
-
this.ctx.lineTo(
|
|
10609
|
-
this.ctx.lineTo(
|
|
10619
|
+
const x = this.options.x;
|
|
10620
|
+
const y = this.options.y;
|
|
10621
|
+
this.ctx.moveTo(x, y);
|
|
10622
|
+
this.ctx.lineTo(x + this.options.width, y);
|
|
10623
|
+
this.ctx.lineTo(x + this.options.width, y + this.options.height);
|
|
10624
|
+
this.ctx.lineTo(x, y + this.options.height);
|
|
10625
|
+
this.ctx.lineTo(x, y);
|
|
10610
10626
|
this.formatPath(paths.slice(0).reverse());
|
|
10611
10627
|
this.ctx.closePath();
|
|
10612
10628
|
}
|