@skrillex1224/playwright-toolkit 2.1.212 → 2.1.213

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/index.cjs CHANGED
@@ -4587,7 +4587,6 @@ var Logger = {
4587
4587
  var import_delay2 = __toESM(require("delay"), 1);
4588
4588
 
4589
4589
  // src/internals/watermarkify.js
4590
- var import_sharp = __toESM(require("sharp"), 1);
4591
4590
  var DEFAULT_TIMEZONE_OFFSET = 8;
4592
4591
  var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
4593
4592
  var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
@@ -4618,6 +4617,7 @@ var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
4618
4617
  var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
4619
4618
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
4620
4619
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
4620
+ var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
4621
4621
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
4622
4622
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4623
4623
  /(?:中国)?移动$/i,
@@ -4940,6 +4940,198 @@ var openProbePage = async (page) => {
4940
4940
  }
4941
4941
  return null;
4942
4942
  };
4943
+ var readPngDimensions = (buffer) => {
4944
+ if (!Buffer.isBuffer(buffer) || buffer.length < 24) {
4945
+ return { width: 0, height: 0 };
4946
+ }
4947
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
4948
+ for (let index = 0; index < pngSignature.length; index += 1) {
4949
+ if (buffer[index] !== pngSignature[index]) {
4950
+ return { width: 0, height: 0 };
4951
+ }
4952
+ }
4953
+ return {
4954
+ width: buffer.readUInt32BE(16),
4955
+ height: buffer.readUInt32BE(20)
4956
+ };
4957
+ };
4958
+ var readJpegDimensions = (buffer) => {
4959
+ if (!Buffer.isBuffer(buffer) || buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
4960
+ return { width: 0, height: 0 };
4961
+ }
4962
+ let offset = 2;
4963
+ while (offset + 9 <= buffer.length) {
4964
+ if (buffer[offset] !== 255) {
4965
+ offset += 1;
4966
+ continue;
4967
+ }
4968
+ const marker = buffer[offset + 1];
4969
+ offset += 2;
4970
+ if (marker === 216 || marker === 217) {
4971
+ continue;
4972
+ }
4973
+ if (marker === 218) {
4974
+ break;
4975
+ }
4976
+ if (offset + 2 > buffer.length) {
4977
+ break;
4978
+ }
4979
+ const segmentLength = buffer.readUInt16BE(offset);
4980
+ if (segmentLength < 2 || offset + segmentLength > buffer.length) {
4981
+ break;
4982
+ }
4983
+ const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
4984
+ if (isStartOfFrame && offset + 7 <= buffer.length) {
4985
+ return {
4986
+ height: buffer.readUInt16BE(offset + 3),
4987
+ width: buffer.readUInt16BE(offset + 5)
4988
+ };
4989
+ }
4990
+ offset += segmentLength;
4991
+ }
4992
+ return { width: 0, height: 0 };
4993
+ };
4994
+ var readImageInfo = (buffer) => {
4995
+ const png = readPngDimensions(buffer);
4996
+ if (png.width && png.height) {
4997
+ return {
4998
+ mimeType: "image/png",
4999
+ width: png.width,
5000
+ height: png.height
5001
+ };
5002
+ }
5003
+ const jpeg = readJpegDimensions(buffer);
5004
+ if (jpeg.width && jpeg.height) {
5005
+ return {
5006
+ mimeType: "image/jpeg",
5007
+ width: jpeg.width,
5008
+ height: jpeg.height
5009
+ };
5010
+ }
5011
+ return {
5012
+ mimeType: "",
5013
+ width: 0,
5014
+ height: 0
5015
+ };
5016
+ };
5017
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
5018
+ const safeWidth = Math.max(1, Number(width) || 1);
5019
+ const safeHeight = Math.max(1, Number(height) || 1);
5020
+ return `
5021
+ <!doctype html>
5022
+ <html lang="zh-CN">
5023
+ <head>
5024
+ <meta charset="utf-8" />
5025
+ <style>
5026
+ html, body {
5027
+ margin: 0;
5028
+ padding: 0;
5029
+ width: ${safeWidth}px;
5030
+ height: ${safeHeight}px;
5031
+ overflow: hidden;
5032
+ background: #ffffff;
5033
+ }
5034
+
5035
+ body {
5036
+ position: relative;
5037
+ }
5038
+
5039
+ #pk-stage {
5040
+ position: relative;
5041
+ width: ${safeWidth}px;
5042
+ height: ${safeHeight}px;
5043
+ overflow: hidden;
5044
+ }
5045
+
5046
+ #pk-base-image {
5047
+ position: absolute;
5048
+ inset: 0;
5049
+ display: block;
5050
+ width: ${safeWidth}px;
5051
+ height: ${safeHeight}px;
5052
+ }
5053
+
5054
+ #pk-overlay {
5055
+ position: absolute;
5056
+ inset: 0;
5057
+ width: ${safeWidth}px;
5058
+ height: ${safeHeight}px;
5059
+ pointer-events: none;
5060
+ }
5061
+ </style>
5062
+ </head>
5063
+ <body>
5064
+ <div id="pk-stage">
5065
+ <img id="pk-base-image" src="${escapeHtmlAttribute(imageSrc)}" alt="" />
5066
+ <div id="pk-overlay">${overlaySvg}</div>
5067
+ </div>
5068
+ </body>
5069
+ </html>
5070
+ `;
5071
+ };
5072
+ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageInfo = {}) => {
5073
+ if (!page || typeof page.context !== "function") {
5074
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u7F3A\u5C11\u53EF\u7528 page");
5075
+ return buffer;
5076
+ }
5077
+ const renderScope = await openProbePage(page);
5078
+ if (!renderScope?.page) {
5079
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA render page");
5080
+ return buffer;
5081
+ }
5082
+ try {
5083
+ const renderPage = renderScope.page;
5084
+ const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
5085
+ const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
5086
+ const viewportHeight = Math.max(
5087
+ 1,
5088
+ Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
5089
+ );
5090
+ await renderPage.setViewportSize({
5091
+ width: safeWidth,
5092
+ height: viewportHeight
5093
+ }).catch(() => {
5094
+ });
5095
+ await renderPage.setContent(buildWatermarkifyRenderHtml({
5096
+ imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
5097
+ overlaySvg,
5098
+ width: safeWidth,
5099
+ height: safeHeight
5100
+ }), {
5101
+ waitUntil: "load"
5102
+ });
5103
+ await renderPage.waitForFunction(() => {
5104
+ const image = document.getElementById("pk-base-image");
5105
+ return image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0 && image.naturalHeight > 0;
5106
+ }, {
5107
+ timeout: 5e3
5108
+ }).catch(() => {
5109
+ });
5110
+ await renderPage.evaluate(async () => {
5111
+ if (document.fonts?.ready) {
5112
+ await document.fonts.ready.catch(() => {
5113
+ });
5114
+ }
5115
+ }).catch(() => {
5116
+ });
5117
+ const composed = await renderPage.screenshot({
5118
+ type: "png",
5119
+ fullPage: true,
5120
+ animations: "disabled"
5121
+ }).catch((error) => {
5122
+ logger11.warning(`watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5123
+ return null;
5124
+ });
5125
+ if (Buffer.isBuffer(composed) && composed.length > 0) {
5126
+ return composed;
5127
+ }
5128
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: \u672A\u5F97\u5230\u6709\u6548\u622A\u56FE\u7ED3\u679C");
5129
+ return buffer;
5130
+ } finally {
5131
+ await renderScope.close().catch(() => {
5132
+ });
5133
+ }
5134
+ };
4943
5135
  var resolveWithIpLookup = async (page, options = {}) => {
4944
5136
  if (!page || typeof page.context !== "function" || options.ipLookup === false) {
4945
5137
  return null;
@@ -5085,6 +5277,7 @@ var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
5085
5277
  ];
5086
5278
  };
5087
5279
  var escapeXml = (value) => String(value || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5280
+ var escapeHtmlAttribute = (value) => String(value || "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5088
5281
  var estimateTextWidth = (value, fontSize = 16) => {
5089
5282
  const text = String(value || "");
5090
5283
  let width = 0;
@@ -5696,24 +5889,22 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
5696
5889
  </svg>
5697
5890
  `;
5698
5891
  };
5699
- var watermarkifyScreenshotBuffer = async (buffer, meta) => {
5892
+ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
5700
5893
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
5701
5894
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
5702
5895
  if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
5703
5896
  return buffer;
5704
5897
  }
5705
- const image = (0, import_sharp.default)(buffer, { failOn: "none" });
5706
- const metadata = await image.metadata().catch(() => null);
5707
- const width = Math.max(1, Number(metadata?.width) || 0);
5708
- const height = Math.max(1, Number(metadata?.height) || 0);
5709
- if (!width || !height) {
5898
+ const imageInfo = readImageInfo(buffer);
5899
+ if (!imageInfo.width || !imageInfo.height || !imageInfo.mimeType) {
5900
+ logger11.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
5710
5901
  return buffer;
5711
5902
  }
5712
- const overlaySvg = buildWatermarkifySvg(meta, width, height);
5903
+ const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
5713
5904
  if (!overlaySvg) {
5714
5905
  return buffer;
5715
5906
  }
5716
- return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
5907
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
5717
5908
  };
5718
5909
 
5719
5910
  // src/share.js
@@ -6177,7 +6368,7 @@ var Share = {
6177
6368
  ...screenshotWatermarkify,
6178
6369
  capturedAt
6179
6370
  });
6180
- const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
6371
+ const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
6181
6372
  return buffer_.toString("base64");
6182
6373
  } finally {
6183
6374
  if (restore) {