@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.js CHANGED
@@ -4559,7 +4559,6 @@ var Logger = {
4559
4559
  import delay2 from "delay";
4560
4560
 
4561
4561
  // src/internals/watermarkify.js
4562
- import sharp from "sharp";
4563
4562
  var DEFAULT_TIMEZONE_OFFSET = 8;
4564
4563
  var DEFAULT_RESOLVER_TIMEOUT_MS = 180;
4565
4564
  var DEFAULT_IP_LOOKUP_TIMEOUT_MS = 1e4;
@@ -4590,6 +4589,7 @@ var DEFAULT_STRIP_LINE_HEIGHT_RATIO = 1.28;
4590
4589
  var DEFAULT_STRIP_PROMPT_MAX_LINES = 3;
4591
4590
  var DEFAULT_STRIP_CONTENT_SAFE_PADDING_X = 12;
4592
4591
  var DEFAULT_STRIP_TEXT_WIDTH_SAFETY = 10;
4592
+ var DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT = 1200;
4593
4593
  var WEAK_LOCATION_VALUES = /* @__PURE__ */ new Set(["cn", "\u4E2D\u56FD"]);
4594
4594
  var LOCATION_NETWORK_SUFFIX_PATTERNS = [
4595
4595
  /(?:中国)?移动$/i,
@@ -4912,6 +4912,198 @@ var openProbePage = async (page) => {
4912
4912
  }
4913
4913
  return null;
4914
4914
  };
4915
+ var readPngDimensions = (buffer) => {
4916
+ if (!Buffer.isBuffer(buffer) || buffer.length < 24) {
4917
+ return { width: 0, height: 0 };
4918
+ }
4919
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
4920
+ for (let index = 0; index < pngSignature.length; index += 1) {
4921
+ if (buffer[index] !== pngSignature[index]) {
4922
+ return { width: 0, height: 0 };
4923
+ }
4924
+ }
4925
+ return {
4926
+ width: buffer.readUInt32BE(16),
4927
+ height: buffer.readUInt32BE(20)
4928
+ };
4929
+ };
4930
+ var readJpegDimensions = (buffer) => {
4931
+ if (!Buffer.isBuffer(buffer) || buffer.length < 4 || buffer[0] !== 255 || buffer[1] !== 216) {
4932
+ return { width: 0, height: 0 };
4933
+ }
4934
+ let offset = 2;
4935
+ while (offset + 9 <= buffer.length) {
4936
+ if (buffer[offset] !== 255) {
4937
+ offset += 1;
4938
+ continue;
4939
+ }
4940
+ const marker = buffer[offset + 1];
4941
+ offset += 2;
4942
+ if (marker === 216 || marker === 217) {
4943
+ continue;
4944
+ }
4945
+ if (marker === 218) {
4946
+ break;
4947
+ }
4948
+ if (offset + 2 > buffer.length) {
4949
+ break;
4950
+ }
4951
+ const segmentLength = buffer.readUInt16BE(offset);
4952
+ if (segmentLength < 2 || offset + segmentLength > buffer.length) {
4953
+ break;
4954
+ }
4955
+ const isStartOfFrame = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
4956
+ if (isStartOfFrame && offset + 7 <= buffer.length) {
4957
+ return {
4958
+ height: buffer.readUInt16BE(offset + 3),
4959
+ width: buffer.readUInt16BE(offset + 5)
4960
+ };
4961
+ }
4962
+ offset += segmentLength;
4963
+ }
4964
+ return { width: 0, height: 0 };
4965
+ };
4966
+ var readImageInfo = (buffer) => {
4967
+ const png = readPngDimensions(buffer);
4968
+ if (png.width && png.height) {
4969
+ return {
4970
+ mimeType: "image/png",
4971
+ width: png.width,
4972
+ height: png.height
4973
+ };
4974
+ }
4975
+ const jpeg = readJpegDimensions(buffer);
4976
+ if (jpeg.width && jpeg.height) {
4977
+ return {
4978
+ mimeType: "image/jpeg",
4979
+ width: jpeg.width,
4980
+ height: jpeg.height
4981
+ };
4982
+ }
4983
+ return {
4984
+ mimeType: "",
4985
+ width: 0,
4986
+ height: 0
4987
+ };
4988
+ };
4989
+ var buildWatermarkifyRenderHtml = ({ imageSrc, overlaySvg, width, height }) => {
4990
+ const safeWidth = Math.max(1, Number(width) || 1);
4991
+ const safeHeight = Math.max(1, Number(height) || 1);
4992
+ return `
4993
+ <!doctype html>
4994
+ <html lang="zh-CN">
4995
+ <head>
4996
+ <meta charset="utf-8" />
4997
+ <style>
4998
+ html, body {
4999
+ margin: 0;
5000
+ padding: 0;
5001
+ width: ${safeWidth}px;
5002
+ height: ${safeHeight}px;
5003
+ overflow: hidden;
5004
+ background: #ffffff;
5005
+ }
5006
+
5007
+ body {
5008
+ position: relative;
5009
+ }
5010
+
5011
+ #pk-stage {
5012
+ position: relative;
5013
+ width: ${safeWidth}px;
5014
+ height: ${safeHeight}px;
5015
+ overflow: hidden;
5016
+ }
5017
+
5018
+ #pk-base-image {
5019
+ position: absolute;
5020
+ inset: 0;
5021
+ display: block;
5022
+ width: ${safeWidth}px;
5023
+ height: ${safeHeight}px;
5024
+ }
5025
+
5026
+ #pk-overlay {
5027
+ position: absolute;
5028
+ inset: 0;
5029
+ width: ${safeWidth}px;
5030
+ height: ${safeHeight}px;
5031
+ pointer-events: none;
5032
+ }
5033
+ </style>
5034
+ </head>
5035
+ <body>
5036
+ <div id="pk-stage">
5037
+ <img id="pk-base-image" src="${escapeHtmlAttribute(imageSrc)}" alt="" />
5038
+ <div id="pk-overlay">${overlaySvg}</div>
5039
+ </div>
5040
+ </body>
5041
+ </html>
5042
+ `;
5043
+ };
5044
+ var composeScreenshotBufferWithBrowser = async (page, buffer, overlaySvg, imageInfo = {}) => {
5045
+ if (!page || typeof page.context !== "function") {
5046
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u7F3A\u5C11\u53EF\u7528 page");
5047
+ return buffer;
5048
+ }
5049
+ const renderScope = await openProbePage(page);
5050
+ if (!renderScope?.page) {
5051
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u8DF3\u8FC7: \u65E0\u6CD5\u521B\u5EFA render page");
5052
+ return buffer;
5053
+ }
5054
+ try {
5055
+ const renderPage = renderScope.page;
5056
+ const safeWidth = Math.max(1, Number(imageInfo.width) || 1);
5057
+ const safeHeight = Math.max(1, Number(imageInfo.height) || 1);
5058
+ const viewportHeight = Math.max(
5059
+ 1,
5060
+ Math.min(safeHeight, DEFAULT_BROWSER_COMPOSITOR_VIEWPORT_HEIGHT)
5061
+ );
5062
+ await renderPage.setViewportSize({
5063
+ width: safeWidth,
5064
+ height: viewportHeight
5065
+ }).catch(() => {
5066
+ });
5067
+ await renderPage.setContent(buildWatermarkifyRenderHtml({
5068
+ imageSrc: `data:${imageInfo.mimeType || "image/png"};base64,${buffer.toString("base64")}`,
5069
+ overlaySvg,
5070
+ width: safeWidth,
5071
+ height: safeHeight
5072
+ }), {
5073
+ waitUntil: "load"
5074
+ });
5075
+ await renderPage.waitForFunction(() => {
5076
+ const image = document.getElementById("pk-base-image");
5077
+ return image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0 && image.naturalHeight > 0;
5078
+ }, {
5079
+ timeout: 5e3
5080
+ }).catch(() => {
5081
+ });
5082
+ await renderPage.evaluate(async () => {
5083
+ if (document.fonts?.ready) {
5084
+ await document.fonts.ready.catch(() => {
5085
+ });
5086
+ }
5087
+ }).catch(() => {
5088
+ });
5089
+ const composed = await renderPage.screenshot({
5090
+ type: "png",
5091
+ fullPage: true,
5092
+ animations: "disabled"
5093
+ }).catch((error) => {
5094
+ logger11.warning(`watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`);
5095
+ return null;
5096
+ });
5097
+ if (Buffer.isBuffer(composed) && composed.length > 0) {
5098
+ return composed;
5099
+ }
5100
+ logger11.warning("watermarkify \u6D4F\u89C8\u5668\u5408\u6210\u5931\u8D25: \u672A\u5F97\u5230\u6709\u6548\u622A\u56FE\u7ED3\u679C");
5101
+ return buffer;
5102
+ } finally {
5103
+ await renderScope.close().catch(() => {
5104
+ });
5105
+ }
5106
+ };
4915
5107
  var resolveWithIpLookup = async (page, options = {}) => {
4916
5108
  if (!page || typeof page.context !== "function" || options.ipLookup === false) {
4917
5109
  return null;
@@ -5057,6 +5249,7 @@ var buildStripSegments = ({ prompt, captureTime, ip, location }) => {
5057
5249
  ];
5058
5250
  };
5059
5251
  var escapeXml = (value) => String(value || "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5252
+ var escapeHtmlAttribute = (value) => String(value || "").replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5060
5253
  var estimateTextWidth = (value, fontSize = 16) => {
5061
5254
  const text = String(value || "");
5062
5255
  let width = 0;
@@ -5668,24 +5861,22 @@ var buildWatermarkifySvg = (meta, imageWidth, imageHeight) => {
5668
5861
  </svg>
5669
5862
  `;
5670
5863
  };
5671
- var watermarkifyScreenshotBuffer = async (buffer, meta) => {
5864
+ var watermarkifyScreenshotBuffer = async (buffer, meta, page = null) => {
5672
5865
  const hasWatermark = meta?.watermark?.enabled !== false && normalizeText(meta?.watermarkText);
5673
5866
  const hasStrip = meta?.strip?.enabled !== false && Array.isArray(meta?.stripSegments) && meta.stripSegments.length > 0;
5674
5867
  if (!Buffer.isBuffer(buffer) || !meta || !hasWatermark && !hasStrip) {
5675
5868
  return buffer;
5676
5869
  }
5677
- const image = sharp(buffer, { failOn: "none" });
5678
- const metadata = await image.metadata().catch(() => null);
5679
- const width = Math.max(1, Number(metadata?.width) || 0);
5680
- const height = Math.max(1, Number(metadata?.height) || 0);
5681
- if (!width || !height) {
5870
+ const imageInfo = readImageInfo(buffer);
5871
+ if (!imageInfo.width || !imageInfo.height || !imageInfo.mimeType) {
5872
+ logger11.warning("watermarkify \u8DF3\u8FC7: \u65E0\u6CD5\u89E3\u6790\u622A\u56FE\u5C3A\u5BF8\u6216\u683C\u5F0F");
5682
5873
  return buffer;
5683
5874
  }
5684
- const overlaySvg = buildWatermarkifySvg(meta, width, height);
5875
+ const overlaySvg = buildWatermarkifySvg(meta, imageInfo.width, imageInfo.height);
5685
5876
  if (!overlaySvg) {
5686
5877
  return buffer;
5687
5878
  }
5688
- return await image.composite([{ input: Buffer.from(overlaySvg), top: 0, left: 0 }]).png().toBuffer();
5879
+ return await composeScreenshotBufferWithBrowser(page, buffer, overlaySvg, imageInfo);
5689
5880
  };
5690
5881
 
5691
5882
  // src/share.js
@@ -6149,7 +6340,7 @@ var Share = {
6149
6340
  ...screenshotWatermarkify,
6150
6341
  capturedAt
6151
6342
  });
6152
- const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta);
6343
+ const buffer_ = await watermarkifyScreenshotBuffer(rawBuffer, watermarkifyMeta, page);
6153
6344
  return buffer_.toString("base64");
6154
6345
  } finally {
6155
6346
  if (restore) {