@skrillex1224/playwright-toolkit 3.0.22 → 3.0.23
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/browser.js +232 -1
- package/dist/browser.js.map +3 -3
- package/dist/index.cjs +21 -626
- package/dist/index.cjs.map +3 -3
- package/dist/index.js +20 -625
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -256,7 +256,6 @@ var ActorInfo = {
|
|
|
256
256
|
name: "\u6587\u5FC3\u4E00\u8A00",
|
|
257
257
|
domain: "wenxin.baidu.com",
|
|
258
258
|
path: "/",
|
|
259
|
-
device: Device.Mobile,
|
|
260
259
|
share: {
|
|
261
260
|
mode: "custom",
|
|
262
261
|
prefix: "",
|
|
@@ -495,7 +494,6 @@ function createInternalLogger(moduleName, explicitLogger) {
|
|
|
495
494
|
|
|
496
495
|
// src/internals/screenshot.js
|
|
497
496
|
var import_delay = __toESM(require("delay"), 1);
|
|
498
|
-
var import_jimp = require("jimp");
|
|
499
497
|
|
|
500
498
|
// src/internals/constants.js
|
|
501
499
|
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
@@ -534,19 +532,9 @@ var FORCED_FULLPAGE_TYPE = "jpeg";
|
|
|
534
532
|
var FORCED_FULLPAGE_QUALITY = 50;
|
|
535
533
|
var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
|
|
536
534
|
var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
|
|
537
|
-
var STITCH_SCROLL_TARGET_ATTR = "data-pk-stitch-scroll-target";
|
|
538
535
|
var DEFAULT_MAX_HEIGHT = 8e3;
|
|
539
536
|
var DEFAULT_SETTLE_MS = 1e3;
|
|
540
537
|
var DEFAULT_MOBILE_SETTLE_MS = 50;
|
|
541
|
-
var DEFAULT_STITCH_SETTLE_MS = 120;
|
|
542
|
-
var DEFAULT_STITCH_OVERLAP_PX = 24;
|
|
543
|
-
var MIN_VIRTUALIZED_SCROLL_RATIO = 2.2;
|
|
544
|
-
var MIN_SPARSE_SCROLL_RATIO = 4;
|
|
545
|
-
var MOBILE_VIEWPORT_WIDTH_THRESHOLD = 520;
|
|
546
|
-
var DEFAULT_QUALITY_RETRY_ATTEMPTS = 2;
|
|
547
|
-
var DEFAULT_QUALITY_RETRY_DELAY_MS = 2500;
|
|
548
|
-
var MIN_TRAILING_BLANK_GAP_PX = 320;
|
|
549
|
-
var MIN_TRAILING_BLANK_GAP_RATIO = 0.12;
|
|
550
538
|
var toPositiveNumber = (value, fallback = 0) => {
|
|
551
539
|
const n = Number(value);
|
|
552
540
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
@@ -569,22 +557,7 @@ var normalizeQuality = (value, type) => {
|
|
|
569
557
|
if (rounded < 0 || rounded > 100) return void 0;
|
|
570
558
|
return rounded;
|
|
571
559
|
};
|
|
572
|
-
var resolvePageDevice =
|
|
573
|
-
const declared = normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
574
|
-
if (declared === Device.Mobile) return Device.Mobile;
|
|
575
|
-
const viewport = await resolveCurrentViewportSize(page).catch(() => null);
|
|
576
|
-
const viewportWidth = Math.round(Number(viewport?.width) || 0);
|
|
577
|
-
if (viewportWidth > 0 && viewportWidth <= MOBILE_VIEWPORT_WIDTH_THRESHOLD) {
|
|
578
|
-
return Device.Mobile;
|
|
579
|
-
}
|
|
580
|
-
return declared;
|
|
581
|
-
};
|
|
582
|
-
var resolveStitchMode = (options = {}) => {
|
|
583
|
-
const raw = options.stitch ?? options.stitching ?? options.strategy;
|
|
584
|
-
if (raw === false || raw === "off" || raw === "none" || raw === "single") return "off";
|
|
585
|
-
if (raw === true || raw === "force" || raw === "stitched") return "force";
|
|
586
|
-
return "auto";
|
|
587
|
-
};
|
|
560
|
+
var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
588
561
|
var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
589
562
|
const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
|
|
590
563
|
const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
|
|
@@ -931,156 +904,10 @@ var restoreAffixedElementsForExpandedScreenshot = async (page) => {
|
|
|
931
904
|
});
|
|
932
905
|
}, EXPANDED_SCROLLABLE_CLASS);
|
|
933
906
|
};
|
|
934
|
-
var measureMeaningfulContentBounds = async (page) => {
|
|
935
|
-
return await page.evaluate(() => {
|
|
936
|
-
const body = document.body;
|
|
937
|
-
if (!body) return null;
|
|
938
|
-
const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || body.clientWidth || 0;
|
|
939
|
-
const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || body.clientHeight || 0;
|
|
940
|
-
const scrollX = window.scrollX || window.pageXOffset || 0;
|
|
941
|
-
const scrollY = window.scrollY || window.pageYOffset || 0;
|
|
942
|
-
const bounds = {
|
|
943
|
-
left: Number.POSITIVE_INFINITY,
|
|
944
|
-
top: Number.POSITIVE_INFINITY,
|
|
945
|
-
right: 0,
|
|
946
|
-
bottom: 0,
|
|
947
|
-
nodes: 0
|
|
948
|
-
};
|
|
949
|
-
const isVisible = (el, style, rect) => {
|
|
950
|
-
if (!el || !style || !rect) return false;
|
|
951
|
-
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") return false;
|
|
952
|
-
if (Number(style.opacity) === 0) return false;
|
|
953
|
-
return rect.width > 1 && rect.height > 1;
|
|
954
|
-
};
|
|
955
|
-
const hasFixedAncestor = (el) => {
|
|
956
|
-
for (let node = el; node && node.nodeType === 1; node = node.parentElement) {
|
|
957
|
-
const position = String(window.getComputedStyle(node).position || "").toLowerCase();
|
|
958
|
-
if (position === "fixed") {
|
|
959
|
-
return true;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
return false;
|
|
963
|
-
};
|
|
964
|
-
const parseRgbColor = (value) => {
|
|
965
|
-
const raw = String(value || "").trim();
|
|
966
|
-
const match = raw.match(/rgba?\(([^)]+)\)/i);
|
|
967
|
-
if (!match) return null;
|
|
968
|
-
const parts = match[1].replace(/\//g, " ").split(/[,\s]+/).map((part) => part.trim()).filter(Boolean);
|
|
969
|
-
if (parts.length < 3) return null;
|
|
970
|
-
const normalizeChannel = (part) => {
|
|
971
|
-
if (part.endsWith("%")) {
|
|
972
|
-
return Math.max(0, Math.min(255, Number.parseFloat(part) * 2.55));
|
|
973
|
-
}
|
|
974
|
-
return Math.max(0, Math.min(255, Number.parseFloat(part)));
|
|
975
|
-
};
|
|
976
|
-
const alpha = parts.length >= 4 ? parts[3].endsWith("%") ? Number.parseFloat(parts[3]) / 100 : Number.parseFloat(parts[3]) : 1;
|
|
977
|
-
return {
|
|
978
|
-
r: normalizeChannel(parts[0]),
|
|
979
|
-
g: normalizeChannel(parts[1]),
|
|
980
|
-
b: normalizeChannel(parts[2]),
|
|
981
|
-
a: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1
|
|
982
|
-
};
|
|
983
|
-
};
|
|
984
|
-
const colorLuminance = (color) => {
|
|
985
|
-
const channel = (value) => {
|
|
986
|
-
const ratio = Math.max(0, Math.min(255, value)) / 255;
|
|
987
|
-
return ratio <= 0.03928 ? ratio / 12.92 : ((ratio + 0.055) / 1.055) ** 2.4;
|
|
988
|
-
};
|
|
989
|
-
return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);
|
|
990
|
-
};
|
|
991
|
-
const contrastRatio = (a, b) => {
|
|
992
|
-
const l1 = colorLuminance(a);
|
|
993
|
-
const l2 = colorLuminance(b);
|
|
994
|
-
const lighter = Math.max(l1, l2);
|
|
995
|
-
const darker = Math.min(l1, l2);
|
|
996
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
997
|
-
};
|
|
998
|
-
const resolveBackgroundColor = (el) => {
|
|
999
|
-
for (let node = el; node && node.nodeType === 1; node = node.parentElement) {
|
|
1000
|
-
const background = parseRgbColor(window.getComputedStyle(node).backgroundColor);
|
|
1001
|
-
if (background && background.a > 0.2) {
|
|
1002
|
-
return background;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
return { r: 255, g: 255, b: 255, a: 1 };
|
|
1006
|
-
};
|
|
1007
|
-
const isLowInformationTextPaint = (el, style) => {
|
|
1008
|
-
const color = parseRgbColor(style?.color);
|
|
1009
|
-
if (!color) return false;
|
|
1010
|
-
const opacity = Number(style.opacity);
|
|
1011
|
-
if (color.a <= 0.08 || Number.isFinite(opacity) && opacity <= 0.18) {
|
|
1012
|
-
return true;
|
|
1013
|
-
}
|
|
1014
|
-
const max = Math.max(color.r, color.g, color.b);
|
|
1015
|
-
const min = Math.min(color.r, color.g, color.b);
|
|
1016
|
-
if (!(min >= 224 && max - min <= 24 && color.a >= 0.85)) {
|
|
1017
|
-
return false;
|
|
1018
|
-
}
|
|
1019
|
-
const background = resolveBackgroundColor(el);
|
|
1020
|
-
return colorLuminance(background) > 0.76 && contrastRatio(color, background) < 1.35;
|
|
1021
|
-
};
|
|
1022
|
-
const addRect = (rect) => {
|
|
1023
|
-
if (!rect || rect.width <= 1 || rect.height <= 1) return;
|
|
1024
|
-
const left = Math.max(0, Math.floor(rect.left + scrollX));
|
|
1025
|
-
const top = Math.max(0, Math.floor(rect.top + scrollY));
|
|
1026
|
-
const right = Math.ceil(rect.right + scrollX);
|
|
1027
|
-
const bottom = Math.ceil(rect.bottom + scrollY);
|
|
1028
|
-
if (right <= left || bottom <= top) return;
|
|
1029
|
-
bounds.left = Math.min(bounds.left, left);
|
|
1030
|
-
bounds.top = Math.min(bounds.top, top);
|
|
1031
|
-
bounds.right = Math.max(bounds.right, right);
|
|
1032
|
-
bounds.bottom = Math.max(bounds.bottom, bottom);
|
|
1033
|
-
bounds.nodes += 1;
|
|
1034
|
-
};
|
|
1035
|
-
const addElement = (el, { minArea = 12, text = false } = {}) => {
|
|
1036
|
-
if (!el || el.nodeType !== 1 || hasFixedAncestor(el)) return;
|
|
1037
|
-
const style = window.getComputedStyle(el);
|
|
1038
|
-
if (text && isLowInformationTextPaint(el, style)) return;
|
|
1039
|
-
const rects = Array.from(el.getClientRects ? el.getClientRects() : []);
|
|
1040
|
-
rects.forEach((rect) => {
|
|
1041
|
-
if (!isVisible(el, style, rect)) return;
|
|
1042
|
-
if (rect.width * rect.height < minArea) return;
|
|
1043
|
-
addRect(rect);
|
|
1044
|
-
});
|
|
1045
|
-
};
|
|
1046
|
-
const walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT);
|
|
1047
|
-
let visitedTextNodes = 0;
|
|
1048
|
-
while (walker.nextNode() && visitedTextNodes < 6e3) {
|
|
1049
|
-
const node = walker.currentNode;
|
|
1050
|
-
visitedTextNodes += 1;
|
|
1051
|
-
const text = String(node.nodeValue || "").replace(/\s+/g, " ").trim();
|
|
1052
|
-
if (text.length < 2) continue;
|
|
1053
|
-
addElement(node.parentElement, { minArea: 8, text: true });
|
|
1054
|
-
}
|
|
1055
|
-
document.querySelectorAll("img,video,canvas,svg,picture").forEach((el) => {
|
|
1056
|
-
addElement(el, { minArea: 900 });
|
|
1057
|
-
});
|
|
1058
|
-
if (!bounds.nodes || !Number.isFinite(bounds.left)) return null;
|
|
1059
|
-
const paddingX = Math.max(16, Math.min(96, viewportWidth * 0.04));
|
|
1060
|
-
const paddingY = Math.max(24, Math.min(160, viewportHeight * 0.18));
|
|
1061
|
-
return {
|
|
1062
|
-
left: Math.max(0, Math.floor(bounds.left - paddingX)),
|
|
1063
|
-
top: Math.max(0, Math.floor(bounds.top - paddingY)),
|
|
1064
|
-
right: Math.ceil(bounds.right + paddingX),
|
|
1065
|
-
bottom: Math.ceil(bounds.bottom + paddingY),
|
|
1066
|
-
width: Math.max(1, Math.ceil(bounds.right - bounds.left)),
|
|
1067
|
-
height: Math.max(1, Math.ceil(bounds.bottom - bounds.top)),
|
|
1068
|
-
nodes: bounds.nodes,
|
|
1069
|
-
viewport: {
|
|
1070
|
-
width: Math.max(1, Math.ceil(viewportWidth || 1)),
|
|
1071
|
-
height: Math.max(1, Math.ceil(viewportHeight || 1))
|
|
1072
|
-
}
|
|
1073
|
-
};
|
|
1074
|
-
}).catch((error) => {
|
|
1075
|
-
logger.warning(`\u622A\u56FE\u5185\u5BB9\u8FB9\u754C\u6D4B\u91CF\u5931\u8D25: ${error?.message || error}`);
|
|
1076
|
-
return null;
|
|
1077
|
-
});
|
|
1078
|
-
};
|
|
1079
907
|
var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
1080
908
|
const originalViewport = await resolveCurrentViewportSize(page);
|
|
1081
909
|
const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
|
|
1082
|
-
const
|
|
1083
|
-
const preserveViewport = options.preserveViewport ?? device === Device.Mobile;
|
|
910
|
+
const preserveViewport = options.preserveViewport ?? resolvePageDevice(page) === Device.Mobile;
|
|
1084
911
|
const defaultSettleMs = preserveViewport ? DEFAULT_MOBILE_SETTLE_MS : DEFAULT_SETTLE_MS;
|
|
1085
912
|
const requestedSettleMs = Math.max(0, Number(options.settleMs ?? defaultSettleMs) || 0);
|
|
1086
913
|
const settleMs = preserveViewport ? Math.min(requestedSettleMs, DEFAULT_MOBILE_SETTLE_MS) : requestedSettleMs;
|
|
@@ -1089,21 +916,7 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
|
1089
916
|
visibleOnly: options.visibleOnly !== false,
|
|
1090
917
|
expandDocumentElements: preserveViewport
|
|
1091
918
|
});
|
|
1092
|
-
const
|
|
1093
|
-
let targetHeight = Math.min(maxScrollHeight, maxHeight);
|
|
1094
|
-
if (contentBounds?.bottom > 0) {
|
|
1095
|
-
const contentBottom = Math.min(Math.ceil(contentBounds.bottom), maxHeight);
|
|
1096
|
-
const trailingGap = targetHeight - contentBottom;
|
|
1097
|
-
const minTrailingGap = Math.max(
|
|
1098
|
-
MIN_TRAILING_BLANK_GAP_PX,
|
|
1099
|
-
Math.floor(targetHeight * MIN_TRAILING_BLANK_GAP_RATIO),
|
|
1100
|
-
Math.floor(originalViewport.height * 0.45)
|
|
1101
|
-
);
|
|
1102
|
-
if (trailingGap >= minTrailingGap && contentBottom >= originalViewport.height * 0.65) {
|
|
1103
|
-
targetHeight = Math.max(1, contentBottom);
|
|
1104
|
-
logger.info(`\u957F\u622A\u56FE\u88C1\u6389\u4F4E\u4FE1\u606F\u5C3E\u90E8: contentBottom=${contentBottom}, originalHeight=${Math.min(maxScrollHeight, maxHeight)}`);
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
919
|
+
const targetHeight = Math.min(maxScrollHeight, maxHeight);
|
|
1107
920
|
let viewportResized = false;
|
|
1108
921
|
if (!preserveViewport) {
|
|
1109
922
|
await page.setViewportSize({
|
|
@@ -1123,7 +936,6 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
|
1123
936
|
originalViewport,
|
|
1124
937
|
maxScrollHeight,
|
|
1125
938
|
targetHeight,
|
|
1126
|
-
contentBounds,
|
|
1127
939
|
preserveViewport,
|
|
1128
940
|
viewportResized
|
|
1129
941
|
};
|
|
@@ -1156,411 +968,6 @@ var restoreExpandedFullPageScreenshot = async (page, state2 = {}) => {
|
|
|
1156
968
|
await page.setViewportSize(state2.originalViewport);
|
|
1157
969
|
}
|
|
1158
970
|
};
|
|
1159
|
-
var resolveVirtualizedScrollTarget = async (page, options = {}) => {
|
|
1160
|
-
const stitchMode = resolveStitchMode(options);
|
|
1161
|
-
if (stitchMode === "off") return null;
|
|
1162
|
-
const device = await resolvePageDevice(page);
|
|
1163
|
-
if (stitchMode !== "force" && device !== Device.Mobile) {
|
|
1164
|
-
return null;
|
|
1165
|
-
}
|
|
1166
|
-
return await page.evaluate((config) => {
|
|
1167
|
-
const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0;
|
|
1168
|
-
const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0;
|
|
1169
|
-
const root = document.documentElement;
|
|
1170
|
-
const body = document.body;
|
|
1171
|
-
const scrollingElement = document.scrollingElement;
|
|
1172
|
-
const candidates = [];
|
|
1173
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1174
|
-
const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
|
|
1175
|
-
const clippingOverflow = /* @__PURE__ */ new Set(["hidden", "clip"]);
|
|
1176
|
-
const pushCandidate = (el2) => {
|
|
1177
|
-
if (!el2 || seen.has(el2)) return;
|
|
1178
|
-
seen.add(el2);
|
|
1179
|
-
candidates.push(el2);
|
|
1180
|
-
};
|
|
1181
|
-
pushCandidate(scrollingElement);
|
|
1182
|
-
pushCandidate(root);
|
|
1183
|
-
pushCandidate(body);
|
|
1184
|
-
document.querySelectorAll("*").forEach(pushCandidate);
|
|
1185
|
-
const isDocumentElement = (el2) => el2 === root || el2 === body || el2 === scrollingElement;
|
|
1186
|
-
const isVisible = (el2, style, rect) => {
|
|
1187
|
-
if (!el2 || !style || !rect) return false;
|
|
1188
|
-
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") return false;
|
|
1189
|
-
if (Number(style.opacity) === 0) return false;
|
|
1190
|
-
return rect.width > 0 && rect.height > 0;
|
|
1191
|
-
};
|
|
1192
|
-
const hasOverflowValue = (style, values) => {
|
|
1193
|
-
const overflowY = String(style?.overflowY || "").toLowerCase();
|
|
1194
|
-
const overflow = String(style?.overflow || "").toLowerCase();
|
|
1195
|
-
return values.has(overflowY) || values.has(overflow);
|
|
1196
|
-
};
|
|
1197
|
-
const looksScrollable = (el2, style) => {
|
|
1198
|
-
if (!el2 || el2.scrollHeight <= el2.clientHeight + 1) return false;
|
|
1199
|
-
if (isDocumentElement(el2)) return true;
|
|
1200
|
-
return hasOverflowValue(style, scrollableOverflow) || hasOverflowValue(style, clippingOverflow);
|
|
1201
|
-
};
|
|
1202
|
-
const textHeightFor = (el2) => {
|
|
1203
|
-
const nodes = isDocumentElement(el2) ? document.querySelectorAll("body *") : el2.querySelectorAll("*");
|
|
1204
|
-
let textHeight = 0;
|
|
1205
|
-
let textNodes = 0;
|
|
1206
|
-
const maxNodes = 3500;
|
|
1207
|
-
for (const node of nodes) {
|
|
1208
|
-
if (textNodes >= maxNodes) break;
|
|
1209
|
-
const text = String(node.textContent || "").replace(/\s+/g, " ").trim();
|
|
1210
|
-
if (text.length < 2) continue;
|
|
1211
|
-
let childHasText = false;
|
|
1212
|
-
for (const child of node.children || []) {
|
|
1213
|
-
if (String(child.textContent || "").replace(/\s+/g, " ").trim().length >= 2) {
|
|
1214
|
-
childHasText = true;
|
|
1215
|
-
break;
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
if (childHasText) continue;
|
|
1219
|
-
const style = window.getComputedStyle(node);
|
|
1220
|
-
const rect = node.getBoundingClientRect();
|
|
1221
|
-
if (!isVisible(node, style, rect)) continue;
|
|
1222
|
-
textNodes += 1;
|
|
1223
|
-
textHeight += Math.min(Math.ceil(rect.height || 0), 900);
|
|
1224
|
-
}
|
|
1225
|
-
return { textHeight, textNodes };
|
|
1226
|
-
};
|
|
1227
|
-
const resolveEdgeOcclusion = () => {
|
|
1228
|
-
let top = 0;
|
|
1229
|
-
let bottom = 0;
|
|
1230
|
-
const maxHeight = Math.max(48, viewportHeight * 0.45);
|
|
1231
|
-
document.querySelectorAll("*").forEach((el2) => {
|
|
1232
|
-
const style = window.getComputedStyle(el2);
|
|
1233
|
-
const position = String(style.position || "").toLowerCase();
|
|
1234
|
-
if (position !== "fixed" && position !== "sticky") return;
|
|
1235
|
-
const rect = el2.getBoundingClientRect();
|
|
1236
|
-
if (!isVisible(el2, style, rect)) return;
|
|
1237
|
-
if (rect.height <= 0 || rect.height > maxHeight) return;
|
|
1238
|
-
if (rect.width < viewportWidth * 0.35) return;
|
|
1239
|
-
if (rect.top <= Math.max(16, viewportHeight * 0.08)) {
|
|
1240
|
-
top = Math.max(top, Math.ceil(rect.bottom));
|
|
1241
|
-
}
|
|
1242
|
-
if (rect.bottom >= viewportHeight - Math.max(16, viewportHeight * 0.08)) {
|
|
1243
|
-
bottom = Math.max(bottom, Math.ceil(viewportHeight - rect.top));
|
|
1244
|
-
}
|
|
1245
|
-
});
|
|
1246
|
-
return {
|
|
1247
|
-
top: Math.max(0, Math.min(Math.ceil(top), Math.floor(viewportHeight * 0.45))),
|
|
1248
|
-
bottom: Math.max(0, Math.min(Math.ceil(bottom), Math.floor(viewportHeight * 0.45)))
|
|
1249
|
-
};
|
|
1250
|
-
};
|
|
1251
|
-
let best = null;
|
|
1252
|
-
candidates.forEach((el2) => {
|
|
1253
|
-
const style = window.getComputedStyle(el2);
|
|
1254
|
-
const rect = isDocumentElement(el2) ? {
|
|
1255
|
-
top: 0,
|
|
1256
|
-
bottom: viewportHeight,
|
|
1257
|
-
left: 0,
|
|
1258
|
-
right: viewportWidth,
|
|
1259
|
-
width: viewportWidth,
|
|
1260
|
-
height: viewportHeight
|
|
1261
|
-
} : el2.getBoundingClientRect();
|
|
1262
|
-
if (!isDocumentElement(el2) && !isVisible(el2, style, rect)) return;
|
|
1263
|
-
if (!looksScrollable(el2, style)) return;
|
|
1264
|
-
const scrollHeight = Math.ceil(el2.scrollHeight || 0);
|
|
1265
|
-
const clientHeight = Math.ceil(el2.clientHeight || viewportHeight || 0);
|
|
1266
|
-
if (scrollHeight < Math.max(900, clientHeight * config.minScrollRatio)) return;
|
|
1267
|
-
const { textHeight, textNodes } = textHeightFor(el2);
|
|
1268
|
-
const sparseRatio = scrollHeight / Math.max(1, textHeight);
|
|
1269
|
-
const sparse = config.force || textNodes > 0 && sparseRatio >= config.minSparseRatio && scrollHeight - textHeight > clientHeight;
|
|
1270
|
-
if (!sparse) return;
|
|
1271
|
-
const visibleWidth = Math.max(1, Math.ceil(rect.width || viewportWidth || 1));
|
|
1272
|
-
const score2 = scrollHeight * Math.min(visibleWidth, viewportWidth || visibleWidth);
|
|
1273
|
-
if (!best || score2 > best.score) {
|
|
1274
|
-
best = {
|
|
1275
|
-
el: el2,
|
|
1276
|
-
score: score2,
|
|
1277
|
-
kind: isDocumentElement(el2) ? "document" : "element",
|
|
1278
|
-
scrollHeight,
|
|
1279
|
-
clientHeight,
|
|
1280
|
-
scrollTop: Math.max(0, Math.round(el2.scrollTop || 0)),
|
|
1281
|
-
rect: {
|
|
1282
|
-
top: Math.max(0, Math.round(rect.top || 0)),
|
|
1283
|
-
bottom: Math.min(viewportHeight, Math.round(rect.bottom || viewportHeight)),
|
|
1284
|
-
left: Math.max(0, Math.round(rect.left || 0)),
|
|
1285
|
-
width: Math.max(1, Math.round(rect.width || viewportWidth || 1)),
|
|
1286
|
-
height: Math.max(1, Math.round(rect.height || viewportHeight || 1))
|
|
1287
|
-
},
|
|
1288
|
-
textHeight,
|
|
1289
|
-
textNodes,
|
|
1290
|
-
sparseRatio
|
|
1291
|
-
};
|
|
1292
|
-
}
|
|
1293
|
-
});
|
|
1294
|
-
if (!best) return null;
|
|
1295
|
-
document.querySelectorAll(`[${config.attrName}="1"]`).forEach((node) => {
|
|
1296
|
-
node.removeAttribute(config.attrName);
|
|
1297
|
-
});
|
|
1298
|
-
if (best.kind === "element") {
|
|
1299
|
-
best.el.setAttribute(config.attrName, "1");
|
|
1300
|
-
}
|
|
1301
|
-
const { el, score, ...target } = best;
|
|
1302
|
-
return {
|
|
1303
|
-
...target,
|
|
1304
|
-
viewport: {
|
|
1305
|
-
width: Math.max(1, Math.ceil(viewportWidth || best.rect.width || 1)),
|
|
1306
|
-
height: Math.max(1, Math.ceil(viewportHeight || best.rect.height || 1))
|
|
1307
|
-
},
|
|
1308
|
-
edgeOcclusion: resolveEdgeOcclusion()
|
|
1309
|
-
};
|
|
1310
|
-
}, {
|
|
1311
|
-
attrName: STITCH_SCROLL_TARGET_ATTR,
|
|
1312
|
-
force: stitchMode === "force",
|
|
1313
|
-
minScrollRatio: MIN_VIRTUALIZED_SCROLL_RATIO,
|
|
1314
|
-
minSparseRatio: MIN_SPARSE_SCROLL_RATIO
|
|
1315
|
-
}).catch((error) => {
|
|
1316
|
-
logger.warning(`\u865A\u62DF\u6EDA\u52A8\u622A\u56FE\u63A2\u6D4B\u5931\u8D25: ${error?.message || error}`);
|
|
1317
|
-
return null;
|
|
1318
|
-
});
|
|
1319
|
-
};
|
|
1320
|
-
var setStitchScrollTop = async (page, target, scrollTop) => {
|
|
1321
|
-
await page.evaluate(({ attrName, kind, top }) => {
|
|
1322
|
-
const el = kind === "document" ? document.scrollingElement || document.documentElement || document.body : document.querySelector(`[${attrName}="1"]`);
|
|
1323
|
-
if (!el) return;
|
|
1324
|
-
el.scrollTop = Math.max(0, Math.round(Number(top) || 0));
|
|
1325
|
-
el.dispatchEvent(new Event("scroll", { bubbles: true }));
|
|
1326
|
-
window.dispatchEvent(new Event("scroll"));
|
|
1327
|
-
}, {
|
|
1328
|
-
attrName: STITCH_SCROLL_TARGET_ATTR,
|
|
1329
|
-
kind: target.kind,
|
|
1330
|
-
top: scrollTop
|
|
1331
|
-
});
|
|
1332
|
-
};
|
|
1333
|
-
var cleanupStitchTarget = async (page) => {
|
|
1334
|
-
await page.evaluate((attrName) => {
|
|
1335
|
-
document.querySelectorAll(`[${attrName}="1"]`).forEach((node) => {
|
|
1336
|
-
node.removeAttribute(attrName);
|
|
1337
|
-
});
|
|
1338
|
-
}, STITCH_SCROLL_TARGET_ATTR).catch(() => {
|
|
1339
|
-
});
|
|
1340
|
-
};
|
|
1341
|
-
var cropImage = (image, crop) => image.clone().crop({
|
|
1342
|
-
x: Math.max(0, Math.round(crop.x || 0)),
|
|
1343
|
-
y: Math.max(0, Math.round(crop.y || 0)),
|
|
1344
|
-
w: Math.max(1, Math.round(crop.w || 1)),
|
|
1345
|
-
h: Math.max(1, Math.round(crop.h || 1))
|
|
1346
|
-
});
|
|
1347
|
-
var captureStitchedScrollableScreenshot = async (page, target, options = {}) => {
|
|
1348
|
-
const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
|
|
1349
|
-
const settleMs = Math.max(0, Number(options.stitchSettleMs ?? DEFAULT_STITCH_SETTLE_MS) || 0);
|
|
1350
|
-
const overlapPx = Math.max(0, Math.round(Number(options.stitchOverlapPx ?? DEFAULT_STITCH_OVERLAP_PX) || 0));
|
|
1351
|
-
const viewport = target.viewport || await resolveCurrentViewportSize(page);
|
|
1352
|
-
const rect = target.rect || {
|
|
1353
|
-
top: 0,
|
|
1354
|
-
bottom: viewport.height,
|
|
1355
|
-
left: 0,
|
|
1356
|
-
width: viewport.width,
|
|
1357
|
-
height: viewport.height
|
|
1358
|
-
};
|
|
1359
|
-
const edge = target.edgeOcclusion || { top: 0, bottom: 0 };
|
|
1360
|
-
const topCrop = Math.max(0, Math.min(rect.top, viewport.height - 1));
|
|
1361
|
-
const topOverlay = Math.max(topCrop, Math.min(edge.top || 0, viewport.height - 1));
|
|
1362
|
-
const bottomOverlay = Math.max(0, Math.min(edge.bottom || 0, viewport.height - topOverlay - 1));
|
|
1363
|
-
const middleCropY = Math.max(topCrop, topOverlay);
|
|
1364
|
-
const middleCropBottom = Math.max(
|
|
1365
|
-
middleCropY + 1,
|
|
1366
|
-
Math.min(rect.bottom || viewport.height, viewport.height - bottomOverlay)
|
|
1367
|
-
);
|
|
1368
|
-
const middleCropHeight = Math.max(1, middleCropBottom - middleCropY);
|
|
1369
|
-
const scrollStep = Math.max(120, middleCropHeight - overlapPx);
|
|
1370
|
-
const maxScrollTop = Math.max(0, Math.ceil(target.scrollHeight - target.clientHeight));
|
|
1371
|
-
const positions = [];
|
|
1372
|
-
for (let top = 0; top < maxScrollTop; top += scrollStep) {
|
|
1373
|
-
positions.push(Math.round(top));
|
|
1374
|
-
}
|
|
1375
|
-
if (!positions.includes(maxScrollTop)) {
|
|
1376
|
-
positions.push(maxScrollTop);
|
|
1377
|
-
}
|
|
1378
|
-
if (positions.length === 0) {
|
|
1379
|
-
positions.push(0);
|
|
1380
|
-
}
|
|
1381
|
-
const segments = [];
|
|
1382
|
-
let totalHeight = 0;
|
|
1383
|
-
let outputWidth = Math.max(1, Math.round(viewport.width || rect.width || 1));
|
|
1384
|
-
try {
|
|
1385
|
-
for (let index = 0; index < positions.length && totalHeight < maxHeight; index += 1) {
|
|
1386
|
-
const isFirst = index === 0;
|
|
1387
|
-
const isLast = index === positions.length - 1;
|
|
1388
|
-
await setStitchScrollTop(page, target, positions[index]);
|
|
1389
|
-
if (settleMs > 0) {
|
|
1390
|
-
await (0, import_delay.default)(settleMs);
|
|
1391
|
-
}
|
|
1392
|
-
const buffer = await capturePageScreenshot(page, {
|
|
1393
|
-
type: options.type || "png",
|
|
1394
|
-
quality: options.quality,
|
|
1395
|
-
timeout: options.timeout
|
|
1396
|
-
});
|
|
1397
|
-
const image = await import_jimp.Jimp.read(buffer);
|
|
1398
|
-
outputWidth = Math.min(outputWidth, image.bitmap.width);
|
|
1399
|
-
const cropY = isFirst ? 0 : middleCropY;
|
|
1400
|
-
const cropBottom = isLast ? image.bitmap.height : middleCropBottom;
|
|
1401
|
-
let cropHeight = Math.max(1, Math.min(image.bitmap.height, cropBottom) - cropY);
|
|
1402
|
-
const remaining = maxHeight - totalHeight;
|
|
1403
|
-
if (cropHeight > remaining) {
|
|
1404
|
-
cropHeight = remaining;
|
|
1405
|
-
}
|
|
1406
|
-
segments.push(cropImage(image, {
|
|
1407
|
-
x: 0,
|
|
1408
|
-
y: cropY,
|
|
1409
|
-
w: outputWidth,
|
|
1410
|
-
h: cropHeight
|
|
1411
|
-
}));
|
|
1412
|
-
totalHeight += cropHeight;
|
|
1413
|
-
}
|
|
1414
|
-
const canvas = new import_jimp.Jimp({
|
|
1415
|
-
width: outputWidth,
|
|
1416
|
-
height: Math.max(1, totalHeight),
|
|
1417
|
-
color: 4294967295
|
|
1418
|
-
});
|
|
1419
|
-
let y = 0;
|
|
1420
|
-
for (const segment of segments) {
|
|
1421
|
-
canvas.composite(segment, 0, y);
|
|
1422
|
-
y += segment.bitmap.height;
|
|
1423
|
-
}
|
|
1424
|
-
logger.info(
|
|
1425
|
-
`\u865A\u62DF\u6EDA\u52A8\u5206\u6BB5\u622A\u56FE: segments=${segments.length}, height=${totalHeight}, scrollHeight=${target.scrollHeight}, textNodes=${target.textNodes}, sparseRatio=${Number(target.sparseRatio || 0).toFixed(2)}`
|
|
1426
|
-
);
|
|
1427
|
-
return await canvas.getBuffer(import_jimp.JimpMime.png);
|
|
1428
|
-
} finally {
|
|
1429
|
-
await setStitchScrollTop(page, target, target.scrollTop || 0).catch(() => {
|
|
1430
|
-
});
|
|
1431
|
-
await cleanupStitchTarget(page);
|
|
1432
|
-
}
|
|
1433
|
-
};
|
|
1434
|
-
var isLightBlankPixel = ({ r, g, b }) => {
|
|
1435
|
-
const max = Math.max(r, g, b);
|
|
1436
|
-
const min = Math.min(r, g, b);
|
|
1437
|
-
return max >= 238 && max - min <= 18;
|
|
1438
|
-
};
|
|
1439
|
-
var isDarkBlankPixel = ({ r, g, b }) => {
|
|
1440
|
-
const max = Math.max(r, g, b);
|
|
1441
|
-
const min = Math.min(r, g, b);
|
|
1442
|
-
return max <= 34 && max - min <= 10;
|
|
1443
|
-
};
|
|
1444
|
-
var isLowInfoPixel = ({ r, g, b }) => {
|
|
1445
|
-
const max = Math.max(r, g, b);
|
|
1446
|
-
const min = Math.min(r, g, b);
|
|
1447
|
-
return max - min <= 12;
|
|
1448
|
-
};
|
|
1449
|
-
var analyzeScreenshotBuffer = async (buffer) => {
|
|
1450
|
-
const image = await import_jimp.Jimp.read(buffer);
|
|
1451
|
-
const width = image.bitmap.width;
|
|
1452
|
-
const height = image.bitmap.height;
|
|
1453
|
-
const stepY = Math.max(1, Math.floor(height / 900));
|
|
1454
|
-
const stepX = Math.max(1, Math.floor(width / 420));
|
|
1455
|
-
const rows = [];
|
|
1456
|
-
let lightRows = 0;
|
|
1457
|
-
let darkRows = 0;
|
|
1458
|
-
let lowInfoRows = 0;
|
|
1459
|
-
let loadingLikeRows = 0;
|
|
1460
|
-
const rowFlags = [];
|
|
1461
|
-
for (let y = 0; y < height; y += stepY) {
|
|
1462
|
-
let light = 0;
|
|
1463
|
-
let dark = 0;
|
|
1464
|
-
let lowInfo = 0;
|
|
1465
|
-
let edge = 0;
|
|
1466
|
-
let count = 0;
|
|
1467
|
-
let prev = null;
|
|
1468
|
-
for (let x = 0; x < width; x += stepX) {
|
|
1469
|
-
const rgba = (0, import_jimp.intToRGBA)(image.getPixelColor(x, y));
|
|
1470
|
-
count += 1;
|
|
1471
|
-
if (isLightBlankPixel(rgba)) light += 1;
|
|
1472
|
-
if (isDarkBlankPixel(rgba)) dark += 1;
|
|
1473
|
-
if (isLowInfoPixel(rgba)) lowInfo += 1;
|
|
1474
|
-
if (prev) {
|
|
1475
|
-
const diff = Math.abs(rgba.r - prev.r) + Math.abs(rgba.g - prev.g) + Math.abs(rgba.b - prev.b);
|
|
1476
|
-
if (diff > 45) edge += 1;
|
|
1477
|
-
}
|
|
1478
|
-
prev = rgba;
|
|
1479
|
-
}
|
|
1480
|
-
const stat = {
|
|
1481
|
-
y,
|
|
1482
|
-
lightRatio: light / Math.max(1, count),
|
|
1483
|
-
darkRatio: dark / Math.max(1, count),
|
|
1484
|
-
lowInfoRatio: lowInfo / Math.max(1, count),
|
|
1485
|
-
edgeRatio: edge / Math.max(1, count - 1)
|
|
1486
|
-
};
|
|
1487
|
-
rows.push(stat);
|
|
1488
|
-
const lightBlank = stat.lightRatio >= 0.965 && stat.edgeRatio <= 0.015;
|
|
1489
|
-
const darkBlank = stat.darkRatio >= 0.965 && stat.edgeRatio <= 0.012;
|
|
1490
|
-
const lowInfoBlank = stat.lowInfoRatio >= 0.965 && stat.edgeRatio <= 0.012;
|
|
1491
|
-
const loadingLike = stat.darkRatio >= 0.88 && stat.edgeRatio <= 0.025;
|
|
1492
|
-
if (lightBlank) lightRows += 1;
|
|
1493
|
-
if (darkBlank) darkRows += 1;
|
|
1494
|
-
if (lowInfoBlank) lowInfoRows += 1;
|
|
1495
|
-
if (loadingLike) loadingLikeRows += 1;
|
|
1496
|
-
rowFlags.push({ lightBlank, darkBlank, lowInfoBlank, loadingLike });
|
|
1497
|
-
}
|
|
1498
|
-
const sampledRows = Math.max(1, rows.length);
|
|
1499
|
-
return {
|
|
1500
|
-
image,
|
|
1501
|
-
width,
|
|
1502
|
-
height,
|
|
1503
|
-
lightBlankRowsRatio: lightRows / sampledRows,
|
|
1504
|
-
darkBlankRowsRatio: darkRows / sampledRows,
|
|
1505
|
-
lowInfoRowsRatio: lowInfoRows / sampledRows,
|
|
1506
|
-
loadingLikeRowsRatio: loadingLikeRows / sampledRows,
|
|
1507
|
-
rowFlags
|
|
1508
|
-
};
|
|
1509
|
-
};
|
|
1510
|
-
var resolveScreenshotQualityIssue = (analysis) => {
|
|
1511
|
-
if (!analysis) return null;
|
|
1512
|
-
if (analysis.loadingLikeRowsRatio >= 0.92 || analysis.darkBlankRowsRatio >= 0.72) {
|
|
1513
|
-
return "loading-like-dark-screenshot";
|
|
1514
|
-
}
|
|
1515
|
-
return null;
|
|
1516
|
-
};
|
|
1517
|
-
var cropBufferToContentBounds = async (buffer, bounds, options = {}) => {
|
|
1518
|
-
if (!bounds || bounds.nodes <= 0) return buffer;
|
|
1519
|
-
const image = options.image || await import_jimp.Jimp.read(buffer);
|
|
1520
|
-
const width = image.bitmap.width;
|
|
1521
|
-
const height = image.bitmap.height;
|
|
1522
|
-
const safeLeft = Math.max(0, Math.min(width - 1, Math.floor(bounds.left || 0)));
|
|
1523
|
-
const safeRight = Math.max(safeLeft + 1, Math.min(width, Math.ceil(bounds.right || width)));
|
|
1524
|
-
const safeTop = Math.max(0, Math.min(height - 1, Math.floor(bounds.top || 0)));
|
|
1525
|
-
const safeBottom = Math.max(safeTop + 1, Math.min(height, Math.ceil(bounds.bottom || height)));
|
|
1526
|
-
const cropW = safeRight - safeLeft;
|
|
1527
|
-
const cropH = safeBottom - safeTop;
|
|
1528
|
-
const shouldCropX = cropW > 80 && cropW <= width * 0.82 && (safeLeft > width * 0.04 || width - safeRight > width * 0.04);
|
|
1529
|
-
const shouldCropY = cropH > 160 && cropH <= height * 0.88 && height - safeBottom > Math.max(320, height * 0.1);
|
|
1530
|
-
if (!shouldCropX && !shouldCropY) {
|
|
1531
|
-
return buffer;
|
|
1532
|
-
}
|
|
1533
|
-
const x = shouldCropX ? safeLeft : 0;
|
|
1534
|
-
const y = shouldCropY ? safeTop : 0;
|
|
1535
|
-
const w = shouldCropX ? cropW : width;
|
|
1536
|
-
const h = shouldCropY ? cropH : height;
|
|
1537
|
-
logger.info(`\u5185\u5BB9\u611F\u77E5\u88C1\u526A\u622A\u56FE: x=${x}, y=${y}, w=${w}, h=${h}, original=${width}x${height}`);
|
|
1538
|
-
return await cropImage(image, { x, y, w, h }).getBuffer(import_jimp.JimpMime.png);
|
|
1539
|
-
};
|
|
1540
|
-
var captureExpandedFullPageScreenshotOnce = async (page, options = {}) => {
|
|
1541
|
-
const stitchedTarget = await resolveVirtualizedScrollTarget(page, options);
|
|
1542
|
-
if (stitchedTarget) {
|
|
1543
|
-
return await captureStitchedScrollableScreenshot(page, stitchedTarget, options);
|
|
1544
|
-
}
|
|
1545
|
-
const state2 = await prepareExpandedFullPageScreenshot(page, options);
|
|
1546
|
-
try {
|
|
1547
|
-
const buffer = await capturePageScreenshot(page, {
|
|
1548
|
-
fullPage: true,
|
|
1549
|
-
type: options.type || "png",
|
|
1550
|
-
quality: options.quality,
|
|
1551
|
-
timeout: options.timeout,
|
|
1552
|
-
maxClipHeight: state2.targetHeight
|
|
1553
|
-
});
|
|
1554
|
-
return await cropBufferToContentBounds(buffer, state2.contentBounds);
|
|
1555
|
-
} finally {
|
|
1556
|
-
await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
|
|
1557
|
-
logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
|
|
1558
|
-
});
|
|
1559
|
-
if (options.restore) {
|
|
1560
|
-
await restoreExpandedFullPageScreenshot(page, state2);
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
};
|
|
1564
971
|
var capturePageScreenshot = async (page, options = {}) => {
|
|
1565
972
|
const fullPage = Boolean(options.fullPage);
|
|
1566
973
|
const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
|
|
@@ -1615,35 +1022,23 @@ var capturePageScreenshot = async (page, options = {}) => {
|
|
|
1615
1022
|
}
|
|
1616
1023
|
};
|
|
1617
1024
|
var captureExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
1618
|
-
const
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
logger.warning(`\u622A\u56FE\u8D28\u91CF\u5206\u6790\u5931\u8D25: ${error?.message || error}`);
|
|
1627
|
-
return null;
|
|
1025
|
+
const state2 = await prepareExpandedFullPageScreenshot(page, options);
|
|
1026
|
+
try {
|
|
1027
|
+
return await capturePageScreenshot(page, {
|
|
1028
|
+
fullPage: true,
|
|
1029
|
+
type: options.type || "png",
|
|
1030
|
+
quality: options.quality,
|
|
1031
|
+
timeout: options.timeout,
|
|
1032
|
+
maxClipHeight: state2.targetHeight
|
|
1628
1033
|
});
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
if (
|
|
1634
|
-
|
|
1635
|
-
}
|
|
1636
|
-
if (attempt < attempts && retryDelayMs > 0) {
|
|
1637
|
-
logger.warning(`\u622A\u56FE\u7591\u4F3C\u5F02\u5E38(${issue})\uFF0C\u7B49\u5F85\u540E\u91CD\u8BD5: attempt=${attempt}/${attempts}`);
|
|
1638
|
-
await (0, import_delay.default)(retryDelayMs);
|
|
1034
|
+
} finally {
|
|
1035
|
+
await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
|
|
1036
|
+
logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
|
|
1037
|
+
});
|
|
1038
|
+
if (options.restore) {
|
|
1039
|
+
await restoreExpandedFullPageScreenshot(page, state2);
|
|
1639
1040
|
}
|
|
1640
1041
|
}
|
|
1641
|
-
if (lastIssue && lastAnalysis) {
|
|
1642
|
-
logger.warning(
|
|
1643
|
-
`\u622A\u56FE\u8D28\u91CF\u4ECD\u5F02\u5E38(${lastIssue})\uFF0C\u8FD4\u56DE\u6700\u4F73\u53EF\u5F97\u7ED3\u679C: light=${lastAnalysis.lightBlankRowsRatio.toFixed(2)}, dark=${lastAnalysis.darkBlankRowsRatio.toFixed(2)}, loading=${lastAnalysis.loadingLikeRowsRatio.toFixed(2)}`
|
|
1644
|
-
);
|
|
1645
|
-
}
|
|
1646
|
-
return lastBuffer;
|
|
1647
1042
|
};
|
|
1648
1043
|
|
|
1649
1044
|
// src/errors.js
|
|
@@ -10320,7 +9715,7 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null, options = {
|
|
|
10320
9715
|
};
|
|
10321
9716
|
|
|
10322
9717
|
// src/internals/compression.js
|
|
10323
|
-
var
|
|
9718
|
+
var import_jimp = require("jimp");
|
|
10324
9719
|
var logger15 = createInternalLogger("Compression");
|
|
10325
9720
|
var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
|
|
10326
9721
|
var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
|
|
@@ -10387,10 +9782,10 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
|
|
|
10387
9782
|
image.resize({
|
|
10388
9783
|
w: width,
|
|
10389
9784
|
h: height,
|
|
10390
|
-
mode:
|
|
9785
|
+
mode: import_jimp.ResizeStrategy.BILINEAR
|
|
10391
9786
|
});
|
|
10392
9787
|
}
|
|
10393
|
-
const buffer = await image.getBuffer(
|
|
9788
|
+
const buffer = await image.getBuffer(import_jimp.JimpMime.jpeg, { quality });
|
|
10394
9789
|
return {
|
|
10395
9790
|
buffer,
|
|
10396
9791
|
bytes: getBase64BytesFromBuffer(buffer),
|
|
@@ -10402,7 +9797,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
|
|
|
10402
9797
|
};
|
|
10403
9798
|
};
|
|
10404
9799
|
var compressImageBuffer = async (buffer, compression) => {
|
|
10405
|
-
const sourceImage = await
|
|
9800
|
+
const sourceImage = await import_jimp.Jimp.read(buffer);
|
|
10406
9801
|
const maxQuality = toJpegQuality(compression.quality);
|
|
10407
9802
|
const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
|
|
10408
9803
|
let quality = maxQuality;
|