@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.js
CHANGED
|
@@ -229,7 +229,6 @@ var ActorInfo = {
|
|
|
229
229
|
name: "\u6587\u5FC3\u4E00\u8A00",
|
|
230
230
|
domain: "wenxin.baidu.com",
|
|
231
231
|
path: "/",
|
|
232
|
-
device: Device.Mobile,
|
|
233
232
|
share: {
|
|
234
233
|
mode: "custom",
|
|
235
234
|
prefix: "",
|
|
@@ -468,7 +467,6 @@ function createInternalLogger(moduleName, explicitLogger) {
|
|
|
468
467
|
|
|
469
468
|
// src/internals/screenshot.js
|
|
470
469
|
import delay from "delay";
|
|
471
|
-
import { Jimp, JimpMime, intToRGBA } from "jimp";
|
|
472
470
|
|
|
473
471
|
// src/internals/constants.js
|
|
474
472
|
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
@@ -507,19 +505,9 @@ var FORCED_FULLPAGE_TYPE = "jpeg";
|
|
|
507
505
|
var FORCED_FULLPAGE_QUALITY = 50;
|
|
508
506
|
var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
|
|
509
507
|
var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
|
|
510
|
-
var STITCH_SCROLL_TARGET_ATTR = "data-pk-stitch-scroll-target";
|
|
511
508
|
var DEFAULT_MAX_HEIGHT = 8e3;
|
|
512
509
|
var DEFAULT_SETTLE_MS = 1e3;
|
|
513
510
|
var DEFAULT_MOBILE_SETTLE_MS = 50;
|
|
514
|
-
var DEFAULT_STITCH_SETTLE_MS = 120;
|
|
515
|
-
var DEFAULT_STITCH_OVERLAP_PX = 24;
|
|
516
|
-
var MIN_VIRTUALIZED_SCROLL_RATIO = 2.2;
|
|
517
|
-
var MIN_SPARSE_SCROLL_RATIO = 4;
|
|
518
|
-
var MOBILE_VIEWPORT_WIDTH_THRESHOLD = 520;
|
|
519
|
-
var DEFAULT_QUALITY_RETRY_ATTEMPTS = 2;
|
|
520
|
-
var DEFAULT_QUALITY_RETRY_DELAY_MS = 2500;
|
|
521
|
-
var MIN_TRAILING_BLANK_GAP_PX = 320;
|
|
522
|
-
var MIN_TRAILING_BLANK_GAP_RATIO = 0.12;
|
|
523
511
|
var toPositiveNumber = (value, fallback = 0) => {
|
|
524
512
|
const n = Number(value);
|
|
525
513
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
@@ -542,22 +530,7 @@ var normalizeQuality = (value, type) => {
|
|
|
542
530
|
if (rounded < 0 || rounded > 100) return void 0;
|
|
543
531
|
return rounded;
|
|
544
532
|
};
|
|
545
|
-
var resolvePageDevice =
|
|
546
|
-
const declared = normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
547
|
-
if (declared === Device.Mobile) return Device.Mobile;
|
|
548
|
-
const viewport = await resolveCurrentViewportSize(page).catch(() => null);
|
|
549
|
-
const viewportWidth = Math.round(Number(viewport?.width) || 0);
|
|
550
|
-
if (viewportWidth > 0 && viewportWidth <= MOBILE_VIEWPORT_WIDTH_THRESHOLD) {
|
|
551
|
-
return Device.Mobile;
|
|
552
|
-
}
|
|
553
|
-
return declared;
|
|
554
|
-
};
|
|
555
|
-
var resolveStitchMode = (options = {}) => {
|
|
556
|
-
const raw = options.stitch ?? options.stitching ?? options.strategy;
|
|
557
|
-
if (raw === false || raw === "off" || raw === "none" || raw === "single") return "off";
|
|
558
|
-
if (raw === true || raw === "force" || raw === "stitched") return "force";
|
|
559
|
-
return "auto";
|
|
560
|
-
};
|
|
533
|
+
var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
561
534
|
var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
562
535
|
const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
|
|
563
536
|
const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
|
|
@@ -904,156 +877,10 @@ var restoreAffixedElementsForExpandedScreenshot = async (page) => {
|
|
|
904
877
|
});
|
|
905
878
|
}, EXPANDED_SCROLLABLE_CLASS);
|
|
906
879
|
};
|
|
907
|
-
var measureMeaningfulContentBounds = async (page) => {
|
|
908
|
-
return await page.evaluate(() => {
|
|
909
|
-
const body = document.body;
|
|
910
|
-
if (!body) return null;
|
|
911
|
-
const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || body.clientWidth || 0;
|
|
912
|
-
const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || body.clientHeight || 0;
|
|
913
|
-
const scrollX = window.scrollX || window.pageXOffset || 0;
|
|
914
|
-
const scrollY = window.scrollY || window.pageYOffset || 0;
|
|
915
|
-
const bounds = {
|
|
916
|
-
left: Number.POSITIVE_INFINITY,
|
|
917
|
-
top: Number.POSITIVE_INFINITY,
|
|
918
|
-
right: 0,
|
|
919
|
-
bottom: 0,
|
|
920
|
-
nodes: 0
|
|
921
|
-
};
|
|
922
|
-
const isVisible = (el, style, rect) => {
|
|
923
|
-
if (!el || !style || !rect) return false;
|
|
924
|
-
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") return false;
|
|
925
|
-
if (Number(style.opacity) === 0) return false;
|
|
926
|
-
return rect.width > 1 && rect.height > 1;
|
|
927
|
-
};
|
|
928
|
-
const hasFixedAncestor = (el) => {
|
|
929
|
-
for (let node = el; node && node.nodeType === 1; node = node.parentElement) {
|
|
930
|
-
const position = String(window.getComputedStyle(node).position || "").toLowerCase();
|
|
931
|
-
if (position === "fixed") {
|
|
932
|
-
return true;
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
return false;
|
|
936
|
-
};
|
|
937
|
-
const parseRgbColor = (value) => {
|
|
938
|
-
const raw = String(value || "").trim();
|
|
939
|
-
const match = raw.match(/rgba?\(([^)]+)\)/i);
|
|
940
|
-
if (!match) return null;
|
|
941
|
-
const parts = match[1].replace(/\//g, " ").split(/[,\s]+/).map((part) => part.trim()).filter(Boolean);
|
|
942
|
-
if (parts.length < 3) return null;
|
|
943
|
-
const normalizeChannel = (part) => {
|
|
944
|
-
if (part.endsWith("%")) {
|
|
945
|
-
return Math.max(0, Math.min(255, Number.parseFloat(part) * 2.55));
|
|
946
|
-
}
|
|
947
|
-
return Math.max(0, Math.min(255, Number.parseFloat(part)));
|
|
948
|
-
};
|
|
949
|
-
const alpha = parts.length >= 4 ? parts[3].endsWith("%") ? Number.parseFloat(parts[3]) / 100 : Number.parseFloat(parts[3]) : 1;
|
|
950
|
-
return {
|
|
951
|
-
r: normalizeChannel(parts[0]),
|
|
952
|
-
g: normalizeChannel(parts[1]),
|
|
953
|
-
b: normalizeChannel(parts[2]),
|
|
954
|
-
a: Number.isFinite(alpha) ? Math.max(0, Math.min(1, alpha)) : 1
|
|
955
|
-
};
|
|
956
|
-
};
|
|
957
|
-
const colorLuminance = (color) => {
|
|
958
|
-
const channel = (value) => {
|
|
959
|
-
const ratio = Math.max(0, Math.min(255, value)) / 255;
|
|
960
|
-
return ratio <= 0.03928 ? ratio / 12.92 : ((ratio + 0.055) / 1.055) ** 2.4;
|
|
961
|
-
};
|
|
962
|
-
return 0.2126 * channel(color.r) + 0.7152 * channel(color.g) + 0.0722 * channel(color.b);
|
|
963
|
-
};
|
|
964
|
-
const contrastRatio = (a, b) => {
|
|
965
|
-
const l1 = colorLuminance(a);
|
|
966
|
-
const l2 = colorLuminance(b);
|
|
967
|
-
const lighter = Math.max(l1, l2);
|
|
968
|
-
const darker = Math.min(l1, l2);
|
|
969
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
970
|
-
};
|
|
971
|
-
const resolveBackgroundColor = (el) => {
|
|
972
|
-
for (let node = el; node && node.nodeType === 1; node = node.parentElement) {
|
|
973
|
-
const background = parseRgbColor(window.getComputedStyle(node).backgroundColor);
|
|
974
|
-
if (background && background.a > 0.2) {
|
|
975
|
-
return background;
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return { r: 255, g: 255, b: 255, a: 1 };
|
|
979
|
-
};
|
|
980
|
-
const isLowInformationTextPaint = (el, style) => {
|
|
981
|
-
const color = parseRgbColor(style?.color);
|
|
982
|
-
if (!color) return false;
|
|
983
|
-
const opacity = Number(style.opacity);
|
|
984
|
-
if (color.a <= 0.08 || Number.isFinite(opacity) && opacity <= 0.18) {
|
|
985
|
-
return true;
|
|
986
|
-
}
|
|
987
|
-
const max = Math.max(color.r, color.g, color.b);
|
|
988
|
-
const min = Math.min(color.r, color.g, color.b);
|
|
989
|
-
if (!(min >= 224 && max - min <= 24 && color.a >= 0.85)) {
|
|
990
|
-
return false;
|
|
991
|
-
}
|
|
992
|
-
const background = resolveBackgroundColor(el);
|
|
993
|
-
return colorLuminance(background) > 0.76 && contrastRatio(color, background) < 1.35;
|
|
994
|
-
};
|
|
995
|
-
const addRect = (rect) => {
|
|
996
|
-
if (!rect || rect.width <= 1 || rect.height <= 1) return;
|
|
997
|
-
const left = Math.max(0, Math.floor(rect.left + scrollX));
|
|
998
|
-
const top = Math.max(0, Math.floor(rect.top + scrollY));
|
|
999
|
-
const right = Math.ceil(rect.right + scrollX);
|
|
1000
|
-
const bottom = Math.ceil(rect.bottom + scrollY);
|
|
1001
|
-
if (right <= left || bottom <= top) return;
|
|
1002
|
-
bounds.left = Math.min(bounds.left, left);
|
|
1003
|
-
bounds.top = Math.min(bounds.top, top);
|
|
1004
|
-
bounds.right = Math.max(bounds.right, right);
|
|
1005
|
-
bounds.bottom = Math.max(bounds.bottom, bottom);
|
|
1006
|
-
bounds.nodes += 1;
|
|
1007
|
-
};
|
|
1008
|
-
const addElement = (el, { minArea = 12, text = false } = {}) => {
|
|
1009
|
-
if (!el || el.nodeType !== 1 || hasFixedAncestor(el)) return;
|
|
1010
|
-
const style = window.getComputedStyle(el);
|
|
1011
|
-
if (text && isLowInformationTextPaint(el, style)) return;
|
|
1012
|
-
const rects = Array.from(el.getClientRects ? el.getClientRects() : []);
|
|
1013
|
-
rects.forEach((rect) => {
|
|
1014
|
-
if (!isVisible(el, style, rect)) return;
|
|
1015
|
-
if (rect.width * rect.height < minArea) return;
|
|
1016
|
-
addRect(rect);
|
|
1017
|
-
});
|
|
1018
|
-
};
|
|
1019
|
-
const walker = document.createTreeWalker(body, NodeFilter.SHOW_TEXT);
|
|
1020
|
-
let visitedTextNodes = 0;
|
|
1021
|
-
while (walker.nextNode() && visitedTextNodes < 6e3) {
|
|
1022
|
-
const node = walker.currentNode;
|
|
1023
|
-
visitedTextNodes += 1;
|
|
1024
|
-
const text = String(node.nodeValue || "").replace(/\s+/g, " ").trim();
|
|
1025
|
-
if (text.length < 2) continue;
|
|
1026
|
-
addElement(node.parentElement, { minArea: 8, text: true });
|
|
1027
|
-
}
|
|
1028
|
-
document.querySelectorAll("img,video,canvas,svg,picture").forEach((el) => {
|
|
1029
|
-
addElement(el, { minArea: 900 });
|
|
1030
|
-
});
|
|
1031
|
-
if (!bounds.nodes || !Number.isFinite(bounds.left)) return null;
|
|
1032
|
-
const paddingX = Math.max(16, Math.min(96, viewportWidth * 0.04));
|
|
1033
|
-
const paddingY = Math.max(24, Math.min(160, viewportHeight * 0.18));
|
|
1034
|
-
return {
|
|
1035
|
-
left: Math.max(0, Math.floor(bounds.left - paddingX)),
|
|
1036
|
-
top: Math.max(0, Math.floor(bounds.top - paddingY)),
|
|
1037
|
-
right: Math.ceil(bounds.right + paddingX),
|
|
1038
|
-
bottom: Math.ceil(bounds.bottom + paddingY),
|
|
1039
|
-
width: Math.max(1, Math.ceil(bounds.right - bounds.left)),
|
|
1040
|
-
height: Math.max(1, Math.ceil(bounds.bottom - bounds.top)),
|
|
1041
|
-
nodes: bounds.nodes,
|
|
1042
|
-
viewport: {
|
|
1043
|
-
width: Math.max(1, Math.ceil(viewportWidth || 1)),
|
|
1044
|
-
height: Math.max(1, Math.ceil(viewportHeight || 1))
|
|
1045
|
-
}
|
|
1046
|
-
};
|
|
1047
|
-
}).catch((error) => {
|
|
1048
|
-
logger.warning(`\u622A\u56FE\u5185\u5BB9\u8FB9\u754C\u6D4B\u91CF\u5931\u8D25: ${error?.message || error}`);
|
|
1049
|
-
return null;
|
|
1050
|
-
});
|
|
1051
|
-
};
|
|
1052
880
|
var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
1053
881
|
const originalViewport = await resolveCurrentViewportSize(page);
|
|
1054
882
|
const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
|
|
1055
|
-
const
|
|
1056
|
-
const preserveViewport = options.preserveViewport ?? device === Device.Mobile;
|
|
883
|
+
const preserveViewport = options.preserveViewport ?? resolvePageDevice(page) === Device.Mobile;
|
|
1057
884
|
const defaultSettleMs = preserveViewport ? DEFAULT_MOBILE_SETTLE_MS : DEFAULT_SETTLE_MS;
|
|
1058
885
|
const requestedSettleMs = Math.max(0, Number(options.settleMs ?? defaultSettleMs) || 0);
|
|
1059
886
|
const settleMs = preserveViewport ? Math.min(requestedSettleMs, DEFAULT_MOBILE_SETTLE_MS) : requestedSettleMs;
|
|
@@ -1062,21 +889,7 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
|
1062
889
|
visibleOnly: options.visibleOnly !== false,
|
|
1063
890
|
expandDocumentElements: preserveViewport
|
|
1064
891
|
});
|
|
1065
|
-
const
|
|
1066
|
-
let targetHeight = Math.min(maxScrollHeight, maxHeight);
|
|
1067
|
-
if (contentBounds?.bottom > 0) {
|
|
1068
|
-
const contentBottom = Math.min(Math.ceil(contentBounds.bottom), maxHeight);
|
|
1069
|
-
const trailingGap = targetHeight - contentBottom;
|
|
1070
|
-
const minTrailingGap = Math.max(
|
|
1071
|
-
MIN_TRAILING_BLANK_GAP_PX,
|
|
1072
|
-
Math.floor(targetHeight * MIN_TRAILING_BLANK_GAP_RATIO),
|
|
1073
|
-
Math.floor(originalViewport.height * 0.45)
|
|
1074
|
-
);
|
|
1075
|
-
if (trailingGap >= minTrailingGap && contentBottom >= originalViewport.height * 0.65) {
|
|
1076
|
-
targetHeight = Math.max(1, contentBottom);
|
|
1077
|
-
logger.info(`\u957F\u622A\u56FE\u88C1\u6389\u4F4E\u4FE1\u606F\u5C3E\u90E8: contentBottom=${contentBottom}, originalHeight=${Math.min(maxScrollHeight, maxHeight)}`);
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
892
|
+
const targetHeight = Math.min(maxScrollHeight, maxHeight);
|
|
1080
893
|
let viewportResized = false;
|
|
1081
894
|
if (!preserveViewport) {
|
|
1082
895
|
await page.setViewportSize({
|
|
@@ -1096,7 +909,6 @@ var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
|
1096
909
|
originalViewport,
|
|
1097
910
|
maxScrollHeight,
|
|
1098
911
|
targetHeight,
|
|
1099
|
-
contentBounds,
|
|
1100
912
|
preserveViewport,
|
|
1101
913
|
viewportResized
|
|
1102
914
|
};
|
|
@@ -1129,411 +941,6 @@ var restoreExpandedFullPageScreenshot = async (page, state2 = {}) => {
|
|
|
1129
941
|
await page.setViewportSize(state2.originalViewport);
|
|
1130
942
|
}
|
|
1131
943
|
};
|
|
1132
|
-
var resolveVirtualizedScrollTarget = async (page, options = {}) => {
|
|
1133
|
-
const stitchMode = resolveStitchMode(options);
|
|
1134
|
-
if (stitchMode === "off") return null;
|
|
1135
|
-
const device = await resolvePageDevice(page);
|
|
1136
|
-
if (stitchMode !== "force" && device !== Device.Mobile) {
|
|
1137
|
-
return null;
|
|
1138
|
-
}
|
|
1139
|
-
return await page.evaluate((config) => {
|
|
1140
|
-
const viewportWidth = window.innerWidth || document.documentElement?.clientWidth || document.body?.clientWidth || 0;
|
|
1141
|
-
const viewportHeight = window.innerHeight || document.documentElement?.clientHeight || document.body?.clientHeight || 0;
|
|
1142
|
-
const root = document.documentElement;
|
|
1143
|
-
const body = document.body;
|
|
1144
|
-
const scrollingElement = document.scrollingElement;
|
|
1145
|
-
const candidates = [];
|
|
1146
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1147
|
-
const scrollableOverflow = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
|
|
1148
|
-
const clippingOverflow = /* @__PURE__ */ new Set(["hidden", "clip"]);
|
|
1149
|
-
const pushCandidate = (el2) => {
|
|
1150
|
-
if (!el2 || seen.has(el2)) return;
|
|
1151
|
-
seen.add(el2);
|
|
1152
|
-
candidates.push(el2);
|
|
1153
|
-
};
|
|
1154
|
-
pushCandidate(scrollingElement);
|
|
1155
|
-
pushCandidate(root);
|
|
1156
|
-
pushCandidate(body);
|
|
1157
|
-
document.querySelectorAll("*").forEach(pushCandidate);
|
|
1158
|
-
const isDocumentElement = (el2) => el2 === root || el2 === body || el2 === scrollingElement;
|
|
1159
|
-
const isVisible = (el2, style, rect) => {
|
|
1160
|
-
if (!el2 || !style || !rect) return false;
|
|
1161
|
-
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse") return false;
|
|
1162
|
-
if (Number(style.opacity) === 0) return false;
|
|
1163
|
-
return rect.width > 0 && rect.height > 0;
|
|
1164
|
-
};
|
|
1165
|
-
const hasOverflowValue = (style, values) => {
|
|
1166
|
-
const overflowY = String(style?.overflowY || "").toLowerCase();
|
|
1167
|
-
const overflow = String(style?.overflow || "").toLowerCase();
|
|
1168
|
-
return values.has(overflowY) || values.has(overflow);
|
|
1169
|
-
};
|
|
1170
|
-
const looksScrollable = (el2, style) => {
|
|
1171
|
-
if (!el2 || el2.scrollHeight <= el2.clientHeight + 1) return false;
|
|
1172
|
-
if (isDocumentElement(el2)) return true;
|
|
1173
|
-
return hasOverflowValue(style, scrollableOverflow) || hasOverflowValue(style, clippingOverflow);
|
|
1174
|
-
};
|
|
1175
|
-
const textHeightFor = (el2) => {
|
|
1176
|
-
const nodes = isDocumentElement(el2) ? document.querySelectorAll("body *") : el2.querySelectorAll("*");
|
|
1177
|
-
let textHeight = 0;
|
|
1178
|
-
let textNodes = 0;
|
|
1179
|
-
const maxNodes = 3500;
|
|
1180
|
-
for (const node of nodes) {
|
|
1181
|
-
if (textNodes >= maxNodes) break;
|
|
1182
|
-
const text = String(node.textContent || "").replace(/\s+/g, " ").trim();
|
|
1183
|
-
if (text.length < 2) continue;
|
|
1184
|
-
let childHasText = false;
|
|
1185
|
-
for (const child of node.children || []) {
|
|
1186
|
-
if (String(child.textContent || "").replace(/\s+/g, " ").trim().length >= 2) {
|
|
1187
|
-
childHasText = true;
|
|
1188
|
-
break;
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
if (childHasText) continue;
|
|
1192
|
-
const style = window.getComputedStyle(node);
|
|
1193
|
-
const rect = node.getBoundingClientRect();
|
|
1194
|
-
if (!isVisible(node, style, rect)) continue;
|
|
1195
|
-
textNodes += 1;
|
|
1196
|
-
textHeight += Math.min(Math.ceil(rect.height || 0), 900);
|
|
1197
|
-
}
|
|
1198
|
-
return { textHeight, textNodes };
|
|
1199
|
-
};
|
|
1200
|
-
const resolveEdgeOcclusion = () => {
|
|
1201
|
-
let top = 0;
|
|
1202
|
-
let bottom = 0;
|
|
1203
|
-
const maxHeight = Math.max(48, viewportHeight * 0.45);
|
|
1204
|
-
document.querySelectorAll("*").forEach((el2) => {
|
|
1205
|
-
const style = window.getComputedStyle(el2);
|
|
1206
|
-
const position = String(style.position || "").toLowerCase();
|
|
1207
|
-
if (position !== "fixed" && position !== "sticky") return;
|
|
1208
|
-
const rect = el2.getBoundingClientRect();
|
|
1209
|
-
if (!isVisible(el2, style, rect)) return;
|
|
1210
|
-
if (rect.height <= 0 || rect.height > maxHeight) return;
|
|
1211
|
-
if (rect.width < viewportWidth * 0.35) return;
|
|
1212
|
-
if (rect.top <= Math.max(16, viewportHeight * 0.08)) {
|
|
1213
|
-
top = Math.max(top, Math.ceil(rect.bottom));
|
|
1214
|
-
}
|
|
1215
|
-
if (rect.bottom >= viewportHeight - Math.max(16, viewportHeight * 0.08)) {
|
|
1216
|
-
bottom = Math.max(bottom, Math.ceil(viewportHeight - rect.top));
|
|
1217
|
-
}
|
|
1218
|
-
});
|
|
1219
|
-
return {
|
|
1220
|
-
top: Math.max(0, Math.min(Math.ceil(top), Math.floor(viewportHeight * 0.45))),
|
|
1221
|
-
bottom: Math.max(0, Math.min(Math.ceil(bottom), Math.floor(viewportHeight * 0.45)))
|
|
1222
|
-
};
|
|
1223
|
-
};
|
|
1224
|
-
let best = null;
|
|
1225
|
-
candidates.forEach((el2) => {
|
|
1226
|
-
const style = window.getComputedStyle(el2);
|
|
1227
|
-
const rect = isDocumentElement(el2) ? {
|
|
1228
|
-
top: 0,
|
|
1229
|
-
bottom: viewportHeight,
|
|
1230
|
-
left: 0,
|
|
1231
|
-
right: viewportWidth,
|
|
1232
|
-
width: viewportWidth,
|
|
1233
|
-
height: viewportHeight
|
|
1234
|
-
} : el2.getBoundingClientRect();
|
|
1235
|
-
if (!isDocumentElement(el2) && !isVisible(el2, style, rect)) return;
|
|
1236
|
-
if (!looksScrollable(el2, style)) return;
|
|
1237
|
-
const scrollHeight = Math.ceil(el2.scrollHeight || 0);
|
|
1238
|
-
const clientHeight = Math.ceil(el2.clientHeight || viewportHeight || 0);
|
|
1239
|
-
if (scrollHeight < Math.max(900, clientHeight * config.minScrollRatio)) return;
|
|
1240
|
-
const { textHeight, textNodes } = textHeightFor(el2);
|
|
1241
|
-
const sparseRatio = scrollHeight / Math.max(1, textHeight);
|
|
1242
|
-
const sparse = config.force || textNodes > 0 && sparseRatio >= config.minSparseRatio && scrollHeight - textHeight > clientHeight;
|
|
1243
|
-
if (!sparse) return;
|
|
1244
|
-
const visibleWidth = Math.max(1, Math.ceil(rect.width || viewportWidth || 1));
|
|
1245
|
-
const score2 = scrollHeight * Math.min(visibleWidth, viewportWidth || visibleWidth);
|
|
1246
|
-
if (!best || score2 > best.score) {
|
|
1247
|
-
best = {
|
|
1248
|
-
el: el2,
|
|
1249
|
-
score: score2,
|
|
1250
|
-
kind: isDocumentElement(el2) ? "document" : "element",
|
|
1251
|
-
scrollHeight,
|
|
1252
|
-
clientHeight,
|
|
1253
|
-
scrollTop: Math.max(0, Math.round(el2.scrollTop || 0)),
|
|
1254
|
-
rect: {
|
|
1255
|
-
top: Math.max(0, Math.round(rect.top || 0)),
|
|
1256
|
-
bottom: Math.min(viewportHeight, Math.round(rect.bottom || viewportHeight)),
|
|
1257
|
-
left: Math.max(0, Math.round(rect.left || 0)),
|
|
1258
|
-
width: Math.max(1, Math.round(rect.width || viewportWidth || 1)),
|
|
1259
|
-
height: Math.max(1, Math.round(rect.height || viewportHeight || 1))
|
|
1260
|
-
},
|
|
1261
|
-
textHeight,
|
|
1262
|
-
textNodes,
|
|
1263
|
-
sparseRatio
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1267
|
-
if (!best) return null;
|
|
1268
|
-
document.querySelectorAll(`[${config.attrName}="1"]`).forEach((node) => {
|
|
1269
|
-
node.removeAttribute(config.attrName);
|
|
1270
|
-
});
|
|
1271
|
-
if (best.kind === "element") {
|
|
1272
|
-
best.el.setAttribute(config.attrName, "1");
|
|
1273
|
-
}
|
|
1274
|
-
const { el, score, ...target } = best;
|
|
1275
|
-
return {
|
|
1276
|
-
...target,
|
|
1277
|
-
viewport: {
|
|
1278
|
-
width: Math.max(1, Math.ceil(viewportWidth || best.rect.width || 1)),
|
|
1279
|
-
height: Math.max(1, Math.ceil(viewportHeight || best.rect.height || 1))
|
|
1280
|
-
},
|
|
1281
|
-
edgeOcclusion: resolveEdgeOcclusion()
|
|
1282
|
-
};
|
|
1283
|
-
}, {
|
|
1284
|
-
attrName: STITCH_SCROLL_TARGET_ATTR,
|
|
1285
|
-
force: stitchMode === "force",
|
|
1286
|
-
minScrollRatio: MIN_VIRTUALIZED_SCROLL_RATIO,
|
|
1287
|
-
minSparseRatio: MIN_SPARSE_SCROLL_RATIO
|
|
1288
|
-
}).catch((error) => {
|
|
1289
|
-
logger.warning(`\u865A\u62DF\u6EDA\u52A8\u622A\u56FE\u63A2\u6D4B\u5931\u8D25: ${error?.message || error}`);
|
|
1290
|
-
return null;
|
|
1291
|
-
});
|
|
1292
|
-
};
|
|
1293
|
-
var setStitchScrollTop = async (page, target, scrollTop) => {
|
|
1294
|
-
await page.evaluate(({ attrName, kind, top }) => {
|
|
1295
|
-
const el = kind === "document" ? document.scrollingElement || document.documentElement || document.body : document.querySelector(`[${attrName}="1"]`);
|
|
1296
|
-
if (!el) return;
|
|
1297
|
-
el.scrollTop = Math.max(0, Math.round(Number(top) || 0));
|
|
1298
|
-
el.dispatchEvent(new Event("scroll", { bubbles: true }));
|
|
1299
|
-
window.dispatchEvent(new Event("scroll"));
|
|
1300
|
-
}, {
|
|
1301
|
-
attrName: STITCH_SCROLL_TARGET_ATTR,
|
|
1302
|
-
kind: target.kind,
|
|
1303
|
-
top: scrollTop
|
|
1304
|
-
});
|
|
1305
|
-
};
|
|
1306
|
-
var cleanupStitchTarget = async (page) => {
|
|
1307
|
-
await page.evaluate((attrName) => {
|
|
1308
|
-
document.querySelectorAll(`[${attrName}="1"]`).forEach((node) => {
|
|
1309
|
-
node.removeAttribute(attrName);
|
|
1310
|
-
});
|
|
1311
|
-
}, STITCH_SCROLL_TARGET_ATTR).catch(() => {
|
|
1312
|
-
});
|
|
1313
|
-
};
|
|
1314
|
-
var cropImage = (image, crop) => image.clone().crop({
|
|
1315
|
-
x: Math.max(0, Math.round(crop.x || 0)),
|
|
1316
|
-
y: Math.max(0, Math.round(crop.y || 0)),
|
|
1317
|
-
w: Math.max(1, Math.round(crop.w || 1)),
|
|
1318
|
-
h: Math.max(1, Math.round(crop.h || 1))
|
|
1319
|
-
});
|
|
1320
|
-
var captureStitchedScrollableScreenshot = async (page, target, options = {}) => {
|
|
1321
|
-
const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
|
|
1322
|
-
const settleMs = Math.max(0, Number(options.stitchSettleMs ?? DEFAULT_STITCH_SETTLE_MS) || 0);
|
|
1323
|
-
const overlapPx = Math.max(0, Math.round(Number(options.stitchOverlapPx ?? DEFAULT_STITCH_OVERLAP_PX) || 0));
|
|
1324
|
-
const viewport = target.viewport || await resolveCurrentViewportSize(page);
|
|
1325
|
-
const rect = target.rect || {
|
|
1326
|
-
top: 0,
|
|
1327
|
-
bottom: viewport.height,
|
|
1328
|
-
left: 0,
|
|
1329
|
-
width: viewport.width,
|
|
1330
|
-
height: viewport.height
|
|
1331
|
-
};
|
|
1332
|
-
const edge = target.edgeOcclusion || { top: 0, bottom: 0 };
|
|
1333
|
-
const topCrop = Math.max(0, Math.min(rect.top, viewport.height - 1));
|
|
1334
|
-
const topOverlay = Math.max(topCrop, Math.min(edge.top || 0, viewport.height - 1));
|
|
1335
|
-
const bottomOverlay = Math.max(0, Math.min(edge.bottom || 0, viewport.height - topOverlay - 1));
|
|
1336
|
-
const middleCropY = Math.max(topCrop, topOverlay);
|
|
1337
|
-
const middleCropBottom = Math.max(
|
|
1338
|
-
middleCropY + 1,
|
|
1339
|
-
Math.min(rect.bottom || viewport.height, viewport.height - bottomOverlay)
|
|
1340
|
-
);
|
|
1341
|
-
const middleCropHeight = Math.max(1, middleCropBottom - middleCropY);
|
|
1342
|
-
const scrollStep = Math.max(120, middleCropHeight - overlapPx);
|
|
1343
|
-
const maxScrollTop = Math.max(0, Math.ceil(target.scrollHeight - target.clientHeight));
|
|
1344
|
-
const positions = [];
|
|
1345
|
-
for (let top = 0; top < maxScrollTop; top += scrollStep) {
|
|
1346
|
-
positions.push(Math.round(top));
|
|
1347
|
-
}
|
|
1348
|
-
if (!positions.includes(maxScrollTop)) {
|
|
1349
|
-
positions.push(maxScrollTop);
|
|
1350
|
-
}
|
|
1351
|
-
if (positions.length === 0) {
|
|
1352
|
-
positions.push(0);
|
|
1353
|
-
}
|
|
1354
|
-
const segments = [];
|
|
1355
|
-
let totalHeight = 0;
|
|
1356
|
-
let outputWidth = Math.max(1, Math.round(viewport.width || rect.width || 1));
|
|
1357
|
-
try {
|
|
1358
|
-
for (let index = 0; index < positions.length && totalHeight < maxHeight; index += 1) {
|
|
1359
|
-
const isFirst = index === 0;
|
|
1360
|
-
const isLast = index === positions.length - 1;
|
|
1361
|
-
await setStitchScrollTop(page, target, positions[index]);
|
|
1362
|
-
if (settleMs > 0) {
|
|
1363
|
-
await delay(settleMs);
|
|
1364
|
-
}
|
|
1365
|
-
const buffer = await capturePageScreenshot(page, {
|
|
1366
|
-
type: options.type || "png",
|
|
1367
|
-
quality: options.quality,
|
|
1368
|
-
timeout: options.timeout
|
|
1369
|
-
});
|
|
1370
|
-
const image = await Jimp.read(buffer);
|
|
1371
|
-
outputWidth = Math.min(outputWidth, image.bitmap.width);
|
|
1372
|
-
const cropY = isFirst ? 0 : middleCropY;
|
|
1373
|
-
const cropBottom = isLast ? image.bitmap.height : middleCropBottom;
|
|
1374
|
-
let cropHeight = Math.max(1, Math.min(image.bitmap.height, cropBottom) - cropY);
|
|
1375
|
-
const remaining = maxHeight - totalHeight;
|
|
1376
|
-
if (cropHeight > remaining) {
|
|
1377
|
-
cropHeight = remaining;
|
|
1378
|
-
}
|
|
1379
|
-
segments.push(cropImage(image, {
|
|
1380
|
-
x: 0,
|
|
1381
|
-
y: cropY,
|
|
1382
|
-
w: outputWidth,
|
|
1383
|
-
h: cropHeight
|
|
1384
|
-
}));
|
|
1385
|
-
totalHeight += cropHeight;
|
|
1386
|
-
}
|
|
1387
|
-
const canvas = new Jimp({
|
|
1388
|
-
width: outputWidth,
|
|
1389
|
-
height: Math.max(1, totalHeight),
|
|
1390
|
-
color: 4294967295
|
|
1391
|
-
});
|
|
1392
|
-
let y = 0;
|
|
1393
|
-
for (const segment of segments) {
|
|
1394
|
-
canvas.composite(segment, 0, y);
|
|
1395
|
-
y += segment.bitmap.height;
|
|
1396
|
-
}
|
|
1397
|
-
logger.info(
|
|
1398
|
-
`\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)}`
|
|
1399
|
-
);
|
|
1400
|
-
return await canvas.getBuffer(JimpMime.png);
|
|
1401
|
-
} finally {
|
|
1402
|
-
await setStitchScrollTop(page, target, target.scrollTop || 0).catch(() => {
|
|
1403
|
-
});
|
|
1404
|
-
await cleanupStitchTarget(page);
|
|
1405
|
-
}
|
|
1406
|
-
};
|
|
1407
|
-
var isLightBlankPixel = ({ r, g, b }) => {
|
|
1408
|
-
const max = Math.max(r, g, b);
|
|
1409
|
-
const min = Math.min(r, g, b);
|
|
1410
|
-
return max >= 238 && max - min <= 18;
|
|
1411
|
-
};
|
|
1412
|
-
var isDarkBlankPixel = ({ r, g, b }) => {
|
|
1413
|
-
const max = Math.max(r, g, b);
|
|
1414
|
-
const min = Math.min(r, g, b);
|
|
1415
|
-
return max <= 34 && max - min <= 10;
|
|
1416
|
-
};
|
|
1417
|
-
var isLowInfoPixel = ({ r, g, b }) => {
|
|
1418
|
-
const max = Math.max(r, g, b);
|
|
1419
|
-
const min = Math.min(r, g, b);
|
|
1420
|
-
return max - min <= 12;
|
|
1421
|
-
};
|
|
1422
|
-
var analyzeScreenshotBuffer = async (buffer) => {
|
|
1423
|
-
const image = await Jimp.read(buffer);
|
|
1424
|
-
const width = image.bitmap.width;
|
|
1425
|
-
const height = image.bitmap.height;
|
|
1426
|
-
const stepY = Math.max(1, Math.floor(height / 900));
|
|
1427
|
-
const stepX = Math.max(1, Math.floor(width / 420));
|
|
1428
|
-
const rows = [];
|
|
1429
|
-
let lightRows = 0;
|
|
1430
|
-
let darkRows = 0;
|
|
1431
|
-
let lowInfoRows = 0;
|
|
1432
|
-
let loadingLikeRows = 0;
|
|
1433
|
-
const rowFlags = [];
|
|
1434
|
-
for (let y = 0; y < height; y += stepY) {
|
|
1435
|
-
let light = 0;
|
|
1436
|
-
let dark = 0;
|
|
1437
|
-
let lowInfo = 0;
|
|
1438
|
-
let edge = 0;
|
|
1439
|
-
let count = 0;
|
|
1440
|
-
let prev = null;
|
|
1441
|
-
for (let x = 0; x < width; x += stepX) {
|
|
1442
|
-
const rgba = intToRGBA(image.getPixelColor(x, y));
|
|
1443
|
-
count += 1;
|
|
1444
|
-
if (isLightBlankPixel(rgba)) light += 1;
|
|
1445
|
-
if (isDarkBlankPixel(rgba)) dark += 1;
|
|
1446
|
-
if (isLowInfoPixel(rgba)) lowInfo += 1;
|
|
1447
|
-
if (prev) {
|
|
1448
|
-
const diff = Math.abs(rgba.r - prev.r) + Math.abs(rgba.g - prev.g) + Math.abs(rgba.b - prev.b);
|
|
1449
|
-
if (diff > 45) edge += 1;
|
|
1450
|
-
}
|
|
1451
|
-
prev = rgba;
|
|
1452
|
-
}
|
|
1453
|
-
const stat = {
|
|
1454
|
-
y,
|
|
1455
|
-
lightRatio: light / Math.max(1, count),
|
|
1456
|
-
darkRatio: dark / Math.max(1, count),
|
|
1457
|
-
lowInfoRatio: lowInfo / Math.max(1, count),
|
|
1458
|
-
edgeRatio: edge / Math.max(1, count - 1)
|
|
1459
|
-
};
|
|
1460
|
-
rows.push(stat);
|
|
1461
|
-
const lightBlank = stat.lightRatio >= 0.965 && stat.edgeRatio <= 0.015;
|
|
1462
|
-
const darkBlank = stat.darkRatio >= 0.965 && stat.edgeRatio <= 0.012;
|
|
1463
|
-
const lowInfoBlank = stat.lowInfoRatio >= 0.965 && stat.edgeRatio <= 0.012;
|
|
1464
|
-
const loadingLike = stat.darkRatio >= 0.88 && stat.edgeRatio <= 0.025;
|
|
1465
|
-
if (lightBlank) lightRows += 1;
|
|
1466
|
-
if (darkBlank) darkRows += 1;
|
|
1467
|
-
if (lowInfoBlank) lowInfoRows += 1;
|
|
1468
|
-
if (loadingLike) loadingLikeRows += 1;
|
|
1469
|
-
rowFlags.push({ lightBlank, darkBlank, lowInfoBlank, loadingLike });
|
|
1470
|
-
}
|
|
1471
|
-
const sampledRows = Math.max(1, rows.length);
|
|
1472
|
-
return {
|
|
1473
|
-
image,
|
|
1474
|
-
width,
|
|
1475
|
-
height,
|
|
1476
|
-
lightBlankRowsRatio: lightRows / sampledRows,
|
|
1477
|
-
darkBlankRowsRatio: darkRows / sampledRows,
|
|
1478
|
-
lowInfoRowsRatio: lowInfoRows / sampledRows,
|
|
1479
|
-
loadingLikeRowsRatio: loadingLikeRows / sampledRows,
|
|
1480
|
-
rowFlags
|
|
1481
|
-
};
|
|
1482
|
-
};
|
|
1483
|
-
var resolveScreenshotQualityIssue = (analysis) => {
|
|
1484
|
-
if (!analysis) return null;
|
|
1485
|
-
if (analysis.loadingLikeRowsRatio >= 0.92 || analysis.darkBlankRowsRatio >= 0.72) {
|
|
1486
|
-
return "loading-like-dark-screenshot";
|
|
1487
|
-
}
|
|
1488
|
-
return null;
|
|
1489
|
-
};
|
|
1490
|
-
var cropBufferToContentBounds = async (buffer, bounds, options = {}) => {
|
|
1491
|
-
if (!bounds || bounds.nodes <= 0) return buffer;
|
|
1492
|
-
const image = options.image || await Jimp.read(buffer);
|
|
1493
|
-
const width = image.bitmap.width;
|
|
1494
|
-
const height = image.bitmap.height;
|
|
1495
|
-
const safeLeft = Math.max(0, Math.min(width - 1, Math.floor(bounds.left || 0)));
|
|
1496
|
-
const safeRight = Math.max(safeLeft + 1, Math.min(width, Math.ceil(bounds.right || width)));
|
|
1497
|
-
const safeTop = Math.max(0, Math.min(height - 1, Math.floor(bounds.top || 0)));
|
|
1498
|
-
const safeBottom = Math.max(safeTop + 1, Math.min(height, Math.ceil(bounds.bottom || height)));
|
|
1499
|
-
const cropW = safeRight - safeLeft;
|
|
1500
|
-
const cropH = safeBottom - safeTop;
|
|
1501
|
-
const shouldCropX = cropW > 80 && cropW <= width * 0.82 && (safeLeft > width * 0.04 || width - safeRight > width * 0.04);
|
|
1502
|
-
const shouldCropY = cropH > 160 && cropH <= height * 0.88 && height - safeBottom > Math.max(320, height * 0.1);
|
|
1503
|
-
if (!shouldCropX && !shouldCropY) {
|
|
1504
|
-
return buffer;
|
|
1505
|
-
}
|
|
1506
|
-
const x = shouldCropX ? safeLeft : 0;
|
|
1507
|
-
const y = shouldCropY ? safeTop : 0;
|
|
1508
|
-
const w = shouldCropX ? cropW : width;
|
|
1509
|
-
const h = shouldCropY ? cropH : height;
|
|
1510
|
-
logger.info(`\u5185\u5BB9\u611F\u77E5\u88C1\u526A\u622A\u56FE: x=${x}, y=${y}, w=${w}, h=${h}, original=${width}x${height}`);
|
|
1511
|
-
return await cropImage(image, { x, y, w, h }).getBuffer(JimpMime.png);
|
|
1512
|
-
};
|
|
1513
|
-
var captureExpandedFullPageScreenshotOnce = async (page, options = {}) => {
|
|
1514
|
-
const stitchedTarget = await resolveVirtualizedScrollTarget(page, options);
|
|
1515
|
-
if (stitchedTarget) {
|
|
1516
|
-
return await captureStitchedScrollableScreenshot(page, stitchedTarget, options);
|
|
1517
|
-
}
|
|
1518
|
-
const state2 = await prepareExpandedFullPageScreenshot(page, options);
|
|
1519
|
-
try {
|
|
1520
|
-
const buffer = await capturePageScreenshot(page, {
|
|
1521
|
-
fullPage: true,
|
|
1522
|
-
type: options.type || "png",
|
|
1523
|
-
quality: options.quality,
|
|
1524
|
-
timeout: options.timeout,
|
|
1525
|
-
maxClipHeight: state2.targetHeight
|
|
1526
|
-
});
|
|
1527
|
-
return await cropBufferToContentBounds(buffer, state2.contentBounds);
|
|
1528
|
-
} finally {
|
|
1529
|
-
await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
|
|
1530
|
-
logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
|
|
1531
|
-
});
|
|
1532
|
-
if (options.restore) {
|
|
1533
|
-
await restoreExpandedFullPageScreenshot(page, state2);
|
|
1534
|
-
}
|
|
1535
|
-
}
|
|
1536
|
-
};
|
|
1537
944
|
var capturePageScreenshot = async (page, options = {}) => {
|
|
1538
945
|
const fullPage = Boolean(options.fullPage);
|
|
1539
946
|
const type = fullPage ? FORCED_FULLPAGE_TYPE : normalizeType(options.type);
|
|
@@ -1588,35 +995,23 @@ var capturePageScreenshot = async (page, options = {}) => {
|
|
|
1588
995
|
}
|
|
1589
996
|
};
|
|
1590
997
|
var captureExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
1591
|
-
const
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
logger.warning(`\u622A\u56FE\u8D28\u91CF\u5206\u6790\u5931\u8D25: ${error?.message || error}`);
|
|
1600
|
-
return null;
|
|
998
|
+
const state2 = await prepareExpandedFullPageScreenshot(page, options);
|
|
999
|
+
try {
|
|
1000
|
+
return await capturePageScreenshot(page, {
|
|
1001
|
+
fullPage: true,
|
|
1002
|
+
type: options.type || "png",
|
|
1003
|
+
quality: options.quality,
|
|
1004
|
+
timeout: options.timeout,
|
|
1005
|
+
maxClipHeight: state2.targetHeight
|
|
1601
1006
|
});
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
if (
|
|
1607
|
-
|
|
1608
|
-
}
|
|
1609
|
-
if (attempt < attempts && retryDelayMs > 0) {
|
|
1610
|
-
logger.warning(`\u622A\u56FE\u7591\u4F3C\u5F02\u5E38(${issue})\uFF0C\u7B49\u5F85\u540E\u91CD\u8BD5: attempt=${attempt}/${attempts}`);
|
|
1611
|
-
await delay(retryDelayMs);
|
|
1007
|
+
} finally {
|
|
1008
|
+
await restoreAffixedElementsForExpandedScreenshot(page).catch((error) => {
|
|
1009
|
+
logger.warning(`\u79FB\u52A8\u7AEF\u5438\u9644\u5143\u7D20\u6062\u590D\u5931\u8D25: ${error?.message || error}`);
|
|
1010
|
+
});
|
|
1011
|
+
if (options.restore) {
|
|
1012
|
+
await restoreExpandedFullPageScreenshot(page, state2);
|
|
1612
1013
|
}
|
|
1613
1014
|
}
|
|
1614
|
-
if (lastIssue && lastAnalysis) {
|
|
1615
|
-
logger.warning(
|
|
1616
|
-
`\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)}`
|
|
1617
|
-
);
|
|
1618
|
-
}
|
|
1619
|
-
return lastBuffer;
|
|
1620
1015
|
};
|
|
1621
1016
|
|
|
1622
1017
|
// src/errors.js
|
|
@@ -10292,7 +9687,7 @@ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null, options = {
|
|
|
10292
9687
|
};
|
|
10293
9688
|
|
|
10294
9689
|
// src/internals/compression.js
|
|
10295
|
-
import { Jimp
|
|
9690
|
+
import { Jimp, JimpMime, ResizeStrategy } from "jimp";
|
|
10296
9691
|
var logger15 = createInternalLogger("Compression");
|
|
10297
9692
|
var DEFAULT_SCREENSHOT_MAX_BYTES = 5 * 1024 * 1024;
|
|
10298
9693
|
var DEFAULT_SCREENSHOT_OUTPUT_TYPE = "jpeg";
|
|
@@ -10362,7 +9757,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
|
|
|
10362
9757
|
mode: ResizeStrategy.BILINEAR
|
|
10363
9758
|
});
|
|
10364
9759
|
}
|
|
10365
|
-
const buffer = await image.getBuffer(
|
|
9760
|
+
const buffer = await image.getBuffer(JimpMime.jpeg, { quality });
|
|
10366
9761
|
return {
|
|
10367
9762
|
buffer,
|
|
10368
9763
|
bytes: getBase64BytesFromBuffer(buffer),
|
|
@@ -10374,7 +9769,7 @@ var encodeJpeg = async (sourceImage, compression, scale, quality) => {
|
|
|
10374
9769
|
};
|
|
10375
9770
|
};
|
|
10376
9771
|
var compressImageBuffer = async (buffer, compression) => {
|
|
10377
|
-
const sourceImage = await
|
|
9772
|
+
const sourceImage = await Jimp.read(buffer);
|
|
10378
9773
|
const maxQuality = toJpegQuality(compression.quality);
|
|
10379
9774
|
const minQuality = Math.min(maxQuality, toJpegQuality(compression.minQuality));
|
|
10380
9775
|
let quality = maxQuality;
|