Reject wallpaper captures for stickers
This commit is contained in:
+84
-2
@@ -1378,6 +1378,88 @@ async function downloadDomStickerThroughScreenshot(p, request) {
|
|||||||
buffer: dataUrl.startsWith(prefix) ? Buffer.from(dataUrl.slice(prefix.length), "base64") : null
|
buffer: dataUrl.startsWith(prefix) ? Buffer.from(dataUrl.slice(prefix.length), "base64") : null
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
const inspectStickerPng = async (buffer) => {
|
||||||
|
const base64 = buffer.toString("base64");
|
||||||
|
return await p.evaluate(async (dataUrl) => {
|
||||||
|
const image = new Image();
|
||||||
|
image.src = dataUrl;
|
||||||
|
await image.decode();
|
||||||
|
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.width = image.naturalWidth;
|
||||||
|
canvas.height = image.naturalHeight;
|
||||||
|
const context = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
|
if (!context || canvas.width <= 0 || canvas.height <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.drawImage(image, 0, 0);
|
||||||
|
const data = context.getImageData(0, 0, canvas.width, canvas.height).data;
|
||||||
|
const totalPixels = canvas.width * canvas.height;
|
||||||
|
const step = Math.max(1, Math.floor(totalPixels / 20000));
|
||||||
|
let sampled = 0;
|
||||||
|
let opaque = 0;
|
||||||
|
let dark = 0;
|
||||||
|
let white = 0;
|
||||||
|
let cyan = 0;
|
||||||
|
let sumR = 0;
|
||||||
|
let sumG = 0;
|
||||||
|
let sumB = 0;
|
||||||
|
|
||||||
|
for (let pixel = 0; pixel < totalPixels; pixel += step) {
|
||||||
|
const offset = pixel * 4;
|
||||||
|
const r = data[offset];
|
||||||
|
const g = data[offset + 1];
|
||||||
|
const b = data[offset + 2];
|
||||||
|
const a = data[offset + 3];
|
||||||
|
sampled++;
|
||||||
|
if (a <= 8) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
opaque++;
|
||||||
|
sumR += r;
|
||||||
|
sumG += g;
|
||||||
|
sumB += b;
|
||||||
|
if (Math.max(r, g, b) < 95) dark++;
|
||||||
|
if (Math.min(r, g, b) > 230) white++;
|
||||||
|
if (b > r + 25 && g > r + 20 && b > 150 && g > 130) cyan++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
width: canvas.width,
|
||||||
|
height: canvas.height,
|
||||||
|
sampled,
|
||||||
|
opaqueRatio: sampled ? opaque / sampled : 0,
|
||||||
|
darkRatio: opaque ? dark / opaque : 0,
|
||||||
|
whiteRatio: opaque ? white / opaque : 0,
|
||||||
|
cyanRatio: opaque ? cyan / opaque : 0,
|
||||||
|
avgR: opaque ? sumR / opaque : 0,
|
||||||
|
avgG: opaque ? sumG / opaque : 0,
|
||||||
|
avgB: opaque ? sumB / opaque : 0
|
||||||
|
};
|
||||||
|
}, `data:image/png;base64,${base64}`).catch(() => null);
|
||||||
|
};
|
||||||
|
const isMaxWallpaperCapture = (metrics) => {
|
||||||
|
if (!metrics) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return metrics.opaqueRatio > 0.98 &&
|
||||||
|
metrics.cyanRatio > 0.72 &&
|
||||||
|
metrics.darkRatio < 0.03 &&
|
||||||
|
metrics.whiteRatio < 0.08 &&
|
||||||
|
metrics.avgB > metrics.avgR + 45 &&
|
||||||
|
metrics.avgG > metrics.avgR + 30;
|
||||||
|
};
|
||||||
|
const stickerCaptureResult = async (buffer) => {
|
||||||
|
const metrics = await inspectStickerPng(buffer);
|
||||||
|
if (isMaxWallpaperCapture(metrics)) {
|
||||||
|
throw new Error(`${kindLabel} capture matched MAX chat wallpaper instead of sticker.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { contentType: "image/png", buffer };
|
||||||
|
};
|
||||||
const screenshotCandidate = async (handles, requestedIndex) => {
|
const screenshotCandidate = async (handles, requestedIndex) => {
|
||||||
const candidates = [];
|
const candidates = [];
|
||||||
for (const handle of handles) {
|
for (const handle of handles) {
|
||||||
@@ -1522,7 +1604,7 @@ async function downloadDomStickerThroughScreenshot(p, request) {
|
|||||||
await target.handle.scrollIntoViewIfNeeded({ timeout: 3000 }).catch(() => {});
|
await target.handle.scrollIntoViewIfNeeded({ timeout: 3000 }).catch(() => {});
|
||||||
const canvasCapture = await captureCanvasPng(target.handle);
|
const canvasCapture = await captureCanvasPng(target.handle);
|
||||||
if (canvasCapture.buffer) {
|
if (canvasCapture.buffer) {
|
||||||
return { contentType: "image/png", buffer: canvasCapture.buffer };
|
return await stickerCaptureResult(canvasCapture.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer;
|
let buffer;
|
||||||
@@ -1548,7 +1630,7 @@ async function downloadDomStickerThroughScreenshot(p, request) {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { contentType: "image/png", buffer };
|
return await stickerCaptureResult(buffer);
|
||||||
} finally {
|
} finally {
|
||||||
for (const item of candidates) {
|
for (const item of candidates) {
|
||||||
await item.handle.dispose().catch(() => {});
|
await item.handle.dispose().catch(() => {});
|
||||||
|
|||||||
Reference in New Issue
Block a user